zoukankan      html  css  js  c++  java
  • Vue基础——将原生事件绑定到组件

    前言: 

    今天再次看了看vue文档,又找到了知识盲区。

    对于 将原生事件绑定到组件 ,文档有讲,别人也有写博客。

    但我还是想根据自己的理解把这一内容讲清楚

    总的来说,有三种方法

    • 使用native修饰符

    • 使用$emit分发事件

    • 使用$listeners

    正文:

    首先,show code

    html中代码
    <
    div id="app"> <my-button @click='handleClick'></my-button> </div>
    js中代码
    Vue.component('my-button',{ template:`<button>点击</button>` }) const vm = new Vue({ el:'#app', methods:{ handleClick(){ console.log('click') } } })

    在这里,我们定义了my-button子组件,在父组件中引用了,然后我们想在上面绑定click事件,触发handleClick回调。

    那么,可以猜猜有没有触发?

    ——结果很容易猜到,没有触发,click没有打印输出。

    为什么?

    ——因为vue有自己事件运行机制,my-button不是原生DOM元素,我们是无法直接给其绑定原生事件并触发的

    所以就有解决办法一:使用native修饰符

    我们仅需要在click后加上.native就可,如下

    <div id="app">
        <my-button @click.native='handleClick'></my-button>
    </div>

    相当于我们会把事件放在原生button标签上,此时事件便触发,click就打印了。

    虽然这个方法使用起来非常简单,但是其存在局限性:它只会把事件放在子组件的根标签上。

    上面子组件的根标签就是button,自然就触发了。

    但是某些情况下,将某些事件绑定在根标签而非目标标签时,是无法触发事件的。如下情况:

    <div id="app2">
        <my-input @focus.native='handleFocus'></my-input>
    </div>
    Vue.component('my-input',{
        template:`
        <label for="">
           label:
           <input type="text">
       </label>
        `
    })
    const vm2 = new Vue({
        el:'#app2',
        methods:{
            handleFocus(){
                console.log('focus...')
            }
        }
    })

    尽管我们使用了native修饰符,但是focus事件放在子组件根标签——label标签上,无法触发该事件。

    所以就有解决办法二:使用$emit分发事件

    Vue.component('my-input',{
        template:`
        <label for="">
           label:
           <input type="text" @focus='$emit("focus","子组件的value")'>
       </label>
        `
    })
    const vm2 = new Vue({
        el:'#app2',
        methods:{
            handleFocus(value){
                console.log('focus...',value)   //focus... 子组件的value
            }
        }
    })

    在子组件input标签中绑定focus事件,其回调中使用$emit分发事件,使父组件事件触发。

    $emit()有两个参数:

    第一个参数为分发的事件名,在这里为focus,也可改别的,只需要与父组件中给子组件标签上绑定的事件名一致即可

    第二个参数为给父组件该事件传的参数,我们在父组件中的该事件回调中就可接受到。所以我们一般想将子组件的数据传给父组件,完成父子组件间的通信,就可使用$emit。

    除了这个解决方法外,还有第三种:使用$listeners

    $listeners 它是一个对象,里面包含了作用在这个组件上的所有监听器。

    Vue.component('my-input',{
        template:`
        <label for="">
           label:
           <input type="text" v-on='$listeners'>    
       </label>
        `
    })

    (其余代码同上一个方法,故省略)

    在input上使用 v-on="$listeners" ,就是将所有的事件监听器指向这个input元素。

    故也同样能打印出,且value值为event对象。

    相比起方法二,这个$listener的使用更加全面——

      若是方法二,再在子组件标签上绑定多个事件,那就要在子组件进行相应的写事件名进行$emit分发

      而这个方法,就已经将所有事件监听绑在input元素上了,就不用再次设置

    而且,你也可以再次设置,$listeners的使用是很灵活的

    你可以自定义监听器,或者覆盖一些监听器的行为。

    在下面的代码中,重写了focus事件监听器

    Vue.component('my-input',{
        template:`
        <label for="">
           label:
           <input type="text" v-on='inputListeners'>    
       </label>
        `,
        computed:{
            inputListeners(){
                return Object.assign({},this.$listeners,{
                    focus:(event)=>{
                        this.$emit('focus',event.target.value)
                    }
                })
            }
        }
    })

    首先,我们得明白 v-on:xxx = fn 等价于 v-on={xxx:fn}  

    (tips:这里不可写为@={xxx:fn}。所有指令的缩写 @ : # 等等,都是在其有参数的情况下使用)

    其次,inputListeners是一个计算属性,返回的是一个对象,是将 $listeners 和 你重写的事件的对象 合并的对象

    还有,在这里重写监听器,还是用到了$emit,每个监听器都得到event对象,我们可以取出event.target.value传给父组件

    最后,父组件就能在focus时触发事件,并得到子组件传来的值了

    拓展:

    当我们使用 $attrs 和 $listeners 时,my-input就相当于一个完全透明包裹器了。

    怎么理解这句话呢?

      ——前面我们已经知道了  v-on = $listeners  会把 所有父组件绑定到该子组件上的事件都放在该元素上

        而使用  v-bind = $attrs  会把 除在props中声明了的,除style和class 的父传子的参数 都放在该元素上。

    那么 当我们同时使用两者放到某个元素上时 ,就已经把父组件所有放在子组件标签(my-input)上的属性、事件, 全都放在了该元素

    此时,事件调用、属性获取都不再有障碍, my-input 不就可以理解成是透明的了嘛~

    总结:

    三种方法都能使原生事件绑定到组件上,就写法上当然是第一种最简单,第三种更麻烦。但是只要理解了就都挺好写的了。

    但是在使用时,还是根据需求来,若是就是想绑定到组件的根标签上,直接使用第一种即可。否则,便使用二或三。

    参考自vue文档:将原生事件绑定到组件

     
    转载请私聊,引用请注明出处,欢迎交流评论,但请不要发动白起大招,谢谢!
  • 相关阅读:
    分布式 and 集群
    时间复杂度



    线性表 & 散列表
    栈 & 队列
    数组 & 链表
    数据结构&算法
    Docket 容器引擎
  • 原文地址:https://www.cnblogs.com/nys013/p/13653292.html
Copyright © 2011-2022 走看看