自制vue组件开发
vue组件的分类
vue 组件大致分为三类,vue-router产生的每个页面,基础组件,业务组件。
-
vue-router组件,也就是平时用cli开发,使用的vue文件,每个文件,和页面都是一个vue组件,处理一些常规文件,主要作用是用来渲染页面使用的,一般不会复用。
-
基础组件,不包含业务,独立的,具有特定功能的组件,例如选择器,输入框,状态栏,按钮,像element-ui这些ui框架都是基础组件,这些组件往往是项目中复用率最高的组件,但这类组件的开发侧重在api的设计,兼容性,性能,考入的事项比其他组件都要的多。
-
业务组件,不单单是一个简单功能的组件,他在业务中被多个页面服用,而他和基础组件区别在于他只在当前项目中广泛应用,业务组件里也会包含一些数据请求,这类组件的开发只要考虑到当前项目的兼容就好。
组件构成
- 属性prop
prop 定义组件有哪些可配置的属性,也可以理解成,从父组件中继承下来的属性,prop是由父组件定义传值,再由子组件去继承,在子组件,props最好使用对象的写法去表明子组件可配置的属性,使用对象的写法,可以在props中也能申明默认属性,在父组件没有配置时,默认属性,也能够自定义校验属性的值是不是你所期望得到的值。 但是props都是单向数据流,只能通过父组件去配置,不能有子组件去修改配置,如果想要修改,只能将prop属性赋值给data里的数据,再修改data里的数据,但是这样更改,父组件还是原始的值。如果想要让子组件的属性通信父组件,则可以使用$emit来通信,或者使用vuex或者Bus来通信。但是这不试用与基础组件的开发。 在组件中,也能通过html的特性传入,例如id,class,这些特性都会被组件的根元素所继承,如果不期望继承,则可以在组件选项配置
inheritAttrs: false
就可以禁用组件继承特性了。
- 插槽slot
slot插槽可以分发组件的内容,他能扩展组件内部的内容
例如,在定义一个按钮组件的时候,就可以在组件占位标签
<template>
<button :disabled="disabled">
<slot></slot>
</button>
</template>
在父类调用的时候就可以
<my-button>这是一个按钮</my-button>
他会将<my-button>
标签内的 ‘这是一个按钮’ 传入给子组件,在<slot></slot>
位置上插入该文本,当然不止能传入单单一个字符串,也能是其他的html内容。
<my-button>
<strong>这是一个带标签的按钮</strong>
</my-button>
插槽也能够默认内容,例如
<template>
<button :disabled="disabled">
<slot>默认按钮</slot>
</button>
</template>
<my-button></my-button>
在父组件<my-button></my-button>
不填写内容的时候,默认会显示’默认按钮’
当需要试用多个插槽的时候,就会用到具名插槽,给子组件的slot
设置name
属性,在父组件调用的时候,给插入内容设置slot
属性,让父子组件能够对应上。
<template>
<button :disabled="disabled">
<slot name="icon"></slot>
<slot></slot>
</button>
</template>
<my-button>
<i slot="icon"></i>
按钮 1
</my-button>
- 自定义事件 $emit
像子组件向父组件传值的时候,可以通过
$emit
,触发自定义事件,然后父组件通过监听出发的事件,获取到子组件传入父组件的数据
<template>
<button @click="handleClick">
<slot></slot>
</button>
</template>
<script>
export default {
methods: {
handleClick (event) {
//当点击按钮的时候 出发on-click事件,并且将dom对象当作数据传值给父组件
this.$emit('on-click', event);
}
}
}
</script>
// 父组件监听 on-click事件 触发handleClick 事件
<my-button @on-click="handleClick"></my-button>
组件之间的通信
组件之间的通信,有很多的方法,可以通过ref 给元素注册引用信息,$parent
/ $children
:访问父 / 子实例。
这两种方法 可以调用组件信息,能够直接获取到方法或者访问数据, 用ref 来访问数据
export default {
data () {
return {
title: 'Vue.js'
}
},
methods: {
sayHello () {
window.alert('Hello');
}
}
}
<template>
//注册 组件信息名字为comA
<component-a ref="comA"></component-a>
</template>
<script>
export default {
mounted () {
//调用vue下的refs 获取到注册组件的comA
const comA = this.$refs.comA;
console.log(comA.title); // Vue.js
comA.sayHello(); // 弹窗
}
}
</script>
$parent
/ $children
:访问父 / 子实例 和 ref
类似,都是通过vue实力属性来调用,但是缺点就是,无法跨级或者兄弟间通信,如果想实现跨级或者兄弟组件之间的通信,一般想到的都是试用vuex 或者Bus来解决,但是这不利于组件的开发。
provide / inject
provide / inject 组件通信,这个是vue2.2.0新增的API,在文档中,这样介绍
这对选项需要一起使用,以允许一个祖先组件向其所有子孙后代注入一个依赖,不论组件层次有多深,并在起上下游关系成立的时间里始终生效。如果你熟悉 React,这与 React 的上下文特性很相似。
我个人认为的provide / inject 可以模拟vuex的效果, 对于。
- 简单了解provide / inject
B组件是A组件的子组件 A->B
// A.vue
export default {
provide: {
name: 'Aresn'
}
}
// B.vue
export default {
inject: ['name'],
mounted () {
console.log(this.name); // Aresn
}
}
先是在A组件中设置provide:name,值为 ‘Aresn’ ,他的作用是将name这个变量提供给他的所有子组件,在B组件中,通过inject
来注入从A组件获取到的name变量,那么在组件B中,就可以直接this.name来获取到这个变量了,需要注意的是这样的通信的变量是不可响应的,如果A组件的name改变了,那么B组件还是之前的’Aresn’
- 替代Vuex
之前了解到provide / inject类似于广播的效果,在父组件设置provide
然后该组件的所有子组件都能接受到这个广播,但是要在子组件中设置inject
来接受这个广播。
那么vue是一个单页面应用,开发过程中,都是在app.vue作为根组件来进行开发的,如果我们在app.vue中设置总台发射站,设置provide
,在其他需要的组件中设置inject
。这是不是和vuex很像呢,在app.vue作为状态管理,那么我们provide
只需要吧app.vue组件中的所有数据,方法都广播出去,这样就能实现一个类似Vuex的效果。
app.vue 是整个项目第一个被渲染的组件,而且只会渲染一次(即使切换路由,app.vue 也不会被再次渲染),利用这个特性,很适合做一次性全局的状态数据管理,例如,我们将用户的登录信息保存起来:
app.vue
<template>
<div>
<router-view></router-view>
</div>
</template>
<script>
export default {
provide () {
return {
app: this
}
},
data () {
return {
userInfo: null
}
},
methods: {
getUserInfo () {
// 这里通过 ajax 获取用户信息后,赋值给 this.userInfo,以下为伪代码
$.ajax('/user/info', (data) => {
this.userInfo = data;
});
}
},
mounted () {
this.getUserInfo();
}
}
</script>
template>
<div>
</div>
</template>
<script>
export default {
inject: ['app'],
methods: {
changeUserInfo () {
// 这里修改完用户数据后,通知 app.vue 更新,以下为伪代码
$.ajax('/user/update', () => {
// 直接通过 this.app 就可以调用 app.vue 里的方法如果app中的userInfo更新了就可以通过调用app组件中的方法获取新的数据
this.app.getUserInfo();
})
}
}
}
</script>
现在就能通过provide / inject解决了跨级组件的通信问题了解以上几点 就能简单的开发一个自定义的组件了