目录:
组件的种类
Vue.js组件的三个API:prop、event、slot
props
props定义了这个组件有哪些可配置的属性,props最好用对象的写法,这样可以针对每个属性设置类型、默认值或自定义校验属性的值。
下面封装一个组件
<template>
<button :class="'i-button-size' + size" :disabled="disabled"></button>
</template>
<script>
export default{
props:{
size:{
default: 'default',
validator(value){
return oneOf(value,['small','large','default'])
}
},
disabled:{
type: Boolean,
default: false
}
}
}
</script>
组件里定义的props,都是单向数据流,只能通过父级修改,组件自己不能修改props的值,只能修改定义在data里的数据,非要修改需要通过自定义事件通知父级。
在使用组建时也可以传入一些标准的html特性,如id 、class
<i-button id="btn1" class="btn-submit"></i-button>
这些html特性,组件中的button元素会继承,不需要通过props属性传递。这个属性是默认支持的,如果不期望开启,在组件选项中设置 inheritAttrs : false。
slot插槽
如果要给上面的<i-button>添加文字,就要用到插槽slot,它可以分发组件的内容。
<template>
<button :class="'i-button-size' + size" :disabled="disabled">
<slot></slot>
</button>
</template>
<i-button>按钮 1</i-button>
<i-button>
<strong>按钮 2</strong>
</i-button>
当需要多个插槽时,可以设置具名插槽
<template>
<button :class="'i-button-size' + size" :disabled="disabled">
<slot name="icon"></slot>
<slot></slot>
</button>
</template>
<i-button>
<i-icon slot="icon" type="checkmark"></i-icon>
按钮 1
</i-button>
在slot中也可以设置默认内容,当父级没有任何slot时,会展示如下:
<slot>提交</slot>
Event事件
绑定事件:
<template>
<button @click="clickBtn"></button>
</template>
<script>
export default{
methods:{
clickBtn(){
this.$emit('on-click','params')
}
}
}
</script>
使用
<i-button @on-click="clickComponent"></i-button>
或者写成
<i-button @click.native="clickComponent"></i-button>
.native 修饰符,为了区别原生的click和自定义click事件。在组件内调用了on-click方法,如果不使用.native修饰符就不能调用原生click事件。
Vue.js组件的通信(基本)
Vue内置的通信手段一般有两种
Vue.js组件的通信(其他)
一、provide/inject(主要解决子组件获取上级组件的状态,主动提供与依赖注入的关系)
Vue.js 2.2.0版本后新增的API。这对选项需要一起使用,以允许一个祖先组件向其所有子孙后代注入一个依赖,不论组件层次有多深,并在上下游关系成立的时间里始终生效。
provide和inject主要为高阶插件/组件库提供用例。并不推荐直接用于应用程序代码中。
用法:
// A.vue
export default {
provide: {
name: 'Aresn' // 将name属性提供给所有子组件
}
}
// B.vue
export default {
inject: ['name'], // 注入从A组件中提供的name变量
mounted () {
console.log(this.name); // Aresn
}
}
provide、inject绑定并不是可响应的。
二、运用$emit实现dispatch和broadcast
dispatch和broadcast的功能:
// 部分代码省略
import Emitter from '../mixins/emitter.js'
export default {
mixins: [ Emitter ],
methods: {
handleDispatch () {
this.dispatch();
},
handleBroadcast () {
this.broadcast();
}
}
}
function broadcast(componentName, eventName, params) {
this.$children.forEach(child => {
const name = child.$options.name;
if (name === componentName) {
child.$emit.apply(child, [eventName].concat(params));
} else {
broadcast.apply(child, [componentName, eventName].concat([params]));
}
});
}
export default {
methods: {
dispatch(componentName, eventName, params) {
let parent = this.$parent || this.$root;
let name = parent.$options.name;
while (parent && (!name || name !== componentName)) {
parent = parent.$parent;
if (parent) {
name = parent.$options.name;
}
}
if (parent) {
parent.$emit.apply(parent, [eventName].concat(params));
}
},
broadcast(componentName, eventName, params) {
broadcast.call(this, componentName, eventName, params);
}
}
};
在 dispatch 里,通过 while 语句,不断向上遍历更新当前组件(即上下文为当前调用该方法的组件)的父组件实例(变量 parent 即为父组件实例),直到匹配到定义的 componentName
与某个上级组件的 name
选项一致时,结束循环,并在找到的组件实例上,调用 $emit
方法来触发自定义事件 eventName
。broadcast 方法与之类似,只不过是向下遍历寻找。
二、找到任意组件实例---findComponents 系列方法
findComponents 系列方法最终都是返回组件的实例,进而读取或调用该组件的数据和方法。
适用场景
5个函数的原理,都是通过递归、遍历,找到指定组件的name选项匹配的组件实例并返回。
向上找到最近的指定组件-findComponentUpward
// 由一个组件,向上找到最近的指定组件
// context 当前上下午,一般都是基于当前的组件,即传入this
// componentNam 是要找的组件的name
function findComponentUpward (context, componentName) {
let parent = context.$parent;
let name = parent.$options.name;
// 判断组件的name与传入的componentName是否一致,直到最近的一个组件为止
while (parent && (!name || [componentName].indexOf(name) < 0)) {
parent = parent.$parent;
if (parent) name = parent.$options.name;
}
// 与dispatch不同的是,findComponentUpward是直接拿到组件的实例,
// 而非通过事件通知组件
return parent;
}
export { findComponentUpward };
其他函数与此方法大同小异
参考:https://juejin.im/book/5bc844166fb9a05cd676ebca/section/5bc844166fb9a05cf52af65f