【vuejs】 $on、$once、$off、$emit 事件监听方法详解以及项目实战

1. Vue实例方法概述

1.1 vm.$on

vm.$on是Vue实例用来监听自定义事件的方法。它允许开发者在Vue实例上注册事件监听器,当事件被触发时,指定的回调函数会被执行。

  • 事件监听:vm.$on允许开发者绑定一个或多个事件到Vue实例上,并且可以为每个事件指定一个或多个回调函数。
  • 回调执行:当使用vm.$emit触发事件时,所有绑定到该事件的回调函数将按照它们被注册的顺序执行。

1.2 vm.$once

vm.𝑜𝑛𝑐𝑒是𝑉𝑢𝑒实例的一个特殊方法,它与𝑣𝑚.onceVue 实例的一个特殊方法,它与v**m.on类似,但只允许事件被触发一次。一旦事件被触发,绑定的监听器将自动被移除。

  • 一次性监听:vm.$once提供了一种机制,确保某个事件监听器只响应一次事件,适用于那些只需要执行一次的逻辑。
  • 节省资源:通过自动移除监听器,vm.$once有助于减少不必要的内存占用和潜在的内存泄漏问题。

1.3 vm.$off

vm.𝑜𝑓𝑓用于从𝑉𝑢𝑒实例上移除事件监听器。这可以是之前通过𝑣𝑚.o**ff 用于从Vue 实例上移除事件监听器。这可以是之前通过v**m.on或vm.$once注册的监听器。

  • 移除监听器:vm.$off可以移除单个事件的监听器,也可以移除所有事件的所有监听器。
  • 灵活性:开发者可以根据需要,选择移除特定事件的特定回调,或者移除特定事件的所有回调,甚至是移除所有事件的所有回调。

1.4 vm.$emit

vm.$emit是Vue实例用来触发事件的方法。它允许开发者从Vue实例上发出自定义事件,通知其他监听器发生了某些事情。

  • 事件派发:vm.$emit可以携带额外的参数,这些参数将作为回调函数的参数传递给监听器。
  • 父子组件通信:在Vue的组件系统中,vm.$emit常用于子组件向父组件发送消息,实现父子组件之间的通信。

2. vm.$on 方法详解

2.1 监听器的注册与执行机制

vm.$on是Vue实例中用于事件监听的核心方法。它允许开发者在Vue实例上注册监听器,以响应特定的事件。

  • 监听器注册:通过vm.$on(eventName, callback)的形式,将callback函数注册为eventName事件的监听器。当事件被触发时,callback将被调用。
  • 执行顺序:事件触发时,所有注册的回调函数将按照它们注册的顺序依次执行。

2.2 参数传递与事件对象

vm.$on允许在触发事件时传递参数,这些参数将被传递给回调函数。

  • 参数传递:使用vm.$emit(eventName, arg1, arg2, ...)触发事件时,可以传递多个参数。这些参数将按顺序传递给监听器的回调函数。
  • 事件对象:虽然Vue的自定义事件不提供传统意义上的事件对象,但传递的参数允许开发者模拟事件对象的行为。

2.3 监听器的高级用法

vm.$on提供了一些高级用法,以增强事件监听的灵活性和功能。

  • 命名空间事件:在Vuex等状态管理库中,事件经常使用命名空间来区分不同来源的事件。
  • 组合事件:可以通过传递一个事件数组给vm.$on来一次性注册多个事件的监听器。

2.4 与vm.𝑜𝑛𝑐𝑒和𝑣𝑚.oncev**m.off的比较

vm.$on与其他事件处理方法相比,有其独特的用途和特点。

  • 与vm.𝑜𝑛𝑐𝑒的比较:𝑣𝑚.once 的比较:v**m.once用于注册只触发一次的监听器,而vm.$on注册的监听器可以响应多次事件触发。
  • 与vm.𝑜𝑓𝑓的比较:𝑣𝑚.o**ff 的比较:v**m.off用于移除监听器,可以与vm.$on配合使用,以在特定条件下清理不再需要的监听器,避免内存泄漏。

2.5 实践中的注意事项

在使用vm.$on时,开发者需要注意一些实践技巧和潜在的问题。

  • 避免循环引用:在组件销毁时,应使用vm.$off移除所有监听器,防止内存泄漏和循环引用问题。
  • 监听器的销毁:确保在组件或实例销毁时,正确清理所有注册的事件监听器,避免潜在的副作用。
  • 性能考虑:大量使用事件监听可能会影响性能,特别是在大型应用中。合理组织事件监听和优化事件处理逻辑是必要的。

3. vm.$once 方法详解

3.1 一次性事件监听器的使用场景

vm.$once提供了一种机制,允许事件只被监听一次,在事件触发后自动移除监听器。

  • 场景应用:适用于那些只需要执行一次的事件处理,例如初始化操作或一次性资源的加载。
  • 资源管理:通过确保监听器只触发一次,vm.$once有助于避免不必要的资源消耗和潜在的内存泄漏。

3.2 与vm.$on的比较

vm.𝑜𝑛𝑐𝑒与𝑣𝑚.oncev**m.on在功能上相似,但在触发行为上存在明显差异。

  • 触发次数:vm.𝑜𝑛注册的事件可以被多次触发,而𝑣𝑚.o**n 注册的事件可以被多次触发,而v**m.once注册的事件只能触发一次。
  • 使用选择:开发者应根据具体需求选择使用vm.𝑜𝑛或𝑣𝑚.o**nv**m.once,以实现更有效的事件处理。

3.3 参数传递和事件对象

vm.$once同样支持在触发事件时传递参数给回调函数。

  • 参数传递机制:与vm.𝑜𝑛相同,𝑣𝑚.o**n 相同,v**m.once允许在事件触发时传递参数,这些参数将被传递给注册的回调函数。
  • 事件对象模拟:虽然Vue不提供标准的事件对象,但通过参数传递,开发者可以模拟事件对象的功能。

3.4 实践中的注意事项

在使用vm.$once时,开发者应注意以下实践技巧和潜在问题。

  • 监听器的自动移除:vm.𝑜𝑛𝑐𝑒在事件触发后会自动移除监听器,开发者无需手动调用𝑣𝑚.once 在事件触发后会自动移除监听器,开发者无需手动调用v**m.off。
  • 避免重复注册:由于vm.$once的特性,重复注册同一个事件的监听器将不会有任何效果,因为第一个监听器在触发后已被移除。
  • 组件销毁:在使用vm.$once时,也应注意组件的销毁逻辑,确保组件销毁时不会留下未清理的监听器。

3.5 应用示例

通过具体的代码示例,展示vm.$once在实际开发中的应用。

new Vue({
  data: {
    message: 'Hello World'
  },
  created: function () {
    this.$once('showMessage', (msg) => {
      console.log(msg);
    });
  },
  methods: {
    triggerOnce: function () {
      this.$emit('showMessage', this.message);
    }
  }
});

在这个示例中,showMessage事件只会被触发一次,之后即使再次调用triggerOnce方法,也不会有新的日志输出。

4. vm.$off 方法详解

4.1 移除事件监听器的机制

vm.$off是Vue实例中用于移除事件监听器的方法,它提供了一种机制来清理不再需要的事件监听,从而避免潜在的内存泄漏问题。

  • 移除机制:通过vm.$off([event, callback])的形式,可以移除Vue实例上注册的事件监听器。如果提供了事件名称和回调函数,则只移除特定的监听器;如果没有提供参数,则移除所有事件的所有监听器。
  • 灵活性:vm.$off的灵活性体现在可以根据实际情况选择移除单个监听器或全部监听器,以满足不同的开发需求。

4.2 移除监听器的使用场景

vm.$off的使用场景通常与组件的生命周期管理相关,特别是在组件销毁或条件性事件监听的情况下。

  • 组件销毁:在Vue组件被销毁前,使用vm.$off移除所有注册的事件监听器,确保组件不会在销毁后继续触发事件,导致不可预期的行为。
  • 条件性监听:在某些情况下,事件监听可能只在特定条件下需要,一旦条件不再满足,就应该使用vm.$off移除监听器,以避免不必要的资源占用。

4.3 参数传递和事件对象

虽然vm.𝑜𝑓𝑓不直接涉及参数传递或事件对象,但它通常与𝑣𝑚.o**ff 不直接涉及参数传递或事件对象,但它通常与v**m.on和vm.$emit配合使用,这些方法允许在事件触发时传递参数。

  • 参数传递:在使用vm.𝑜𝑛注册监听器时,可以指定回调函数接收的参数,这些参数在事件触发时通过𝑣𝑚.o**n 注册监听器时,可以指定回调函数接收的参数,这些参数在事件触发时通过v**m.emit传递。
  • 事件对象:Vue的自定义事件不提供标准的事件对象,但开发者可以通过参数传递来模拟事件对象的功能,并通过vm.$off在适当的时候清理监听器。

4.4 与vm.𝑜𝑛和𝑣𝑚.o**nv**m.once的比较

vm.𝑜𝑓𝑓与𝑣𝑚.o**ffv**m.on和vm.$once在事件处理机制中扮演不同的角色,但它们共同构成了Vue实例的事件系统。

  • 与vm.𝑜𝑛的比较:𝑣𝑚.o**n 的比较:v**m.on用于注册事件监听器,而vm.$off用于移除这些监听器。两者通常成对出现,确保事件监听的生命周期得到妥善管理。
  • 与vm.𝑜𝑛𝑐𝑒的比较:𝑣𝑚.once 的比较:v**m .once注册的监听器在触发一次后会自动被移除,不需要显式调用vm.𝑜𝑓𝑓。然而,在某些复杂场景下,可能需要提前移除由𝑣𝑚.o**ff 。然而,在某些复杂场景下,可能需要提前移除由v**m.once注册的监听器,这时vm.$off同样适用。

4.5 实践中的注意事项

在使用vm.$off时,开发者应注意以下实践技巧和潜在问题,以确保事件监听的合理性和应用的性能。

  • 确保移除:在组件销毁或条件性事件不再需要时,应确保调用vm.$off来移除监听器,避免内存泄漏。
  • 避免重复移除:如果一个监听器已经被移除,再次调用vm.$off尝试移除同一个监听器是安全的,但应避免在逻辑上产生混淆。
  • 组件通信:在组件间通信时,合理使用vm.$off可以防止组件间的不必要耦合,尤其是在复杂的组件树中。

4.6 应用示例

通过具体的代码示例,展示vm.$off在实际开发中的应用,特别是在组件销毁时的事件清理。

new Vue({
  data: {
    message: 'Hello World'
  },
  created: function () {
    this.$on('showMessage', (msg) => {
      console.log(msg);
    });
  },
  beforeDestroy: function () {
    this.$off('showMessage');
  },
  methods: {
    triggerMessage: function () {
      this.$emit('showMessage', this.message);
    }
  }
});

在这个示例中,showMessage事件的监听器在组件销毁前通过beforeDestroy钩子使用vm.$off进行了清理。

5. vm.$emit 方法详解

5.1 事件派发机制

vm.$emit是Vue实例中用于事件派发的核心方法。它允许开发者触发自定义事件,从而实现组件之间的通信。

  • 事件触发:通过vm.$emit(eventName)的形式,可以触发一个名为eventName的事件。
  • 参数传递:vm.$emit可以携带额外的参数,这些参数将作为监听器回调函数的参数被传递。

5.2 父子组件通信

vm.$emit在Vue组件系统中扮演着至关重要的角色,尤其是在父子组件之间的通信中。

  • 子组件触发:子组件通过调用vm.$emit来触发一个事件,该事件可以被父组件监听。
  • 父组件监听:父组件通过在子组件的引用上使用v-on指令来监听子组件触发的事件。

5.3 事件名称的动态性

vm.$emit支持动态事件名称,这为事件派发提供了更大的灵活性。

  • 动态事件:可以使用变量来指定事件名称,从而根据不同的条件触发不同的事件。

5.4 与vm.𝑜𝑛和𝑣𝑚.o**nv**m.once的配合使用

vm.𝑒𝑚𝑖𝑡与𝑣𝑚.emitv**m.on和vm.$once紧密配合,共同构成了Vue的事件系统。

  • 与vm.𝑜𝑛:当使用𝑣𝑚.o**n :当使用v**m.emit触发事件时,所有通过vm.$on注册的监听器将被调用。
  • 与vm.𝑜𝑛𝑐𝑒:使用𝑣𝑚.once :使用v**m.emit触发一次性事件时,可以配合vm.$once来确保事件只被触发一次。

5.5 事件冒泡

在Vue中,自定义事件不支持冒泡。但是,可以通过适当的设计模式来模拟事件冒泡的行为。

  • 事件代理:可以通过在父组件上监听事件,然后根据事件的来源或内容来处理,从而实现类似冒泡的效果。

5.6 实践中的注意事项

在使用vm.$emit时,开发者应注意以下实践技巧和潜在问题。

  • 避免滥用:过度使用事件派发可能会使组件之间的耦合度增加,应谨慎使用。
  • 命名冲突:确保事件名称的唯一性,避免不同组件间的事件名称冲突。
  • 性能考虑:频繁的事件派发和监听可能会影响应用性能,特别是在大型应用中。

5.7 应用示例

通过具体的代码示例,展示vm.$emit在实际开发中的应用,尤其是在父子组件通信中。

// 子组件
new Vue({
  template: '<button @click="triggerEvent">Click me</button>',
  methods: {
    triggerEvent: function () {
      this.$emit('childEvent', 'Data from child');
    }
  }
});

// 父组件
new Vue({
  components: {
    'child-component': ChildComponent
  },
  template: `
    <div>
      <child-component @childEvent="handleEvent"></child-component>
    </div>
  `,
  methods: {
    handleEvent: function (data) {
      console.log('Received data from child:', data);
    }
  }
}).$mount('#app');

在这个示例中,子组件通过vm.$emit触发了一个名为childEvent的事件,并将数据传递给父组件的handleEvent方法。

6. 事件传递参数

6.1 参数传递的基本概念

在Vue的事件系统里,vm.$emit可以携带额外的参数,这些参数会被传递给监听器的回调函数。

  • 基本用法:vm.$emit允许在触发事件时传递一个或多个参数,如this.$emit('myEvent', param1, param2)
  • 参数顺序:参数将按照它们被传递的顺序,依次传递给监听器的回调函数。

6.2 参数传递的应用场景

参数传递在多种场景下非常有用,特别是在需要将数据从子组件传递到父组件时。

  • 数据传递:子组件通过vm.$emit传递数据,父组件接收这些数据并进行处理。
  • 事件处理:在事件的回调函数中,可以根据传递的参数执行不同的逻辑。

6.3 参数传递的高级技巧

Vue的参数传递不仅限于简单的数据传递,还可以用于实现更复杂的功能。

  • 动态参数:参数可以是动态计算的结果,增加了事件触发的灵活性。
  • 参数解构:在回调函数中,可以使用ES6的解构语法来简化参数的使用。

7. 实践示例

7.1 组件间通信

Vue组件间通信是开发中常见的需求,以下是使用vm.$emitvm.$on实现父子组件通信的示例。

// 子组件
new Vue({
  template: '<button @click="sendDataToParent">Send Data</button>',
  data: function () {
    return {
      childData: 'Data from child'
    };
  },
  methods: {
    sendDataToParent: function () {
      this.$emit('dataToSend', this.childData);
    }
  }
});

// 父组件
new Vue({
  components: {
    'child-component': ChildComponent
  },
  template: `
    <div>
      <child-component @dataToSend="receiveData"></child-component>
    </div>
  `,
  methods: {
    receiveData: function (data) {
      console.log('Data received from child:', data);
    }
  }
}).$mount('#app');

7.2 事件监听器的一次性使用

演示如何使用vm.$once来注册一个仅响应一次的事件监听器。

new Vue({
  data: {
    message: 'Hello Vue!'
  },
  created: function () {
    this.$once('showMessage', (msg) => {
      console.log(msg);
    });
  },
  methods: {
    showMessage: function () {
      this.$emit('showMessage', this.message);
    }
  }
});

7.3 移除事件监听器

展示如何在Vue实例销毁前使用vm.$off移除所有事件监听器,防止内存泄漏。

new Vue({
  data: {
    eventMessage: 'Event triggered'
  },
  created: function () {
    this.$on('eventToListen', (msg) => {
      console.log(msg);
    });
  },
  beforeDestroy: function () {
    this.$off();
  },
  methods: {
    triggerEvent: function () {
      this.$emit('eventToListen', this.eventMessage);
    }
  }
});

7.4 动态事件名的使用

使用变量作为事件名,展示vm.$emit如何触发动态指定的事件。

new Vue({
  data: {
    eventName: 'firstEvent'
  },
  methods: {
    triggerDynamicEvent: function () {
      this.$emit(this.eventName, 'Data for the first event');
      // Change event name for the next trigger
      this.eventName = 'secondEvent';
    }
  }
});

7.5 事件参数的传递与解构

演示如何使用vm.$emit传递多个参数,并在回调函数中使用ES6解构语法。

new Vue({
  data: {
    firstName: 'John',
    lastName: 'Doe'
  },
  methods: {
    emitGreeting: function () {
      this.$emit('greeting', this.firstName, this.lastName);
    }
  }
});

// 在监听器中
someVueInstance.$on('greeting', (firstName, lastName) => {
  console.log(`Hello, ${firstName} ${lastName}!`);
});

7.6 事件命名空间

展示如何在Vuex等状态管理库中使用事件命名空间。

// 在Vuex store中
const store = new Vuex.Store({
  state: {
    eventNamespace: 'user/'
  },
  mutations: {
    triggerUserEvent(state, payload) {
      const eventName = state.eventNamespace + 'userAction';
      this.$emit(eventName, payload);
    }
  }
});

// 在组件中监听命名空间事件
someVueInstance.$on('user/userAction', (payload) => {
  console.log('User action with payload:', payload);
});

// 触发事件
store.commit('triggerUserEvent', { action: 'login' });

以上示例涵盖了Vue实例方法vm.$onvm.$oncevm.$offvm.$emit在不同场景下的应用,展示了它们在实际开发中的灵活性和强大功能。

如果这篇文章对你有所帮助,欢迎点赞、分享和留言,让更多的人受益。感谢你的细心阅读,如果你发现了任何错误或需要补充的地方,请随时告诉我,我会尽快处理。

相关推荐
cwj&xyp23 分钟前
Python(二)str、list、tuple、dict、set
前端·python·算法
dlnu201525062225 分钟前
ssr实现方案
前端·javascript·ssr
古木201930 分钟前
前端面试宝典
前端·面试·职场和发展
轻口味2 小时前
命名空间与模块化概述
开发语言·前端·javascript
前端小小王3 小时前
React Hooks
前端·javascript·react.js
迷途小码农零零发3 小时前
react中使用ResizeObserver来观察元素的size变化
前端·javascript·react.js
娃哈哈哈哈呀3 小时前
vue中的css深度选择器v-deep 配合!important
前端·css·vue.js
旭东怪4 小时前
EasyPoi 使用$fe:模板语法生成Word动态行
java·前端·word
ekskef_sef5 小时前
32岁前端干了8年,是继续做前端开发,还是转其它工作
前端