props/$emit
最为基础的使用方式,vue官网基础组件中的示例
<body>
<div id="blog-posts-events-demo">
<div :style="{ fontSize: postFontSize + 'em' }">
<blog-post v-on:enlarge-text="postFontSize += 0.1" v-for="post in posts" v-bind:key="post.id" v-bind:post="post">
</blog-post>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
Vue.component('blog-post', {
props: ['post'],
template: `
<div class="blog-post">
<h3>{{ post.title }}</h3>
<button v-on:click="$emit('enlarge-text')">
Enlarge text
</button>
<div v-html="post.content"></div>
</div>
`
})
new Vue({
el: '#blog-posts-events-demo',
data: {
posts: [{ title: 'lisan' }, { title: 'wuzhao' }, { title: 'selirea' }],
postFontSize: 1
}
})
</script>
</body>
通过Vue.component
全局注册了一个组件blog-post
,在根组件上也就是blog-post
的父组件上通过v-bind
向blog-post
传递了数据,子组件blog-post
通过props
收到数据进行渲染,并且可以通过$emit
发出事件携带数据。
$emit/$on
这种方法通过一个空的Vue实例作为中央事件总线(事件中心),用它来触发事件和监听事件,巧妙而轻量地实现了任何组件间的通信,包括父子、兄弟、跨级。
$attrs/$listeners
多级组件嵌套需要传递数据时,通常使用的方法是通过vuex。但如果仅仅是传递数据,而不做中间处理,使用 vuex 处理,未免有点大材小用。为此Vue2.4 版本提供了另一种方法–$attrs/$listeners
$attrs:包含了父作用域中不被 prop 所识别 (且获取) 的特性绑定 (class 和 style 除外)。当一个组件没有声明任何 prop 时,这里会包含所有父作用域的绑定 (class 和 style 除外),并且可以通过 v-bind="$attrs"
传入内部组件。
下边例子中并没有使用props接收数据,则使用this.$attrs可以把父组件绑定的值传进来,
<body>
<div id="blog-posts-events-demo">
<div>
<blog-post v-for="post in posts" v-bind:attr="attr" v-bind:key="post.id" v-bind:post="post">
</blog-post>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
Vue.component('blog-post', {
props: ['post'],
inheritAttrs: false, // 可以关闭自动挂载到组件根元素上的没有在props声明的属性
template: `
<div class="blog-post">
<h3>{{ post.title }}</h3>
<button @click ="getAttrValue">getAttrValue</button>
<div></div>
</div>
`,
methods: {
getAttrValue() {
console.log(this)
}
},
})
// 定义一个名为 button-counter 的新组件
new Vue({
el: '#blog-posts-events-demo',
data: {
posts: [{ title: 'lisan' }, { title: 'wuzhao' }, { title: 'selirea' }],
attr: 'hello im child component whitout prop',
postFontSize: 1
}
})
</script>
</body>
如果props接收了某几个父组件绑定的值,则this.$attrs不包含这几个值。
通常配合 inheritAttrs
选项一起使用,可以关闭自动挂载到组件根元素上的没有在props声明的属性
简单来说:$attrs
与$listeners
是两个对象,$attrs
里存放的是父组件中绑定的非 Props 属性,$listeners
里存放的是父组件中绑定的非原生事件,比如子组件通过$emit发射上来的。
provide/inject
https://cn.vuejs.org/v2/api/#provide-inject
父组件通过provide
提供数据,子组件声明inject会被注入
<body>
<div id="blog-posts-events-demo">
<div>
<blog-post v-for="post in posts" v-bind:attr="attr" v-bind:key="post.id" v-bind:post="post">
</blog-post>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
Vue.component('blog-post', {
props: ['post'],
inject: ['foo'],
template: `
<div class="blog-post">
<button @click ="getAttrValue" >getAttrValue</button>
</div>
`,
created() {
console.log(this.foo) // => "bar"
},
methods: {
getAttrValue() {
console.log(this.foo)
}
},
})
// 定义一个名为 button-counter 的新组件
new Vue({
el: '#blog-posts-events-demo',
provide: {
foo: 'bar'
},
data: {
posts: [{ title: 'lisan' }, { title: 'wuzhao' }, { title: 'selirea' }],
attr: 'hello im child component whitout prop',
postFontSize: 1
}
})
</script>
</body>
$parent/$children
<body>
<div id="blog-posts-events-demo">
<div>
<blog-post v-for="post in posts" v-bind:attr="attr" v-bind:key="post.id" v-bind:post="post">
</blog-post>
</div>
<button @click="getChildConponent">getChildConponent</button>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
Vue.component('blog-post', {
props: ['post'],
inject: ['foo'],
template: `
<div class="blog-post">
<button @click ="getParentConponent" >getParentConponent</button>
</div>
`,
created() {
console.log(this.$parent, '----子组件拿到了父组件----')
},
methods: {
getParentConponent() {
console.log(this.$parent)
}
},
})
new Vue({
el: '#blog-posts-events-demo',
provide: {
foo: 'bar'
},
data: {
posts: [{ title: 'lisan' }, { title: 'wuzhao' }, { title: 'selirea' }],
attr: 'hello im child component whitout prop',
postFontSize: 1
},
methods: {
getChildConponent() {
console.log(this.$children, '---父组件拿到了直接子组件---')
}
}
})
</script>
</body>
直接拿到父组件的实例,可以做想做的一切
vuex
当然还有依赖全局变量、本地缓存等这类傻逼不太推荐的用法
总结
无疑的,vuex是最强大的跨组件通信解决方案;
$emit/$on是类似全局变量的方案,不推荐;
$attr/$listeners若乱用只会让代码更乱;
$provide/inject用在业务代码官方不太推荐;
$parent/$children有点取巧了;
常用的就是props/$emit的组合,和vuex