Vue 事件机制

简介: Vue 事件机制

Vue事件API

众所周知,Vue.js为我们提供了四个事件API,分别是$on](https://cn.vuejs.org/v2/api/#vm-on-event-callback),[$once$off](https://cn.vuejs.org/v2/api/#vm-off-event-callback),[$emit

初始化事件

初始化事件在vm上创建一个_events对象,用来存放事件。_events的内容如下:

{
    eventName: [func1, func2, func3]
}

存放事件名以及对应执行方法。

/*初始化事件*/
export function initEvents (vm: Component) {
  /*在vm上创建一个_events对象,用来存放事件。*/
  vm._events = Object.create(null)
  /*这个bool标志位来表明是否存在钩子,而不需要通过哈希表的方法来查找是否有钩子,这样做可以减少不必要的开销,优化性能。*/
  vm._hasHookEvent = false
  // init parent attached events
  /*初始化父组件attach的事件*/
  const listeners = vm.$options._parentListeners
  if (listeners) {
    updateComponentListeners(vm, listeners)
  }
}

$on

$on方法用来在vm实例上监听一个自定义事件,该事件可用$emit触发。

  Vue.prototype.$on = function (event: string | Array<string>, fn: Function): Component {
    const vm: Component = this

    /*如果是数组的时候,则递归$on,为每一个成员都绑定上方法*/
    if (Array.isArray(event)) {
      for (let i = 0, l = event.length; i < l; i++) {
        this.$on(event[i], fn)
      }
    } else {
      (vm._events[event] || (vm._events[event] = [])).push(fn)
      // optimize hook:event cost by using a boolean flag marked at registration
      // instead of a hash lookup
      /*这里在注册事件的时候标记bool值也就是个标志位来表明存在钩子,而不需要通过哈希表的方法来查找是否有钩子,这样做可以减少不必要的开销,优化性能。*/
      if (hookRE.test(event)) {
        vm._hasHookEvent = true
      }
    }
    return vm
  }

$once

$once监听一个只能触发一次的事件,在触发以后会自动移除该事件。

  Vue.prototype.$once = function (event: string, fn: Function): Component {
    const vm: Component = this
    function on () {
      /*在第一次执行的时候将该事件销毁*/
      vm.$off(event, on)
      /*执行注册的方法*/
      fn.apply(vm, arguments)
    }
    on.fn = fn
    vm.$on(event, on)
    return vm
  }

$off

$off用来移除自定义事件

Vue.prototype.$off = function (event?: string | Array<string>, fn?: Function): Component {
    const vm: Component = this
    // all
    /*如果不传参数则注销所有事件*/
    if (!arguments.length) {
      vm._events = Object.create(null)
      return vm
    }
    // array of events
    /*如果event是数组则递归注销事件*/
    if (Array.isArray(event)) {
      for (let i = 0, l = event.length; i < l; i++) {
        this.$off(event[i], fn)
      }
      return vm
    }
    // specific event
    const cbs = vm._events[event]
    /*本身不存在该事件则直接返回*/
    if (!cbs) {
      return vm
    }
    /*如果只传了event参数则注销该event方法下的所有方法*/
    if (arguments.length === 1) {
      vm._events[event] = null
      return vm
    }
    // specific handler
    /*遍历寻找对应方法并删除*/
    let cb
    let i = cbs.length
    while (i--) {
      cb = cbs[i]
      if (cb === fn || cb.fn === fn) {
        cbs.splice(i, 1)
        break
      }
    }
    return vm
  }

$emit

$emit用来触发指定的自定义事件。

Vue.prototype.$emit = function (event: string): Component {
    const vm: Component = this
    if (process.env.NODE_ENV !== 'production') {
      const lowerCaseEvent = event.toLowerCase()
      if (lowerCaseEvent !== event && vm._events[lowerCaseEvent]) {
        tip(
          `Event "${lowerCaseEvent}" is emitted in component ` +
          `${formatComponentName(vm)} but the handler is registered for "${event}". ` +
          `Note that HTML attributes are case-insensitive and you cannot use ` +
          `v-on to listen to camelCase events when using in-DOM templates. ` +
          `You should probably use "${hyphenate(event)}" instead of "${event}".`
        )
      }
    }
    let cbs = vm._events[event]
    if (cbs) {
      /*将类数组的对象转换成数组*/
      cbs = cbs.length > 1 ? toArray(cbs) : cbs
      const args = toArray(arguments, 1)
      /*遍历执行*/
      for (let i = 0, l = cbs.length; i < l; i++) {
        cbs[i].apply(vm, args)
      }
    }
    return vm
  }
目录
相关文章
|
1天前
|
JavaScript
Vue学习之--------深入理解Vuex之多组件共享数据(2022/9/4)
这篇文章通过一个实际的Vue项目案例,演示了如何在Vuex中实现多组件间共享数据。文章内容包括在Vuex的state中新增用户数组,创建Person.vue组件用于展示和添加用户信息,以及在Count组件中使用Person组件操作的数据。通过测试效果展示了组件间数据共享和状态更新的流程。
Vue学习之--------深入理解Vuex之多组件共享数据(2022/9/4)
|
1天前
|
JavaScript
Vue学习之--------深入理解Vuex之模块化编码(2022/9/4)
这篇文章详细介绍了Vuex的模块化编码和命名空间的使用,旨在让代码更易于维护并提高数据分类的明确性。内容包括模块化和命名空间的概念、如何在store中配置模块、以及如何在组件中使用模块化的数据。文章通过实战项目案例,展示了如何拆分`store/index.js`文件,创建`count.js`和`person.js`模块,并在`Count.vue`和`Person.vue`组件中使用这些模块。最后,文章还提供了测试效果和一些使用注意点。
Vue学习之--------深入理解Vuex之模块化编码(2022/9/4)
|
1天前
|
JavaScript 前端开发 开发者
Vue学习之--------深入理解Vuex、原理详解、实战应用(2022/9/1)
这篇文章详细介绍了Vuex的基本概念、使用场景、安装配置、基本用法、实际应用案例以及注意事项,通过一个数字累加器的实战示例,帮助开发者深入理解Vuex的原理和应用。
|
1天前
|
存储 JavaScript API
vue后台管理权限码处理
【8月更文挑战第19天】vue后台管理权限码处理
8 0
|
1天前
|
JavaScript
Vue学习之--------深入理解Vuex之getters、mapState、mapGetters(2022/9/3)
这篇文章深入探讨了Vuex中的getters概念和用法,以及如何通过mapState、mapGetters、mapActions和mapMutations四个辅助函数简化组件中的Vuex状态访问和操作,通过实际项目案例展示了这些概念的应用和效果。
|
4天前
|
JavaScript
Vue中如何设置在执行删除等危险操作时给用户提示(二次确认后执行对应的操作)
这篇文章介绍了在Vue项目中如何实现执行删除等危险操作时的二次确认机制,使用Element UI的`el-popconfirm`组件来弹出确认框,确保用户在二次确认后才会执行删除操作。
Vue中如何设置在执行删除等危险操作时给用户提示(二次确认后执行对应的操作)
|
4天前
|
JavaScript
如何创建一个Vue项目(手把手教你)
这篇文章是一篇手把手教读者如何创建Vue项目的教程,包括使用管理员身份打开命令行窗口、找到存放项目的位置、通过vue-cli初始化项目、填写项目信息、进入项目目录、启动项目等步骤,并提供了一些常见第三方库的引入方法。
如何创建一个Vue项目(手把手教你)
|
4天前
|
前端开发
StringBoot+Vue实现游客或用户未登录系统前、可以浏览商品等信息、但是不能购买商品或者加入购物车等操作。登录系统显示用户的登录名(源码+讲解)
这篇文章介绍了使用StringBoot+Vue实现用户登录状态判断的方法,包括前端加载用户信息和后端设置session的源码示例。
|
1天前
|
JavaScript
Vue学习之--------路由的query、params参数、路由命名(3)(2022/9/5)
这篇文章详细介绍了Vue路由中的query参数、命名路由、params参数以及props配置的使用方式,并通过实际项目案例展示了它们在开发中的应用和测试结果,同时解释了`<router-link>`的`replace`属性如何影响浏览器历史记录。
Vue学习之--------路由的query、params参数、路由命名(3)(2022/9/5)
|
1天前
|
JavaScript
Vue学习之--------VueX(2022/8/31)
这篇文章是关于VueX的基础知识介绍,涵盖了VueX中的state、mutations、getters和actions的定义和使用,以及Action提交mutation而非直接变更状态,以及mutations的同步执行特性。
Vue学习之--------VueX(2022/8/31)