十二、自定义事件

自定义事件

(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修饰符用法及原理详解
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值