Vue.js 组件 - 自定义事件
父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!
我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即:
使用
$on(eventName)
监听事件
使用
$emit(eventName)
触发事件
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。
<
div
id
=
"
app
"
>
<
div
id
=
"
counter-event-example
"
>
<
p
>
{{ total }}
</
p
>
<
button-counter
v-on:increment
=
"
incrementTotal
"
>
</
button-counter
>
<
button-counter
v-on:increment
=
"
incrementTotal
"
>
</
button-counter
>
</
div
>
</
div
>
<
script
>
Vue.component('button-counter', {
template: '
<
button
v-on:click
=
"
incrementHandler
"
>
{{ counter }}
</
button
>
',
data: function () {
return {
counter: 0
methods: {
incrementHandler: function () {
this.counter += 1
this.$emit('increment')
new Vue({
el: '#counter-event-example',
data: {
total: 0
methods: {
incrementTotal: function () {
this.total += 1
</
script
>
尝试一下 »
如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如:
<my-component v-on:click.native="doTheThing"></my-component>
data 必须是一个函数
上面例子中,可以看到 button-counter 组件中的 data 不是一个对象,而是一个函数:
data: function () {
return {
count: 0
这样的好处就是每个实例可以维护一份被返回对象的独立的拷贝,如果 data 是一个对象则会影响到其他实例,如下所示:
<div id="components-demo3" class="demo">
<button-counter2></button-counter2>
<button-counter2></button-counter2>
<button-counter2></button-counter2>
</div>
<script>
var buttonCounter2Data = {
count: 0
Vue.component('button-counter2', {
data: function () {
// data 选项是一个函数,组件不相互影响
return {
count: 0
data: function () {
// data 选项是一个对象,会影响到其他实例
return buttonCounter2Data
template: '<button v-on:click="count++">点击了 {{ count }} 次。</button>'
new Vue({ el: '#components-demo3' })
</script>
尝试一下 »
自定义组件的 v-model
组件上的 v-model 默认会利用名为 value 的 prop 和名为 input 的事件。
<input v-model="parentData">
<input
:value="parentData"
@input="parentData = $event.target.value"
以下实例自定义组件 runoob-input,父组件的 num 的初始值是 100,更改子组件的值能实时更新父组件的 num:
<div id="app">
<runoob-input v-model="num"></runoob-input>
<p>输入的数字为:{{num}}</p>
</div>
<script>
Vue.component('runoob-input', {
template: `
<p>
<input
ref="input"
:value="value"
@input="$emit('input', $event.target.value)"
props: ['value'], // 名为 value 的 prop
new Vue({
el: '#app',
data: {
num: 100,
</script>
尝试一下 »
由于 v-model 默认传的是 value,不是 checked,所以对于复选框或者单选框的组件时,我们需要使用 model 选项,model 选项可以指定当前的事件类型和传入的 props。
<div id="app">
<base-checkbox v-model="lovingVue"></base-checkbox>
<div v-show="lovingVue">
如果选择框打勾我就会显示。
</div>
</div>
<script>
// 注册
Vue.component('base-checkbox', {
model: {
prop: 'checked',
event: 'change' // onchange 事件
props: {
checked: Boolean
template: `
<input
type="checkbox"
v-bind:checked="checked"
v-on:change="$emit('change', $event.target.checked)"
// 创建根实例
new Vue({
el: '#app',
data: {
lovingVue: true
</script>
尝试一下 »
实例中 lovingVue 的值会传给 checked 的 prop,同时当 <base-checkbox> 触发 change 事件时, lovingVue 的值也会更新。
return buttonCounter2Data
template: '<button v-on:click="count++">点击了 {{ count }} 次。</button>'
注释起来的 data 代码和未注释起来的 data 都是函数,只是注释起来的函数返回值是每执行一次函数就产生一个独立的对象,而未注释的 data 函数返回值却是引用了一个已有对象的名称(即对象的引用),不管函数执行多少次返回值都是这个外部定义的对象的引用而已,也就是说不管有多少个组件,所有的组件维护的数据都是同一个对象的数据而已,所以一个组件的数据发生变化同样会影响到其他所有的组件的数据。。。