在现有ElementUI下,子组件是不知道自己所属的标签页是否处于开启状态的。
下面写一个Vue的指令让子组件知道

实现

请看逐行注释。


 type TabPaneChildren = {
    onTabShow?: () => unknown;
    $children: TabPaneChildren[];
  };

  /**
   * 调用所有子孙组件的 onTabShow方法
   *
   */
  function callOnShow(instances: TabPaneChildren[]) {
    //遍历子组件
    instances.forEach((ins) => {
        //如果当前组件有onTabShow方法,则调用。
      ins.onTabShow && ins.onTabShow();
       //对当前组件的子组件递归调用callOnShow。
      if (ins.$children.length > 0) {
        callOnShow(ins.$children);
      }
    });
  }

  Vue.directive("tabs-lifecycle", {
    inserted(_el, _binding, vnode) {
      // 获取需要添加生命周期方法的ElTabs的实例
      const ins: any = vnode.componentInstance;
      // 获取所有ELPane的实例
      const panes: any[] = ins.$children.filter((k: any) => k.$vnode.tag?.includes("ElTabPane")) ??
        [];
      // 监听ElTabs的tab-click事件。详见官网文档。
      ins.$on("tab-click", async () => {
        // Promise.resolve()的效果等于 Vue.$nextTick();
        // 这一行也可改成ins.$nextTick();
        await Promise.resolve();
        // 遍历ElPane实例
        panes.forEach((pane) => {
            // 看源码可知ElPane的active属性代表当前ElPane是否被打开了
            // 从Vue devtool中也可以得知这一点。
          if (!pane.active) return;
            // 从pane的实例上抛出一个激活事件。可以直接在模板中监听
          pane.$emit("active");
            // 调用callOnShow方法,该方法会递归pane的所有的子孙组件,并调用他们的onTabShow方法,如果有的话。
          callOnShow([pane]);
        });
      });
    },
  });

使用

  1. 首先需要在ElTabs上使用这个指令

    <el-tabs v-tabs-lifecycle>
    ....
    <el-tabs>
  2. 在某个子组件中

    onTabShow(){
     //当前组件所属的标签被打开了
    }
  3. 在模板中
    监听ElTabPane的active事件即可

    <el-tabs v-tabs-lifecycle>
        <el-tab-pane @active="onActive">
        </el-tab-pane>
    <el-tabs>

    完。


OLong
450 声望318 粉丝