Skip to content
此页目录
本文总阅读量

Vue 组件通讯与插槽事件分发

js
// 全局组件 [注意] 必须在new Vue之前
Vue.component('组件名',{
  template:`html模板`,
  // data必须为函数
  data() {
return {}
  },
  // 局部组件
  components : {
组件名:{}
  }
});
// 根组件
new Vue({el:'#app'});

父传子

  1. 接收的变量与父组件的变量名一致
  2. 对象写法验证支持的类型,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
  },
})

子传父

  1. <子组件 @自定义事件='父组件事件'></子组件>
  2. 子组件 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>

组件通信

  1. let bus = new Vue(); new 一个空 vue 作为中间传递
  2. bus.$emit('自定义事件','发送的值') 发送数据
  3. bus.$on('自定义事件',回调函数) 接收数据
  4. [注意] 脚手架需要在 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 通信

  1. <组件 ref='自定义组件名字'></组件>
  2. 父组件操控: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']
})

动态组件

  1. 使用 component 标签,绑定 is 属性,对应的值为组件名称
  2. 外层添加 keep-alive 可以在切换之后避免重新渲染元素
vue
<keep-alive> <!-- keep-alive 可以避免动态组件重新渲染,每次切换不会删除之前的 -->
  <!-- 改变 is 属性,is 的属性为组件的名字。每次切换组件后会重新渲染 -->
  <component :is='who'></component> component会被替换为who组件的标签
</keep-alive>

slot插槽

  1. 插槽显示顺序以子组件的<slot>为准
  2. 匿名插槽对应匿名<slot>
  3. 具名插槽父组件属性 slot='名字' 子组件<slot name='名字'></slot> 对应
  4. 多个标签使用 template 标签并加上 slot='名字'属性。简写 #名字
  5. 作用域插槽,子组件动态绑定属性 :键='值',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>

评论

交流群