Vue基础——将原生事件绑定到组件

Vue基础——将原生事件绑定到组件

1、首先看一个小例子

父组件:

<template>
  <div id="app">
    <my-button @click="handleClick"></my-button>
  </div>
</template>

<script>
import MyButton from "@/components/myButton";
export default {
  name: 'App',
  components: {MyButton},
  methods: {
    handleClick() {
      console.log(111);
    }
  }
}
</script>

子组件

<template>
  <div>点我</div>
</template>

<script>
export default {
  name: "myButton",
  data() {
    return {}
  },
  computed: {},
  methods: {},
  mounted() {}
}
</script>
你觉得点击了按钮之后,会有输出吗?

鼠标按烂了都不会输出,不要按坏了你的鼠标🙅‍♀️(不过好像只有 Vue2 是如此,Vue3 会有输出)

我的理解是:HTML 自带的标签,是可以直接绑定原生事件的;但 Vue 里面提供的标签,是不行的,比如 组件标签、router-link 等,因为它没有该事件,所以它认为这是一个自定义事件

如果我非要绑定呢?

把父组件中改成:

<template>
  <div id="app">
    <my-button @click.native="handleClick"></my-button>
  </div>
</template>
注意:给父组件绑定事件,原理是把该事件绑定到子组件的根标签。Vue 就是用这种手段去区分原生事件和组件自定义事件的,如果是原生,那么就给你绑定到该子组件的根标签;如果是组件自定义事件,那么就给你绑定到该组件标签上
2、以上通过加 .native 的方法,对点击事件挺好使,但是对 focus 事件不好使了。
举例如下:

父组件:

<template>
  <div id="app">
    <my-button @focus.native="handleClick"></my-button>
  </div>
</template>

子组件:

<template>
  <div>点我:<input type="text"></div>
</template>

翻译过来就是:我们给子组件的根标签绑定了一个聚焦事件,但是 div 标签本身就不具备 focus 事件,所以无论如何,它也聚不了焦,所以无论如何也无法触发

那么我们应该怎么触发呢?

让里面的 input 去触发,给 input 随便绑定一个原生事件,在事件回调函数里面写上 $emit 去触发(以下模板是组件自定义事件)

所以写法就是:

父组件:(千万注意:这里不要加上 .native 的后缀,因为加了,它就给你绑到子组件的根标签去了,而根标签是 HTML 自带的原生标签,你只能给它绑定原生事件)

<template>
  <div id="app">
    <my-button @focus="handleClick"></my-button>
  </div>
</template>

子组件:

<template>
  <div>点我:<input type="text" @focus="$emit('focus')"></div>
</template>
注意:

以下代码代表给该组件绑定一个名字叫做 click 的事件,这不叫 点击 事件,只是名字叫做 click,绑定到的是 my-button 标签上,而不是它的根标签,属于组件自定义事件的范畴(只能通过 $emit 触发)

<my-button @click="handleClick"></my-button>

这个代表给该组件的 子组件的根标签 绑定一个点击事件,因为根标签是原生标签,所以这是货真价实的点击事件。Vue 没有把它绑定到 my-button 上,而绑到了该子组件的根标签,属于原生事件的范畴

<my-button @click.navite="handleClick"></my-button>
3、进阶写法

父组件:

<template>
  <div id="app">
    <my-button @focus="handleClick"></my-button>
  </div>
</template>

子组件:(基础写法)

<template>
  <div>点我:<input type="text" @focus="sayHello"></div>
</template>

<script>
export default {
  name: "myButton",
  data() {
    return {}
  },
  computed: {},
  methods: {
    sayHello() {
      this.$emit('focus')
    }
  },
  mounted() {}
}
</script>

子组件:(高级写法)

<template>
<!--  v-on 需要绑定的是一个属性,所以我们应该把它写在计算属性里面,并返回一个对象-->
  <div>点我:<input type="text" v-on="sayHi"></div>
</template>

<script>
export default {
  name: "myButton",
  data() {
    return {}
  },
  computed: {
    // 原来计算属性的方法一开始就会执行
    sayHi() {
      // $listeners:只包含父组件上绑定的事件(不含 .native 修饰的),不包含自己的
      let obj = Object.assign({}, this.$listeners, {
        focus: () => {
          console.log('input 框触发了 focus 事件');
          this.$emit('focus')
        }
      })
      console.log(obj);
      return obj
    }
  },
  methods: {},
  mounted() {}
}
</script>
这里我们重写了 $listeners 身上的 focus 事件,然后干了一件什么事呢?(当 input 框触发了原生事件时,都会走下面这个对象里面的事件回调函数,这里其实是重写了 input 原生事件聚焦的回调函数)

this.$emit('focus'),告诉父组件,我要你执行名字叫做 focus 的组件自定义事件的回调函数

这个方法就相当于是集成了所有事件,在处理多个事件时很方便

总结:

1、不能给自定义组件绑定原生事件,若要绑定原生事件,就要使用.native修饰符

2、<my-button @click="test" />是绑定在了my-button这个标签上

<my-button @click.native="test" />是绑定在了它里面的根标签上,即深入到组件内部去了

相关链接:https://www.cnblogs.com/nys013/p/13653292.html

posted @ 2022-08-19 09:24  朱在春  阅读(745)  评论(0编辑  收藏  举报