element-ui - 源码学习 - 自定义事件

1.前言

这次探索源于改造element-ui中下拉菜单的触发方式,el-dropdown提供了两种触发方式hoverclick。由于之前项目中有很多自定义右键菜单的操作。而element-ui并未提供右键菜单相关的组件,于是查看el-dropdown的源码想改造一个支持此右键操作的下拉菜单。尽管这不符合实际用户操作习惯哈,不过这只是一次改造element-ui组件的一个尝试,改造并非止于此。

2.el-dropdown目录结构

查看 dropdown.vuedropdown-item.vue中都混入了 Emitter

import Emitter from 'element-ui/src/mixins/emitter';

3. Emitter

在学习vue自定义事件的时候,父组件在使用子组件时,可以为子组件的自定义事件指定事件处理程序。子组件中可以通过vm.$emit(eventName, [...args])触发自定义事件。但是vue官网的案例比较简单,案例中只涉及到一层子组件。

Emitter定义了两个方法,扩展了自定义事件,父组件可以通过broadcast(广播)的方式触发后代组件的自定义事件;后代组件可以通过dispatch(派遣)的方式触发最近一级指定名称的祖先组件的自定义事件。源码如下:

// 指定后代组件名称componentName
function broadcast(componentName, eventName, params) {
  this.$children.forEach(child => {
    var name = child.$options.componentName;

    if (name === componentName) {
      child.$emit.apply(child, [eventName].concat(params));
    } else {
      // 递归调用进行广播,触发自定义事件
      broadcast.apply(child, [componentName, eventName].concat([params]));
    }
  });
}
export default {
  methods: {
    // 触发祖先组件的自定义事件
    dispatch(componentName, eventName, params) {
      var parent = this.$parent || this.$root;
      var name = parent.$options.componentName;
      // 循环找到最近一级名称为componentName的祖先组件
      while (parent && (!name || name !== componentName)) {
        parent = parent.$parent;

        if (parent) {
          name = parent.$options.componentName;
        }
      }
      if (parent) {
        parent.$emit.apply(parent, [eventName].concat(params));
      }
    },
    broadcast(componentName, eventName, params) {
      broadcast.call(this, componentName, eventName, params);
    }
  }
};
复制代码

4.案例

<el-dropdown trigger="click">
  <span class="el-dropdown-link">
    下拉菜单<i class="el-icon-arrow-down el-icon--right"></i>
  </span>
  <el-dropdown-menu slot="dropdown">
    <el-dropdown-item>黄金糕</el-dropdown-item>
    <el-dropdown-item>狮子头</el-dropdown-item>
    <el-dropdown-item>螺蛳粉</el-dropdown-item>
    <el-dropdown-item>双皮奶</el-dropdown-item>
    <el-dropdown-item>蚵仔煎</el-dropdown-item>
  </el-dropdown-menu>
</el-dropdown>
复制代码

从组件代码结果上看,el-dropdown子组件是el-dropdown-item,孙组件是el-dropdown-item。查看el-dropdown的侦听器:

watch: {
  visible(val) {
    this.broadcast('ElDropdownMenu', 'visible', val);
    this.$emit('visible-change', val);
  },
  focusing(val) {
    const selfDefine = this.$el.querySelector('.el-dropdown-selfdefine');
    if (selfDefine) { // 自定义
      if (val) {
        selfDefine.className += ' focusing';
      } else {
        selfDefine.className = selfDefine.className.replace('focusing', '');
      }
    }
  }
}
复制代码

this.broadcast('ElDropdownMenu', 'visible', val);用于向后代名为ElDropdownMenu调用名为visible的自定义事件。

在查看dropdown-item.vue选项中的方法:

methods: {
  handleClick(e) {
    this.dispatch('ElDropdown', 'menu-item-click', [this.command, this]);
  }
}
复制代码

this.dispatch('ElDropdown', 'menu-item-click', [this.command, this]);触发了el-dropdown的自定义事件menu-item-click

5.总结

Emitter实际上扩展了自定义事件的触发范围。父组件可以触发后代组件的自定义事件,不限于儿子组件。后代组件可以触发最近一级指定名称的祖先组件的自定义事件。其中涉及到事件处理程序的位置,通俗的讲,就是父组件干了一件事情,它可以通过广播的方式告诉后代组件作出回应,事件处理程序在后代组件中定义;而后代组件干了一件事件,可以通知某一祖先组件作出回应,事件处理程序在祖先组件中定义。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值