Vue 组件通讯与插槽事件分发
js
// 全局组件 [注意] 必须在new Vue之前
Vue.component('组件名',{
template:`html模板`,
// data必须为函数
data() {
return {}
},
// 局部组件
components : {
组件名:{}
}
});
// 根组件
new Vue({el:'#app'});
父传子
- 接收的变量与父组件的变量名一致
- 对象写法验证支持的类型,Number,String,Boolean,Array,Object,Function,null(不限制数据类型)
js
props:[接收的变量]
props:{
接收的变量:限制接收的数据类型,
接收的变量:{
type : [Number, String], // 单个或多个
default : '默认值',
required : true, // 必填项
}
// 自定义校验器
接收的变量: {
validator(val){
return xxx
}
}
}
js
<nav1 :val='a'></nav1>
Vue.component('nav1',{
template:`<h1>{{val}}</h1>`,
props:['val'] //
})
let vm = new Vue({
el:'#app',
data : {
a : 1
},
})
子传父
- <子组件 @自定义事件='父组件事件'></子组件>
- 子组件 this.$emit('自定义事件',传参,[可选多个参数])
vue
<div id="box">
<!-- nn被子组件调用,ff为父组件方法 -->
<qj @nn='ff' :val='a'></qj>
</div>
<script>
Vue.component('qj',{
template : `<button @click=ff>click</button>`,
data() {
return { child : '子组件值' }
},
methods: {
ff(){ // 调用自定义事件
this.$emit('nn',this.child)
}
},
})
let vm = new Vue({
el:'#box',
methods: {
ff(n){
console.log(n);
}
}
})
</script>
组件通信
- let bus = new Vue(); new 一个空 vue 作为中间传递
- bus.$emit('自定义事件','发送的值') 发送数据
- bus.$on('自定义事件',回调函数) 接收数据
- [注意] 脚手架需要在 main.js 中 Vue实例之前在 Vue.prototype 属性添加 new Vue()
js
let bus = new Vue();
Vue.component('c1',{
template:`<div><button @click='fn1()'>click</button></div>`,
methods: {
fn1(){
bus.$emit('msg','值')
}
},
})
Vue.component('a2',{
template : `<div></div>`,
mounted() {
bus.$on('msg',d => { console.log(d); })
},
})
单向数据流
所有的 prop 都使得其父子 prop 之间形成了一个单向下行绑定,父级组件发生变更时,子组件中所有的 prop 都将会刷新为最新的值。这意味着你不应该在一个子组件内部改变 prop 将其作为一个本地的 prop 数据来使用
js
props: ['initialCounter'],
data: function () {
return {
counter: this.initialCounter
}
}
ref 通信
- <组件 ref='自定义组件名字'></组件>
- 父组件操控:this.$refs.自定义组件名字 拿到实例
vue
<slide ref='child'></slide>
Vue.component('slide',{
template : '<div></div>',
methods: {fn(){}}
})
let vm = new Vue({
el:'#box',
methods: {
getChild(){
console.log(this.$refs.child); // 拿到子组件的实例对象
this.$refs.child.fn()
}
}
})
组件使用 v-model
props 接收父级数据,组件使用 $emit('input',$event.target.value)发送
[原理] v-model 等价 :value=p 和 @input ;$emit 调用 @input,发送当前 value
js
<child v-model='p'></child>
Vue.component('child',{
template : `<input :value='p' @input='$emit("input",$event.target.value)'>`,
props : ['p']
})
动态组件
- 使用 component 标签,绑定 is 属性,对应的值为组件名称
- 外层添加 keep-alive 可以在切换之后避免重新渲染元素
vue
<keep-alive> <!-- keep-alive 可以避免动态组件重新渲染,每次切换不会删除之前的 -->
<!-- 改变 is 属性,is 的属性为组件的名字。每次切换组件后会重新渲染 -->
<component :is='who'></component> component会被替换为who组件的标签
</keep-alive>
slot插槽
- 插槽显示顺序以子组件的<slot>为准
- 匿名插槽对应匿名<slot>
- 具名插槽父组件属性 slot='名字' 子组件<slot name='名字'></slot> 对应
- 多个标签使用 template 标签并加上 slot='名字'属性。简写 #名字
- 作用域插槽,子组件动态绑定属性 :键='值',name='名字'对应 父组件 #名字='接收参数'。接收的参数为对象,对象中包含子组件传入的键和值
父组件
vue
<ss>
<mark>匿名插槽</mark>
<p slot="top">具名插槽</p>
<!-- 老语法 slot='' 新语法 #xxx 只能在template使用 -->
<template #bom>
<div>多个标签</div>
<p>多个标签</p>
</template>
<template #list='props'>
<div>{{props.objkey}}</div>
</template>
</ss>
子组件
html
<div>
<slot name="default"></slot>
<!-- 匿名插槽默认default -->
<slot name='top'></slot>
<slot name='bom'></slot>
<!-- 遍历数组,传出对象 {objkey:item,...} -->
<slot v-for="item of arr" :objkey='item' name="list"></slot>
</div>