美文网首页
.native && $listeners

.native && $listeners

作者: 简单tao的简单 | 来源:发表于2019-07-27 17:29 被阅读0次

将原生事件绑定到自定义组件

原生事件在自定义组件上是不起作用的

<template>
  <div>
    <my-component @click="outClick"></my-component>
  </div>
</template>

<script>
import Vue from 'vue';
Vue.component('my-component',{
  template:'<button>点击我</button>'
})
export default {
  methods:{
    outClick(){
      alert(111112)
    }
  }
}
</script>
//此时点击按钮无任何反应

添加修饰符.native,原生事件在自定义组件上就起作用了

<template>
  <div>
    <my-component @click.native="outClick"></my-component>
  </div>
</template>

<script>
import Vue from 'vue';
Vue.component('my-component',{
  template:'<button>点击我</button>'
})
export default {
  methods:{
    outClick(){
      alert(111112)
    }
  }
}
</script>
//此时点击会弹框

可以理解为该修饰符的作用就是把一个vue组件转化为一个普通的HTML标签,并且该修饰符对普通HTML标签是没有任何作用的

<template>
  <div>
    <my-component @click.native="outClick"></my-component>
    <div @click.native="outClick">ddddd</div> 
    //在div标签上用.native修饰符没有任何作用,不会弹框
  </div>
</template>
<script>
</script>

如果子组件的根元素是一个label标签或者是div一类的标签,那么.native将会失效

<template>
  <div>
    <my-component @focus.native="outClick"></my-component>
  </div>
</template>

<script>
import Vue from 'vue';
Vue.component('my-component',{  
  template:'<label><input placeholder="获取焦点" /></label>'
})
export default {
  methods:{
    outClick(){
      console.log(111113)
    }
  }
}
</script>

为了解决这个问题,Vue 提供了一个 $listeners 属性,它是一个对象,里面包含了作用在这个组件上的所有监听器。例如:

{
  focus: function (event) { /* ... */ }
  input: function (value) { /* ... */ },
}

有了这个 $listeners 属性,你就可以配合 v-on="$listeners"将所有的事件监听器指向这个组件的某个特定的子元素。
注意:使用.native修饰符的事件,不会体现在$listeners属性上。

<template>
  <div>
    <my-component @focus="outClick"></my-component>
    //这里不要用.native
  </div>
</template>

<script>
import Vue from 'vue';
Vue.component('my-component',{  
  template:'<label><input v-on="$listeners" placeholder="获取焦点" /></label>'
  //用v-on="$listeners"将所有的事件监听器指向input上
})
export default {
  methods:{
    outClick(){
      console.log(111113)
    }
  }
}
</script>

$listeners 和 v-model 配合,需要计算属性inputListeners,把父组件传递进来的事件和v-model用到的事件合并为一个新对象

<template>
  <div>
    <base-input v-model="username" label="基础输入组件" @click.native="fnClick" @focus="fnFocus" placeholder="请输入" />
  </div>
</template>

<script>
import Vue from 'vue';
// 注册组件
// 因为base-input的外层是一个label元素,所以默认情况下使用v-on:focus是无效的,所以需要配合$listeners使用,该属性可以把事件的监听指向组件中某个特定的元素
// 注意:如果父级的事件添加了.native修饰符,在$listeners中不会体现出来的
Vue.component('base-input',{
    inheritAttrs: false,
    props: ['label','value'],
    template: `
        <label>
            {{label}}
            <input v-bind="$attrs" v-on="inputListeners"/>
        </label>
    `,
    data() {
        return {
            
        }
    },
    computed: {
        inputListeners () {
            var vm = this
            return Object.assign({}, // `Object.assign` 将所有的对象合并为一个新对象
                this.$listeners,
                {
                    input: function () {
                        vm.$emit('input', event.target.value) //默认的event为input
                    },
                    focus: function (event) {
                        vm.$emit('focus', '哈哈哈,onfocus了') //第二个参数是fnFocus的参数
                    },
                    aa:function(){
                        vm.$emit('focus', '哈哈哈,onfocus了')
                    } //增加的事件
                }
            )
        }
    },
    mounted: function(){
        console.log(`$attrs:`)
        console.log(this.$attrs)
        console.log(`$listeners:`)
        console.log(this.$listeners) // 父级添加的所有属性都在这里
        console.log(this.inputListeners)
    },
    methods: {
        
    }
})
export default {
  data(){
    return {
      username: ''
    }
  },
  beforeUpdate: function () {
    console.log(this.username)
  },
  methods: {
    fnFocus: function(ev){
        console.log(`111111111111${JSON.stringify(ev)}`)
    },
    fnClick: function(ev){
        console.log(ev.type)
    }
  }
}
</script>

相关文章

网友评论

      本文标题:.native && $listeners

      本文链接:https://www.haomeiwen.com/subject/ecberctx.html