网站首页 » 前端开发 » Vue » Vue2 Element dom.js 详解
上一篇:
下一篇:

Vue2 Element dom.js 详解

一个 dom.js 模块功能比较简单,把一些常用的 dom 操作封装在这里。比如:类的添加删除,样式的设置等。

dom.js
/* istanbul ignore next */

import Vue from 'vue';
// 运行环境
const isServer = Vue.prototype.$isServer;
// 匹配 “:”,“-”,“_” 中的任意一个,但每一个都可以重复,并且连带后面的一个字符(用于改为大写)
const SPECIAL_CHARS_REGEXP = /([\:\-\_]+(.))/g;
// 匹配 moz开头并且后面含有一个大写字母的字符串
const MOZ_HACK_REGEXP = /^moz([A-Z])/;
// 获取 IE 版本,在非 IE  浏览器中会返回 undefined
const ieVersion = isServer ? 0 : Number(document.documentMode);

/* istanbul ignore next */
// 去掉字符串前后空格,\uFEFF 是零宽不换行空格(Zero Width No-Break Space)
const trim = function (string) {
  return (string || '').replace(/^[\s\uFEFF]+|[\s\uFEFF]+$/g, '');
};
/* istanbul ignore next */
const camelCase = function (name) {
  // 这里涉及到两方法的知识点,replace() 方法,和正则中的匹配项
  // replace() 方法可以接收一个函数作为参数,函数接收的参数个数跟正则相关可以是三个,也可以是多个,在这里有两个匹配项
  // _ 为正则匹配项;separator:匹配到的第一项,letter:匹配到的第二项;offset:匹配到项的位置

  return name.replace(SPECIAL_CHARS_REGEXP, function (_, separator, letter, offset) {
    return offset ? letter.toUpperCase() : letter;
  }).replace(MOZ_HACK_REGEXP, 'Moz$1');
};

/* istanbul ignore next */
// 添加事件监听,这里主要是做了兼容处理而已
export const on = (function () {
  if (!isServer && document.addEventListener) {
    return function (element, event, handler) {
      if (element && event && handler) {
        element.addEventListener(event, handler, false);
      }
    };
  } else {
    return function (element, event, handler) {
      if (element && event && handler) {
        element.attachEvent('on' + event, handler);
      }
    };
  }
})();

/* istanbul ignore next */
// 解除事件监听
export const off = (function () {
  if (!isServer && document.removeEventListener) {
    return function (element, event, handler) {
      if (element && event) {
        element.removeEventListener(event, handler, false);
      }
    };
  } else {
    return function (element, event, handler) {
      if (element && event) {
        element.detachEvent('on' + event, handler);
      }
    };
  }
})();

/* istanbul ignore next */
// 只监听一次
export const once = function (el, event, fn) {
  var listener = function () {
    if (fn) {
      fn.apply(this, arguments);
    }
    off(el, event, listener);
  };
  on(el, event, listener);
};

/* istanbul ignore next */
// 是否含有某个类名
export function hasClass(el, cls) {
  if (!el || !cls) return false;
  if (cls.indexOf(' ') !== -1) throw new Error('className should not contain space.');
  if (el.classList) { // classList 存在,即支持 classList
    return el.classList.contains(cls);
  } else { // 如果不支持,而走 indexOf 查找
    return (' ' + el.className + ' ').indexOf(' ' + cls + ' ') > -1;
  }
};

/* istanbul ignore next */
// 添加类
export function addClass(el, cls) {
  if (!el) return;
  var curClass = el.className;
  var classes = (cls || '').split(' ');

  for (var i = 0, j = classes.length; i < j; i++) {
    var clsName = classes[i];
    if (!clsName) continue;

    if (el.classList) {
      el.classList.add(clsName);
    } else if (!hasClass(el, clsName)) {
      curClass += ' ' + clsName;
    }
  }
  if (!el.classList) {
    el.className = curClass;
  }
};

/* istanbul ignore next */
// 删除类
export function removeClass(el, cls) {
  // 只要其一不存,则直接返回
  if (!el || !cls) return;
  // 分割类名字符串
  var classes = cls.split(' ');
  // 处理下目标元素当前已设置类名
  var curClass = ' ' + el.className + ' ';

  for (var i = 0, j = classes.length; i < j; i++) {
    var clsName = classes[i];
    // 如果不存在直接跳过
    if (!clsName) continue;
    // 如果支持 classList
    if (el.classList) {
      // 直接使用 classList 的 remove 方法删除类名
      el.classList.remove(clsName);
    } else if (hasClass(el, clsName)) { // 如果不支持 classList
      curClass = curClass.replace(' ' + clsName + ' ', ' ');
    }
  }
  if (!el.classList) {
    // 去掉字符串前后空格
    el.className = trim(curClass);
  }
};

/* istanbul ignore next */
// 获取样式
export const getStyle = ieVersion < 9 ? function (element, styleName) {
  if (isServer) return;
  // 没传目标元素或者样式属性的直接返回 null
  if (!element || !styleName) return null;
  styleName = camelCase(styleName);
  if (styleName === 'float') {
    styleName = 'styleFloat';
  }
  try {
    switch (styleName) {
      // 如果为透明度 opacity
      case 'opacity':
        try {
          return element.filters.item('alpha').opacity / 100;
        } catch (e) {
          return 1.0;
        }
        // 其它样式直接设置
      default:
        return (element.style[styleName] || element.currentStyle ? element.currentStyle[styleName] : null);
    }
  } catch (e) {
    return element.style[styleName];
  }
} : function (element, styleName) { // 如果 IE 版本大于或者等于9,或者非 IE 浏览器
  // 如果不是浏览器环境,则直接返回
  if (isServer) return;
  // 没传目标元素或者样式属性的直接返回 null
  if (!element || !styleName) return null;
  styleName = camelCase(styleName);
  if (styleName === 'float') {
    styleName = 'cssFloat';
  }
  try {
    // defaultView 是 document 关联的 window 对象, defaultView 跟全局对象 window 指的是同一个东西(document.defaultView === window)
    // 不过在特定版本的火狐浏览器(Firefox 3.6)中,访问框架样式的时候,要使用 document.defaultView 才能获取得到
    // https://developer.mozilla.org/en-US/docs/Web/API/Window/getComputedStyle#defaultView

    var computed = document.defaultView.getComputedStyle(element, '');
    return element.style[styleName] || computed ? computed[styleName] : null;
  } catch (e) {
    return element.style[styleName];
  }
};

/* istanbul ignore next */
// 设置属性
export function setStyle(element, styleName, value) {
  // 没传目标元素或者样式属性的直接返回
  if (!element || !styleName) return;
  // 如果传入的是一个对象,则遍历下,并递归地设置样式
  if (typeof styleName === 'object') {
    for (var prop in styleName) {
      if (styleName.hasOwnProperty(prop)) {
        // 递归设置样式
        setStyle(element, prop, styleName[prop]);
      }
    }
  } else { // 如果不是对象
    styleName = camelCase(styleName);
    // 如果样式属性为 opacity 并且 IE 版本小于 9
    if (styleName === 'opacity' && ieVersion < 9) {
      // 兼容 IE 透明度的写法
      element.style.filter = isNaN(value) ? '' : 'alpha(opacity=' + value * 100 + ')';
    } else { // 否则直接设置
      element.style[styleName] = value;
    }
  }
};

一切尽在不言中,细细口味,如有不足,请多多指教。

  • 微信扫一扫,赏我

  • 支付宝扫一扫,赏我

声明

原创文章,不经本站同意,不得以任何形式转载,如有不便,请多多包涵!

本文永久链接:http://yunkus.com/vue-element-dom/

Leave a Reply

Your email address will not be published. Required fields are marked *

评论 END