自定义事件
(1.)事件名
- 推荐使用 kebab-case 的事件名。
(2.)自定义组件的v-model
- model选项可以用来避免,输入控件将value attribute用于不同目的。
(3.)将原生事件绑定到组件
-
(3.1) .native修饰符
-
.native修饰符:监听组件根元素的原生事件。
-
(3.1.1)首先要明白vue中的事件与原生事件有什么不同。
-
详细内容:
-
(1.) Vue中事件与原生事件
-
在组件的根元素上直接监听一个原生事件。在vue中不能访问event,要使用$event来代替。
<base-input v-on:focus.native="onFocus"></base-input>
- 详细解释:
// 首先义一个 child 组件,什么事件都不绑定
Vue.component('child', {
template: '<button>click me</button>'
})
// 在根组件中使用它
<div id="app">
<child></child>
</div>
new Vue({
el: '#app'
})
// 点击按钮什么都没有发生
// 给child组件加@click事件
<div id="app">
<child @click="handleClick"></child>
</div>
// 这个handleClick方法是父作用域下的方法
// 在根组件中增加一个方法
new Vue({
el: '#app',
methods: {
handleClick () {
alert('hello,world!')
}
}
})
// 再次点击依旧没有任何弹出,handleClick方法没有执行。
<div id="app">
<child @click.native="handleClick"></child>
</div>
- 要使handleClick方法被执行,可以通过$emit事件派发给父组件也可以。例:
<div id='app'>
<component-three v-on:give-advice="sayHi"></component-three>
</div>
<template id="componentThree">
<button v-on:click="giveAdvice">Click me please!!</button>
</template>
<script>
var ComponentC = {
data:function(){
return {}
},
template:"#componentThree",
methods:{
giveAdvice:function(){
this.$emit('give-advice','点击我有惊喜!!')
}
}
}
new Vue({
el:'#app',
data:{},
components:{
'component-three':ComponentC,
},
methods:{
sayHi:function(advice){
console.log(advice)
}
}
})
</script>
- 详细了解:
- (1.) vue中的$emit()事件
- 子组件可以使用
$emit
,触发父组件的自定义事件。 - 注意:
@click="$emit('age-ask','this.age')"
其中$emit
传入的事件名称只能使用小写,不能使用大写的驼峰规则命名,否则无法触发事件。 - 在组件上绑定原生事件还需要自定义事件,过于麻烦。这个时候 .native 原生修饰符就派上用场了,例:
<div id='app'>
<component-three v-on:click.native="sayHi"></component-three>
</div>
<template id="componentThree">
<button>点击我有惊喜!!</button>
</template>
<script>
var ComponentC = {
data:function(){
return {}
},
template:"#componentThree"
}
new Vue({
el:'#app',
data:{},
components:{
'component-three':ComponentC,
},
methods:{
sayHi:function(){
alert('都是骗你的哦!!!')
}
}
})
</script>
-
以上的全面概括:vue给组件绑定原生事件
-
(3.2)$listeners属性
-
但是.native修饰符也不是全能的,在你尝试监听一个类似
<input>
的非常特定的元素时,组件可能做了重构,所以根元素实际上是一个<label>
元素,例:
// 你以为的input元素
<base-input v-on:focus.native="onFocus"></base-input>
// 实际上的input元素
<label>
{{ label }}
<input
v-bind="$attrs"
v-bind:value="value"
v-on:input="$emit('input', $event.target.value)"
>
</label>
// 老千层饼了
- 此时父级的
.native
将静默失败,不会产生任何报错,但函数无法正常调用。 - 为解决这个问题,vue提供的
$listeners
监听属性派上用场,它是一个对象,里面包含了在这个组件上的所有监听器。也就是说如果你使用子组件时,给它传入的所有v-on事件都可以在$listeners
中找到。(除了.native
修饰器的v-on事件监听器)
(4.) .sync
修饰符
想要对一个prop进行双向绑定,但真正的双向绑定会带来维护问题。
- (1.)
$emit
可以使子组件触发父组件自定义事件,那么也可以实现子组件改变父组件值的操作,例:
<template id="componentThree">
<button @click="$emit('set-age',123)">click</button>
</template>
<div id='app'>
<component-three :age="age" @set-age="sayAge"></component-three>
</div>
<script>
var ComponentC = {
props:['age'],
data:function(){
return {}
},
template:"#componentThree"
}
new Vue({
el:'#app',
data:{
age:45
},
components:{
'component-three':ComponentC,
},
methods:{
sayAge:function(cont){
console.log(this.age) // age初始值为45
this.age = cont
console.log(this.age) // age变为123
}
}
})
</script>
- 不过以上写法过于麻烦,需要自己定义方法,推荐以
update:myPropName
的模式触发事件取而代之,例:
<template id="componentThree">
<button @click="$emit('update:title',newTitle)">click</button>
</template>
<div id='app'>
<!--与之前相比,事件名称被换成了update:title-->
<!--update:是被固定的也就是vue为我们约定好的名称部分,title是我们要修改的状态的名称,是我们手动配置的,与传入的状态名字对应起来-->
<component-three :title="doc.title" @update:title="doc.title = $event"></component-three>
<h1>{{doc.title}}</h1>
</div>
<script>
var ComponentC = {
props:['title'],
data:function(){
return {
newTitle: 'have a happy day'
}
},
template:"#componentThree"
}
new Vue({
el:'#app',
data:{
doc:{
age:45,
title: "hello mini!!"
}
},
components:{
'component-three':ComponentC
}
})
</script>
- 点击前
- 点击后
update:myPropName
这种模式的缩写,即.sync
修饰符:
<div id='app'>
<component-three :title="doc.title" @update:title="doc.title = $event"></component-three>
</div>
// 最终缩写为
<div id='app'>
<component-three :title.sync="doc.title"></component-three>
</div>
- 注意: 带有
.sync
修饰符的v-bind
不能和表达式一起使用,例如v-bind:title.sync=”doc.title + ‘!’”
是无效的。你只能提供你想要绑定的 property 名。 - 辅助理解:vue中的.sync修饰符用法及原理详解