今天看vue的API,看到组件通信这一块,发现通信方式有好多种,但官网上的说明都是一笔带过,而且语句有点拗口,里面又有很多不理解的专有名词,以致于以前看的时候漏掉了很多东西,今天就好好总结一下。
1. props传值
props方式是用得比较多的:
<div id="app">
<child :value="msg" :fun="printMsg"></child>
</div>
Vue.component('child', {
props: ['value', 'fun'],
mounted() {
this.fun(' 我是在child组件中加入的参数')
},
template: `
<div>{{value}}</div>
`
})
new Vue({
el: '#app',
data: {
msg: '我是app内的msg'
},
methods: {
printMsg(str = '') {
console.log('msg:', this.msg + str) // msg: 我是app内的msg 我是在child组件中加入的参数
}
}
})
上例中根组件向子组件传了两个值,分别是一个字符串和一个方法,在子组件中,传入的值会放到vm实例中,可用this来访问。
传入的方法(不是用箭头函数定义的)在调用时,方法内部的this仍然指向根的Vue实例,并且能获取子组件传递的参数,这样就能方便的在子组件中调用父组件的方法。
特点:
- 在子组件调用时给子组件写入的属性,在子组件内用props注册后会添加到子组件的vm实例上;
- 在子组件中不能直接修改props传入的值;
- 只能是父组件传子组件,不能‘隔代’;
2. $attrs
$attrs是2.4版本添加的内容,目的是解决props在‘隔代’传值时反复注册props属性的问题。
若现在有三个组件grand, parent 和 child,parent是grand的子组件,child是parent的子组件,现在需要grand组件传值到child组件,如果用props来注册的话,不管parent组件需不需要用到这个值,都必须在parent中用props注册,再传给child。
$attrs是一个对象,它的值是组件在调用时写入的属性(不包括style, class以及在子组件中注册的props)。使用$attrs就可以避免过多的注册props:
<div id="app">
<parent :value="msg"></parent>
</div>
Vue.component('parent', {
data() {
return {
msg: ''
}
},
mounted() {
console.log('parent', this.$attrs)
},
template: `
<div>
<child :value="$attrs.value"></child>
</div>
`
})
Vue.component('child', {
props: ['value'],
mounted() {
console.log('child', this.value)
},
template:`<div></div>`
})
new Vue({
el: '#app',
data: {
msg: '我是app内的msg'
},
})
上例中parent组件没有注册props,通过$attrs将值传给了child
3. $root
在任何一个组件中,$root都指向根组件实例,即_uid 为0的vue实例,通过vm.$root可以访问到根上的属性和方法
<div id="app">
<child></child>
</div>
Vue.component('child', {
mounted() {
this.$root.fun('子组件的参数')
},
template:`<div></div>`
})
new Vue({
el: '#app',
data: {
msg: '我是app内的msg'
},
methods: {
fun (str) {
console.log(this.msg + str) // 我是app内的msg 子组件的参数
}
}
})
4. $parent和$children
$parent指向父组件实例,在根实例中的值为undefined
$children是一个数组,包含了该组件下的所有子组件
<div id="app">
<child></child>
</div>
Vue.component('child', {
mounted() {
this.$parent.fun('子组件的参数')
},
template:`<div></div>`
})
new Vue({
el: '#app',
data: {
msg: '我是app内的msg'
},
methods: {
fun (str) {
console.log(this.msg + str) // 我是app内的msg 子组件的参数
}
}
})
5. $refs
这个也比较常用,直接上码:
<body>
<div id="app">
<child ref="child"></child>
<div ref="myDiv"></div>
</div>
</body>
<script>
Vue.component('child', {
data () {
return {
msg: '我是子组件的msg'
}
},
methods: {
fun(str) {
console.log(this.msg + str)
}
},
template: `<div></div>`
})
new Vue({
el: '#app',
mounted () {
this.$refs['child'].fun(' 我是父组件的参数') // 我是子组件的msg 我是父组件的参数
console.log('myDiv',this.$refs['myDiv']) // 这是一个DOM对象
}
})
</script>
6. $emit
子传父常用的方法,上码:
<body>
<div id="app">
<child @getmsg="fun"></child>
</div>
</body>
<script>
Vue.component('child', {
data () {
return {
msg: '我是子组件的msg'
}
},
mounted() {
this.$emit('getmsg', this.msg)
},
template: `<div></div>`
})
new Vue({
el: '#app',
methods: {
fun (msg) {
console.log(msg) // 我是子组件的msg
}
},
})
</script>
7. 依赖注入
使用 $parent 属性无法很好的扩展到更深层级的嵌套组件上。这也是依赖注入的用武之地,它用到了两个新的实例选项:provide 和 inject。
provide 选项允许我们指定我们想要提供给后代组件的数据/方法。
然后在任何后代组件里,我们都可以使用 inject 选项来接收指定的我们想要添加在这个实例上的属性:
<body>
<div id="app">
<child></child>
</div>
</body>
<script>
Vue.component('child', {
inject: ['value'],
mounted() {
console.log(this.value) // 我是根组件的msg
},
template: `<div></div>`
})
new Vue({
el: '#app',
data: {
msg: '我是根组件的msg'
},
provide() {
return {
value: this.msg
}
}
})
</script>