上一篇内容我们了解了vue组件中关于prop选项的内容,props选项实现了父组件向子组件的数据传递,这篇我们将了解一下子组件与父组件进行通信。
$emit()方法
子组件使用 $emit()方法触发父组件事件。在父组件中通过v-on指令监听子组件的自定义事件,然后自定义事件执行 $emit()方法触发父组件事件,这样就可以实现子组件和父组件之间的通信
<div id="app">
<post-item :value="arr" @greet="fatherClick"></post-item>
</div>
<script>
Vue.component('PostItem', {
props: [
'value'
],
methods: {
click() {
this.$emit('greet', '这是通过$emit方法触发')
}
},
template: '<h3> <button type="button" v-on:click="click">点击一下</button></br> {{ value }}</h3>'
})
let vm = new Vue({
el: "#app",
data: {
arr: ""
},
methods: {
fatherClick(value) {
this.arr = value;
}
}
})
</script>
通过$emit方法的第一个参数是事件名,第二个参数是参数
。
在上述案例中,在我们先监听子组件的单击事件,当触发单击事件后执行子组件的click方法,然后click方法触发父组件中的fatherClick方法,并将参数传递过去。
.sync修饰符
在vue中,一个组件通过prop属性传递数据是单向的,父组件可以将数据传递到子组件。但是在特殊情况下,需要对一个组件的prop进行双向绑定,vue提供了一个update:myPropName模式触发事件来实现双向绑定。看下列案例:
<div id="app">
<span>计数器的值:{{ counter }}</span>
<parent :val="counter" v-on:update:count="counter = $event"></parent>
</div>
<script>
Vue.component('parent', {
props: {
count: {
type: Number,
define: 0
}
},
template: `
<div>
<span>计数:{{ count }}</span>
<button @click="Click">添加计数</button>
</div>
`,
methods: {
Click() {
this.$emit('update:count', ++this.count);
}
},
})
let vm = new Vue({
el: "#app",
data: {
counter: 0
}
})
</script>
在这个组件中有一个名为 count的prop,点击按钮的单击事件,调动
$emi(()
方法触发
update:val
事件, 并将加 1 之后的计数值作为事件的附加参数。
在父组件中,使用 v-on指令监听
update:val
事件,这样就可以接收子组件传递过来的数据,然后使用 v-bind 指令绑定子组件中名为 count 的 prop,就可以实现给子组件传递父组件的数据,这样就实现了数据的双向绑定。
其中
$event
是自定义的事件的附加参数,而
update:val
事件是一个自定义事件,所以其参数就是加 1 之后的计数值。
在上面我们实现的数据双向绑定比较复杂,vue 提供了
.sync
修饰符简化了数据的双向绑定,如下所示修改:
<parent :count.sync="counter"></parent>
需要注意的是,在这种简化方式,一定要确保 prop 中的参数和 需要出发的事件同名,且事件名必须是
update:
开头,如下所示:
<parent :count.sync="counter"></parent>
this.$emit('update:count', ++this.count);
props: {
count: {
type: Number,
define: 0
}
},
//如果进行修改,则同时改变
<parent :ss.sync="counter"></parent>
this.$emit('update:ss', ++this.ss);
props: {
ss: {
type: Number,
define: 0
}
},
.native修饰符
.native
修饰符主要是将原生事件绑定到组件。
<div id="app">
<div :style="'font-size:'+fontsize+'em'">
<parent v-for="book of books" :book="book" @click.native="fangda"></parent>
</div>
</div>
Vue.component('parent', {
props: ['book'],
template: `
<div>
<p>{{ book.title }}</p>
<button>放大字体</button>
<p>{{ book.content }}</p>
</div>
`,
})
let vm = new Vue({
el: "#app",
data: {
fontsize: 1,
books: [{
title: "朝花夕拾",
content: "鲁迅的文章",
id: 1
}, {
title: "时间简史",
content: "反正我不喜欢看,但是她很出名",
id: 2
}]
},
methods: {
fangda() {
this.fontsize++;
}
}
})
在上述案例中,我们将点击事件通过
.native
修饰符添加到了组件根元素上,导致点击任何文字都会将字体放大。
但我们需要的效果是点击按钮放大文字,所以我们需要通过
$listeners
属性将
组件所有的事件监听器全部转发到特定的子元素
。
Vue.component('parent', {
props: ['book'],
template: `
<div>
<p>{{ book.title }}</p>
<button v-on="$listeners">放大字体</button>
<p>{{ book.content }}</p>
</div>
`,
})
上述案例就是当单击按钮之后才能修改文本大小。需要注意的是
$listeners
属性虽然会将所有的事件监听转发到特定的子元素,但是
不包括通过.native修饰的事件
。