IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> ElementUI 、AntDesign 、IVIew三大组件库z-index层级管理方案对比总结 -> 正文阅读

[JavaScript知识库]ElementUI 、AntDesign 、IVIew三大组件库z-index层级管理方案对比总结

ElementUI

elementUI将弹窗层级管理收敛到了一个入口PopupManager中,涉及zIndex层级的弹窗组件实例都需要注册到PopupManager中。源码传送门

// element/src/utils/popup/popup-manager.js
import { addClass, removeClass } from 'element-ui/src/utils/dom';

// 是否有模态层
let hasModal = false;
// 是否有初始zIndex
let hasInitZIndex = false;
// z-index值
let zIndex;

// 获取模态层
const getModal = function() {
  let modalDom = PopupManager.modalDom;
  if (modalDom) {
    hasModal = true;
  } else {
    hasModal = false;
    modalDom = document.createElement('div');
    PopupManager.modalDom = modalDom;

    modalDom.addEventListener('touchmove', function(event) {
      event.preventDefault();
      event.stopPropagation();
    });

    modalDom.addEventListener('click', function() {
      PopupManager.doOnModalClick && PopupManager.doOnModalClick();
    });
  }

  return modalDom;
};

// 组件实例集合
const instances = {};

// 弹窗管理器
const PopupManager = {
  // 模态消失渐退
  modalFade: true,

  getInstance: function(id) {
    return instances[id];
  },

  register: function(id, instance) {
    if (id && instance) {
      instances[id] = instance;
    }
  },

  deregister: function(id) {
    if (id) {
      instances[id] = null;
      delete instances[id];
    }
  },

  nextZIndex: function() {
    return PopupManager.zIndex++;
  },

  modalStack: [],

  doOnModalClick: function() {
    const topItem = PopupManager.modalStack[PopupManager.modalStack.length - 1];
    if (!topItem) return;

    const instance = PopupManager.getInstance(topItem.id);
    if (instance && instance.closeOnClickModal) {
      instance.close();
    }
  },

  // 打开模态层
  openModal: function(id, zIndex, dom, modalClass, modalFade) {
    if (!id || zIndex === undefined) return;
    this.modalFade = modalFade;

    const modalStack = this.modalStack;

    for (let i = 0, j = modalStack.length; i < j; i++) {
      const item = modalStack[i];
      if (item.id === id) {
        return;
      }
    }

    const modalDom = getModal();

    addClass(modalDom, 'v-modal');
    if (this.modalFade && !hasModal) {
      addClass(modalDom, 'v-modal-enter');
    }
    if (modalClass) {
      let classArr = modalClass.trim().split(/\s+/);
      classArr.forEach(item => addClass(modalDom, item));
    }
    setTimeout(() => {
      removeClass(modalDom, 'v-modal-enter');
    }, 200);

    if (dom && dom.parentNode && dom.parentNode.nodeType !== 11) {
      dom.parentNode.appendChild(modalDom);
    } else {
      document.body.appendChild(modalDom);
    }

    if (zIndex) {
      modalDom.style.zIndex = zIndex;
    }
    modalDom.tabIndex = 0;
    modalDom.style.display = '';

    this.modalStack.push({ id: id, zIndex: zIndex, modalClass: modalClass });
  },
  
  // 关闭模态层
  closeModal: function(id) {
    const modalStack = this.modalStack;
    const modalDom = getModal();

    if (modalStack.length > 0) {
      const topItem = modalStack[modalStack.length - 1];
      if (topItem.id === id) {
        if (topItem.modalClass) {
          let classArr = topItem.modalClass.trim().split(/\s+/);
          classArr.forEach(item => removeClass(modalDom, item));
        }

        modalStack.pop();
        if (modalStack.length > 0) {
          modalDom.style.zIndex = modalStack[modalStack.length - 1].zIndex;
        }
      } else {
        for (let i = modalStack.length - 1; i >= 0; i--) {
          if (modalStack[i].id === id) {
            modalStack.splice(i, 1);
            break;
          }
        }
      }
    }

    if (modalStack.length === 0) {
      if (this.modalFade) {
        addClass(modalDom, 'v-modal-leave');
      }
      setTimeout(() => {
        if (modalStack.length === 0) {
          if (modalDom.parentNode) modalDom.parentNode.removeChild(modalDom);
          modalDom.style.display = 'none';
          PopupManager.modalDom = undefined;
        }
        removeClass(modalDom, 'v-modal-leave');
      }, 200);
    }
  }
};

// 代理zIndex
Object.defineProperty(PopupManager, 'zIndex', {
  configurable: true,
  get() {
    if (!hasInitZIndex) {
      zIndex = zIndex || 2000;
      hasInitZIndex = true;
    }
    return zIndex;
  },
  set(value) {
    zIndex = value;
  }
});

// 获取最高层的弹窗
const getTopPopup = function() {
  if (PopupManager.modalStack.length > 0) {
    const topPopup = PopupManager.modalStack[PopupManager.modalStack.length - 1];
    if (!topPopup) return;
    const instance = PopupManager.getInstance(topPopup.id);

    return instance;
  }
};

// 处理esc按键
window.addEventListener('keydown', function(event) {
  if (event.keyCode === 27) {
    const topPopup = getTopPopup();

    if (topPopup && topPopup.closeOnPressEscape) {
      topPopup.handleClose
        ? topPopup.handleClose()
        : (topPopup.handleAction ? topPopup.handleAction('cancel') : topPopup.close());
    }
  }
});

export default PopupManager;

AntDesign

AntDesign的层级管理方案,利用了less预处理语言的特性,根据组件类型声明基准zIndex,不同类型组件之间的基准值相差至少10,同时组件内部基于基准值维护各自的zIndex。源码传送门

// ant-design/components/style/themes/default.less
/* z-index列表, 按值从小到大排列 */
@zindex-badge: auto;
@zindex-table-fixed: 2;
@zindex-affix: 10;
@zindex-back-top: 10;
@zindex-picker-panel: 10;
@zindex-popup-close: 10;
@zindex-modal: 1000;
@zindex-modal-mask: 1000;
@zindex-message: 1010;
@zindex-notification: 1010;
@zindex-popover: 1030;
@zindex-dropdown: 1050;
@zindex-picker: 1050;
@zindex-popoconfirm: 1060;
@zindex-tooltip: 1070;
@zindex-image: 1080;

以Table组件为例:
// ant-design/components/table/style/index.less
@import '../../style/themes/index';
 
@table-sticky-zindex: (@zindex-table-fixed + 1);
 
&-summary {
    position: relative;
    z-index: @zindex-table-fixed;
    background: @table-bg;
}

&-cell-fix-left,
&-cell-fix-right {
    position: -webkit-sticky !important;
    position: sticky !important;
    z-index: @zindex-table-fixed;
    background: @table-bg;
}

&-sticky {
    &-holder {
        position: sticky;
        z-index: @table-sticky-zindex;
        background: @component-background;
    }
}

IVIew

IView的方案和ElementUI类似,但是看上去更简单直接,全局维护一个transferIndex值,每个组件只要使用了一次transferIndex,就主动调用方法transferIncrease使得transferIndex的值+1。源码传送门

// iview/src/utils/transfer-queue.js
let transferIndex = 0;

function transferIncrease() {
    transferIndex++;
}

export {transferIndex, transferIncrease};

下面以poptip组件为例(已移除无关代码)。其默认基础zIndex为1060,实际zIndex为1060 + transferIndex,当每个Poptip组件实例生成时,获取当前transferIndex,并调用方法transferIncrease。源码传送门

// iview/src/components/poptip/poptip.vue
import { transferIndex, transferIncrease } from '../../utils/transfer-queue';

export default {
    data() {
        return {
            tIndex: this.handleGetIndex()
        }
    },
    computed: {
        styles() {
            let style = {};
    
            if (this.transfer) style['z-index'] = 1060 + this.tIndex;
    
            return style;
        }
    },
    methods: {
        handleGetIndex () {
            transferIncrease();
            return transferIndex;
        }
    }
}

对比总结

库名方法优点缺点
ElementUI统一入口注册组件,在内部管理层级统一管理,层级递增,不易紊乱只针对弹窗层级管理
AntDesign根据类型划分基准层级,组件内部维护层级关系分层设计,隔离性高基准层级的设定依靠经验值
IView由各个组件维护全局zIndex颗粒度较细,针对组件定制化层级维护较为零散,排查问题时比较麻烦
  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2021-09-02 11:15:56  更:2021-09-02 11:16:40 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年12日历 -2024/12/27 20:20:25-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码
数据统计