/* DOM 操作 API */ // 根据 html 代码片段创建 dom 对象 function createElemByHTML(html) { let div div = document.createElement('div') div.innerHTML = html return div.children } // 是否是 DOM List function isDOMList(selector) { if (!selector) { return false } if (selector instanceof HTMLCollection || selector instanceof NodeList) { return true } return false } // 封装 document.querySelectorAll function querySelectorAll(selector) { const result = document.querySelectorAll(selector) if (isDOMList(result)) { return result } else { return [result] } } // 记录所有的事件绑定 const eventList = [] // 创建构造函数 function DomElement(selector) { if (!selector) { return } // selector 本来就是 DomElement 对象,直接返回 if (selector instanceof DomElement) { return selector } this.selector = selector const nodeType = selector.nodeType // 根据 selector 得出的结果(如 DOM,DOM List) let selectorResult = [] if (nodeType === 9) { // document 节点 selectorResult = [selector] } else if (nodeType === 1) { // 单个 DOM 节点 selectorResult = [selector] } else if (isDOMList(selector) || selector instanceof Array) { // DOM List 或者数组 selectorResult = selector } else if (typeof selector === 'string') { // 字符串 selector = selector.replace('/\n/mg', '').trim() if (selector.indexOf('<') === 0) { // 如
selectorResult = createElemByHTML(selector) } else { // 如 #id .class selectorResult = querySelectorAll(selector) } } const length = selectorResult.length if (!length) { // 空数组 return this } // 加入 DOM 节点 let i for (i = 0; i < length; i++) { this[i] = selectorResult[i] } this.length = length } // 修改原型 DomElement.prototype = { constructor: DomElement, // 类数组,forEach forEach: function (fn) { let i for (i = 0; i < this.length; i++) { const elem = this[i] const result = fn.call(elem, elem, i) if (result === false) { break } } return this }, // clone clone: function (deep) { const cloneList = [] this.forEach(elem => { cloneList.push(elem.cloneNode(!!deep)) }) return $(cloneList) }, // 获取第几个元素 get: function (index) { const length = this.length if (index >= length) { index = index % length } return $(this[index]) }, // 第一个 first: function () { return this.get(0) }, // 最后一个 last: function () { const length = this.length return this.get(length - 1) }, // 绑定事件 on: function (type, selector, fn) { // selector 不为空,证明绑定事件要加代理 if (!fn) { fn = selector selector = null } // type 是否有多个 let types = [] types = type.split(/\s+/) return this.forEach(elem => { types.forEach(type => { if (!type) { return } // 记录下,方便后面解绑 eventList.push({ elem: elem, type: type, fn: fn }) if (!selector) { // 无代理 elem.addEventListener(type, fn) return } // 有代理 elem.addEventListener(type, e => { const target = e.target if (target.matches(selector)) { fn.call(target, e) } }) }) }) }, // 取消事件绑定 off: function (type, fn) { return this.forEach(elem => { elem.removeEventListener(type, fn) }) }, // 获取/设置 属性 attr: function (key, val) { if (val == null) { // 获取值 return this[0].getAttribute(key) } else { // 设置值 return this.forEach(elem => { elem.setAttribute(key, val) }) } }, // 添加 class addClass: function(className) { if (!className) { return this } return this.forEach(elem => { let arr if (elem.className) { // 解析当前 className 转换为数组 arr = elem.className.split(/\s/) arr = arr.filter(item => { return !!item.trim() }) // 添加 class if (arr.indexOf(className) < 0) { arr.push(className) } // 修改 elem.class elem.className = arr.join(' ') } else { elem.className = className } }) }, // 删除 class removeClass: function (className) { if (!className) { return this } return this.forEach(elem => { let arr if (elem.className) { // 解析当前 className 转换为数组 arr = elem.className.split(/\s/) arr = arr.filter(item => { item = item.trim() // 删除 class if (!item || item === className) { return false } return true }) // 修改 elem.class elem.className = arr.join(' ') } }) }, // 修改 css css: function (key, val) { const currentStyle = `${key}:${val};` return this.forEach(elem => { const style = (elem.getAttribute('style') || '').trim() let styleArr, resultArr = [] if (style) { // 将 style 按照 ; 拆分为数组 styleArr = style.split(';') styleArr.forEach(item => { // 对每项样式,按照 : 拆分为 key 和 value let arr = item.split(':').map(i => { return i.trim() }) if (arr.length === 2) { resultArr.push(arr[0] + ':' + arr[1]) } }) // 替换或者新增 resultArr = resultArr.map(item => { if (item.indexOf(key) === 0) { return currentStyle } else { return item } }) if (resultArr.indexOf(currentStyle) < 0) { resultArr.push(currentStyle) } // 结果 elem.setAttribute('style', resultArr.join('; ')) } else { // style 无值 elem.setAttribute('style', currentStyle) } }) }, // 显示 show: function () { return this.css('display', 'block') }, // 隐藏 hide: function () { return this.css('display', 'none') }, // 获取子节点 children: function () { const elem = this[0] if (!elem) { return null } return $(elem.children) }, // 获取子节点(包括文本节点) childNodes: function () { const elem = this[0] if (!elem) { return null } return $(elem.childNodes) }, // 增加子节点 append: function($children) { return this.forEach(elem => { $children.forEach(child => { elem.appendChild(child) }) }) }, // 移除当前节点 remove: function () { return this.forEach(elem => { if (elem.remove) { elem.remove() } else { const parent = elem.parentElement parent && parent.removeChild(elem) } }) }, // 是否包含某个子节点 isContain: function ($child) { const elem = this[0] const child = $child[0] return elem.contains(child) }, // 尺寸数据 getSizeData: function () { const elem = this[0] return elem.getBoundingClientRect() // 可得到 bottom height left right top width 的数据 }, // 封装 nodeName getNodeName: function () { const elem = this[0] return elem.nodeName }, // 从当前元素查找 find: function (selector) { const elem = this[0] return $(elem.querySelectorAll(selector)) }, // 获取当前元素的 text text: function (val) { if (!val) { // 获取 text const elem = this[0] return elem.innerHTML.replace(/<.*?>/g, () => '') } else { // 设置 text return this.forEach(elem => { elem.innerHTML = val }) } }, // 获取 html html: function (value) { const elem = this[0] if (value == null) { return elem.innerHTML } else { elem.innerHTML = value return this } }, // 获取 value val: function () { const elem = this[0] return elem.value.trim() }, // focus focus: function () { return this.forEach(elem => { elem.focus() }) }, // parent parent: function () { const elem = this[0] return $(elem.parentElement) }, // parentUntil 找到符合 selector 的父节点 parentUntil: function (selector, _currentElem) { const results = document.querySelectorAll(selector) const length = results.length if (!length) { // 传入的 selector 无效 return null } const elem = _currentElem || this[0] if (elem.nodeName === 'BODY') { return null } const parent = elem.parentElement let i for (i = 0; i < length; i++) { if (parent === results[i]) { // 找到,并返回 return $(parent) } } // 继续查找 return this.parentUntil(selector, parent) }, // 判断两个 elem 是否相等 equal: function ($elem) { if ($elem.nodeType === 1) { return this[0] === $elem } else { return this[0] === $elem[0] } }, // 将该元素插入到某个元素前面 insertBefore: function (selector) { const $referenceNode = $(selector) const referenceNode = $referenceNode[0] if (!referenceNode) { return this } return this.forEach(elem => { const parent = referenceNode.parentNode parent.insertBefore(elem, referenceNode) }) }, // 将该元素插入到某个元素后面 insertAfter: function (selector) { const $referenceNode = $(selector) const referenceNode = $referenceNode[0] if (!referenceNode) { return this } return this.forEach(elem => { const parent = referenceNode.parentNode if (parent.lastChild === referenceNode) { // 最后一个元素 parent.appendChild(elem) } else { // 不是最后一个元素 parent.insertBefore(elem, referenceNode.nextSibling) } }) } } // new 一个对象 function $(selector) { return new DomElement(selector) } // 解绑所有事件,用于销毁编辑器 $.offAll = function () { eventList.forEach(item => { const elem = item.elem const type = item.type const fn = item.fn // 解绑 elem.removeEventListener(type, fn) }) } export default $