UNPKG

@joyzl/eno

Version:
1,259 lines (1,195 loc) 33.6 kB
// 提供HTML标签元素处理与数据对象之间的互操作支持。 // 用于简化 HTMLElement 与 JS JSON/Object 之间的互操作。 export default { create, append, replace, selects, select, remove, show, hide, toggle, classes, attribute, get, gets, set, sets, bind, entity, element, target, query } // 这个临时标签用于解析HTML字符串 const TEMPLATE = document.createElement("template"); /** * HTML字符串创建标签元素实例 * @example eno.create(html); * @param {String|HTMLElement} html 要创建为标签元素实例的HTML字符串 * @return {HTMLElement|HTMLElement[]|null} 创建的单个或多个标签元素 */ function create(html) { // DocumentFragment // 插入文档即便多个标签也仅触发一次重渲染 // 插入后实例为空集合 // Element.innerHTML if (html) { if (html.trim) { // 创建新元素 TEMPLATE.innerHTML = html; if (TEMPLATE.content.childElementCount == 1) { return TEMPLATE.content.firstElementChild; } else if (TEMPLATE.content.childElementCount > 1) { return Array.from(TEMPLATE.content.children); } } else if (html.tagName) { // 已为元素实例 // 添加到临时集合以便渲染 TEMPLATE.innerHTML = ""; TEMPLATE.appendChild(html); return html; } else if (html instanceof DocumentFragment) { // 已为元素实例 // 添加到临时集合以便渲染 TEMPLATE.innerHTML = ""; TEMPLATE.appendChild(html); return Array.from(TEMPLATE.content.children); } } return null; } /** * 创建并添加标签元素 * @param {HTMLElement} element 父标签元素 * @param {String} selector 选择器字符串 * @param {HTMLElement|String} html 要添加的标签元素实例或HTML字符串 * @return {HTMLElement|HTMLElement[]|null} 创建的单个/多个标签元素/null * @example eno.append(html); //添加到文档尾部 * @example eno.append(element,html); // 添加到指定标签尾部 * @example eno.append(element,selector,html); // 添加到指定标签中匹配选择器的标签尾部 */ function append(element, selector, html) { if (arguments.length == 1) { // append(html); html = create(element); element = document.body; } else if (arguments.length == 2) { // append(element,selector); 无效 // append(element,html); // append(selector,html); element = select(element); html = create(selector); } else if (arguments.length == 3) { // append(element,selector,html) element = select(element, selector); html = create(html); } else { return null; } if (element && html) { element.appendChild(TEMPLATE.content); return html; } return null; } /** * 创建并替换为标签元素 * @param {HTMLElement} element 目标标签元素 * @param {String} selector 选择器字符串 * @param {HTMLElement|String} html 用于替换的标签元素或HTML字符串 * @return {HTMLElement|HTMLElement[]|null} 创建的单个/多个标签元素/null * @example eno.replace(element,html); * @example eno.replace(element,selector,html); */ function replace(element, selector, html) { if (arguments.length == 2) { // replace(element,html); // replace(selector,html); element = select(element); html = create(selector); } else if (arguments.length == 3) { // replace(element,selector,html); element = select(element, selector); html = create(html); } else { return null; } if (element && html) { // 转移样式属性,如果有 if (element.classList && element.classList.length) { if (Array.isArray(html)) { for (let i = 0; i < html.length; i++) { // TODO 需要测试验证 html[i].classList.add(element.classList); if (element.style.cssText) { html[i].style.cssText += element.style.cssText; } } } else { // TODO 需要测试验证 html.classList.add(element.classList); if (element.style.cssText) { html.style.cssText += element.style.cssText; } } } element.replaceWith(TEMPLATE.content); return html; } return null; } /** * 在指定范围内/整个文档查找标签元素 * @example eno.select(selector); * @example eno.select(element,selector); * @param {HTMLElement} element 要在其中查找的父标签元素 * @param {String} selector 选择器字符串 * @return {HTMLElement|null} 匹配的单个标签元素,如果匹配多个仅返回第一个 */ function select(element, selector) { if (arguments.length == 1) { // 仅指定1个参数 // select(element); // select(selector); if (element.tagName) { return element; } else if (element.trim) { return document.querySelector(element); } else if (element.length) { // NodeList,HTMLCollection return element[0]; } } else if (arguments.length == 2) { // 指定了2个参数 // select(element, selector); if (element.tagName) { return element.querySelector(selector); } else if (element.trim) { element = document.querySelector(element); if (element) { return element.querySelector(selector); } } // 不支持element参数为数组或集合 // 应用场景极少且让程序难以理解 } return null; } /** * 在指定范围内/整个文档查找标签元素 * @example eno.selects(selector); * @example eno.selects(element,selector); * @param {HTMLElement} element 要在其中查找的父标签元素 * @param {String} selector 选择器字符串 * @return {HTMLElement[]|null} 匹配的多个标签元素数组,仅匹配一个也返回数组 */ function selects(element, selector) { if (arguments.length == 1) { // 仅指定1个参数 // selects(selector); if (element.tagName) { // 仅提供元素参数 return [element]; } else if (element.trim) { // 仅提供字符串参数 element = document.querySelectorAll(element); if (element.length > 0) { return Array.from(element); } } else if (element.length) { // NodeList,HTMLCollection return Array.from(element); } } else if (arguments.length == 2) { // 指定了2个参数 // select(element, selector); if (element.tagName) { element = element.querySelectorAll(selector); if (element.length > 0) { return Array.from(element); } } else if (element.trim) { element = document.querySelector(element); if (element) { element = element.querySelectorAll(selector); if (element.length > 0) { return Array.from(element); } } } // 不支持element参数为数组或集合 // 应用场景极少且让程序难以理解 } return null; } /** * 从文档移除标签元素 * @param {HTMLElement} element 要在其中查找的父标签元素 * @param {String} selector 选择器字符串 * @return {HTMLElement[]|null} 移除的标签元素数组 */ function remove(element, selector) { if (arguments.length == 1) { element = selects(element); } else if (arguments.length == 2) { element = selects(element, selector); } else { return; } if (element && element.length) { for (let i = 0; i < element.length; i++) { element[i].remove(); } } return element; } /** * 隐藏标签元素 * @param {HTMLElement} element 要在其中查找的父标签元素 * @param {String} selector 选择器字符串 * @return {HTMLElement[]|null} 隐藏的标签元素数组 */ function hide(element, selector) { if (arguments.length == 1) { element = selects(element); } else if (arguments.length == 2) { element = selects(element, selector); } else { return; } if (element && element.length) { for (let i = 0; i < element.length; i++) { hideElement(element[i]); } } return element; } /** * 显示标签元素 * @param {HTMLElement} element 要在其中查找的父标签元素 * @param {String} selector 选择器字符串 * @return {HTMLElement[]|null} 显示的标签元素数组 */ function show(element, selector) { if (arguments.length == 1) { element = selects(element); } else if (arguments.length == 2) { element = selects(element, selector); } else { return; } if (element && element.length) { for (let i = 0; i < element.length; i++) { showElement(element[i]); } } return element; } function hideElement(element) { if (element.hidden) { if (element.__ENO_DISPLAY !== undefined) { return; } } else { element.hidden = true; } // display:flex 导致 hidden 属性失效而不会隐藏 element.__ENO_DISPLAY = element.style.display; element.style.display = "none"; } function showElement(element) { if (element.hidden) { element.hidden = false; if (element.__ENO_DISPLAY !== undefined) { element.style.display = element.__ENO_DISPLAY; } } } /** * 切换指定元素显示,同级其余元素隐藏; * 如果指定样式类名,则当前元素添加样式类,其余元素移除样式类,样式类名区分大小写 * @param {HTMLElement} element 要在其中查找的父标签元素 * @param {String} selector 选择器字符串 * @param {String} applyClass 添加类名称,必须同时提供otherClass参数,可指定""/null表示无具体类名 * @param {String} otherClass 移除类名称,必须同时提供applyClass参数,可指定""/null表示无具体类名 * @return {HTMLElement|HTMLElement[]|null} 显示的单个/多个标签元素 */ function toggle(element, selector, applyClass, otherClass) { if (arguments.length == 1) { // toggle(element) element = selects(element); if (element) { toggleElements(element); return element; } } else if (arguments.length == 2) { // toggle(element,selector) // toggle(element,applyClass) 无效 element = selects(element, selector); if (element) { toggleElements(element); return element; } } else if (arguments.length == 3) { // toggle(element,selector,applyClass) 无效 // toggle(element,applyClass,otherClass) element = selects(element); if (element) { toggleClasses(element, selector, applyClass); return element; } } else if (arguments.length == 4) { // toggle(element,selector,applyClass,otherClass) element = selects(element, selector); if (element) { toggleClasses(element, applyClass, otherClass); return element; } } return null; } function toggleElement(element) { const parent = element.parentElement; for (let i = 0; i < parent.children.length; i++) { if (element !== parent.children[i]) { hideElement(parent.children[i]); } } showElement(element); } function toggleElements(elements) { // 这些元素可能不在同级 let element, parent, i; for (let e = 0; e < elements.length; e++) { element = elements[e]; if (element.parentElement !== parent) { parent = element.parentElement; for (i = 0; i < parent.children.length; i++) { if (element !== parent.children[i]) { hideElement(parent.children[i]); } } } showElement(element); } } function toggleClass(element, apply, other) { // 移除同级其它元素样式名 const parent = element.parentElement; for (let i = 0; i < parent.children.length; i++) { if (element !== parent.children[i]) { parent.children[i].classList.remove(apply); parent.children[i].classList.add(other); } } // 添加当前元素样式名 element.classList.remove(other); element.classList.add(apply); } function toggleClasses(elements, apply, other) { // 这些元素可能不在同级 let element, parent, i; for (let e = 0; e < elements.length; e++) { element = elements[e]; if (element.parentElement !== parent) { // 移除同级其它元素样式名 parent = element.parentElement; for (i = 0; i < parent.children.length; i++) { if (element !== parent.children[i]) { parent.children[i].classList.remove(apply); parent.children[i].classList.add(other); } } } // 添加当前元素样式名 element.classList.remove(other); element.classList.add(apply); } } /** * 添加和移除样式名 * @param {HTMLElement} element 要在其中查找的父标签元素 * @param {String} selector 选择器字符串 * @param {String} apply 要添加的样式名 * @param {String} remove 要移除的样式名 * @return {HTMLElement[]} 添加或移除样式名的标签元素数组 * @example classes(element,apply) * @example classes(element,selector,apply) * @example classes(element,selector,apply,remove) */ function classes(element, selector, apply, remove) { if (arguments.length == 1) { // classes(element) 无效 return null; } else if (arguments.length == 2) { // classes(element,selector) 无效 // classes(element,apply) element = selects(element); apply = selector; } else if (arguments.length == 3) { // classes(element,selector,apply) // classes(element,apply,remove) 无效(无法辨别) element = selects(element, selector); } else if (arguments.length == 4) { // classes(element,selector,apply,remove) element = selects(element, selector); } if (element) { if (apply) { if (remove) { for (let e = 0; e < element.length; e++) { element[e].classList.remove(remove); element[e].classList.add(apply); } } else { for (let e = 0; e < element.length; e++) { element[e].classList.add(apply); } } } else { if (remove) { for (let e = 0; e < element.length; e++) { element[e].classList.remove(remove); } } } return element; } return null; } /** * 设置标签元素属性值 * @param {HTMLElement} element 要在其中查找的父标签元素 * @param {String} selector 选择器字符串 * @param {String} name 属性名(必须指定) * @param {String} value 属性值(必须指定) */ function attribute(element, selector, name, value) { if (arguments.length == 1) { // attribute(element) 无效 return null; } else if (arguments.length == 2) { // attribute(element,selector) 无效 return null; } else if (arguments.length == 3) { // classes(element,selector,name) 无效 // classes(element,name,value) element = selects(element); value = name; name = selector; } else if (arguments.length == 4) { // classes(element,selector,name,value) element = selects(element, selector); } if (element) { value = value ? value : ""; for (let e = 0; e < element.length; e++) { element[e].setAttribute(name, value); } return element; } // 移除属性值使用情形极少 return null; } // 默认转换函数 function defaultConverter(element, entity, name) { // return 0; 使用返回值 // return null; 不执行默认行为 // return; undefined 未处理执行默认行为 } /** * 从指定元素获取值以实体对象返回 * @param {HTMLElement} element 要在其中查找的父标签元素 * @param {String} selector 选择器字符串 * @param {Function} converter 转换方法 * @return {Object} 包含数据的实体对象实例 */ function get(element, selector, converter = defaultConverter) { if (arguments.length == 1) { // get(element) // get(selector) element = select(element); } else if (arguments.length == 2) { // get(element,selector) // get(element,converter) if (selector instanceof Function) { element = select(element); converter = selector; } else { element = select(element, selector); } } else if (arguments.length == 3) { // get(element,selector,converter) element = select(element, selector); } else { return null; } if (element) { let entity = {}; getEntity(element, entity, converter); return entity; } return null; } /** * 从指定元素获取值以JSON对象返回 * @param {HTMLElement} element 要在其中查找的父标签元素 * @param {String} selector 选择器字符串 * @param {Function} converter 转换方法 * @return {Object[]} 包含数据的实体对象实例 */ function gets(element, selector, converter = defaultConverter) { if (arguments.length == 1) { // gets(element) // gets(selector) element = selects(element); } else if (arguments.length == 2) { // gets(element,selector) // gets(element,converter) if (selector instanceof Function) { element = selects(element); converter = selector; } else { element = selects(element, selector); } } else if (arguments.length == 3) { // gets(element,selector,converter) element = selects(element, selector); } else { return null; } if (element) { let entity, entities = new Array(); for (let i = 0; i < element.length; i++) { entity = {}; getEntity(element[i], entity, converter); entities.push(entity); } return entities; } return null; } /** * 实体对象设置到标签元素显示,以name属性作为标识 * @param {HTMLElement} element 要在其中查找的父标签元素 * @param {String} selector 选择器字符串 * @param {Object} entity 数据实体对象 * @param {Function} converter 数据转换方法 * @return {HTMLElement} 设置或创建的标签元素 */ function set(element, selector, entity, converter = defaultConverter) { // 仅对单个标签元素目标 // 多个标签元素目标难以理解 if (arguments.length == 2) { // set(element,entity) // set(selector,entity) element = select(element); entity = selector; } else if (arguments.length == 3) { // set(element,selector,entity) // set(element,entity,converter) if (entity instanceof Function) { element = select(element); converter = entity; entity = selector; } else { element = select(element, selector); } } else if (arguments.length == 4) { // set(element,selector,entity,converter) element = select(element, selector); } else { return null; } if (element) { // Object -> Element if (Array.isArray(entity)) { entity = entity[0]; } setEntity(element, entity, converter); element.__ENO_ENTITY = entity; return element; } } /** * 实体对象设置到标签元素显示,以name属性作为标识 * @param {HTMLElement} element 要在其中查找的父标签元素 * @param {String} selector 选择器字符串 * @param {Object} entity 数据实体对象 * @param {Function} converter 数据转换方法 * @return {HTMLElement} 设置或创建的标签元素 */ function sets(element, selector, entity, converter = defaultConverter) { // 仅对单个标签元素目标 // 多个标签元素目标难以理解 // entity为数组时返回数组 if (arguments.length == 2) { // sets(element,entity) // sets(selector,entity) element = select(element); entity = selector; } else if (arguments.length == 3) { // sets(element,selector,entity) // sets(element,entity,converter) if (entity instanceof Function) { element = select(element); converter = entity; entity = selector; } else { element = select(element, selector); } } else if (arguments.length == 4) { // sets(element,selector,entity,converter) element = select(element, selector); } else { return null; } if (element) { // Object[] -> Element.children let i = 0; // 利用ENO_SET缓存模板并判定是否首次 if (element.__ENO_SETS === undefined) { if (element.childElementCount) { element.__ENO_SETS = {}; // 查找模块和位置 // before...<template>...after // 只有<template>模板具有content属性 // 记录模板前后已有标签元素数量 // before数量包括模板本身 for (i = 0; i < element.childElementCount; i++) { if (element.children[i].content) { element.__ENO_SETS.fragment = element.children[i].content; element.__ENO_SETS.before = ++i; element.__ENO_SETS.after = element.childElementCount - i; break; } } // 未定义模板<template> // 子元素视为模板 if (element.__ENO_SETS.fragment === undefined) { element.__ENO_SETS.fragment = new DocumentFragment(); while (element.childElementCount > 0) { element.__ENO_SETS.fragment.appendChild(element.children[0]); } element.__ENO_SETS.before = 0; element.__ENO_SETS.after = 0; } } else { // 没有可用模板 return null; } } if (entity) { if (!Array.isArray(entity)) { entity = [entity]; } let node, n; // 构造填充元素 for (i = 0; i < entity.length; i++) { if (element.__ENO_SETS.before + i < element.childElementCount - element.__ENO_SETS.after) { // 重用已有元素 for (n = 0; n < element.__ENO_SETS.fragment.childElementCount; n++) { node = element.children[element.__ENO_SETS.before + i + n]; setEntity(node, entity[i], converter); node.__ENO_ENTITY = entity[i]; } } else { // 克隆新的元素(DocumentFragment) node = element.__ENO_SETS.fragment.cloneNode(true); for (n = 0; n < node.childElementCount; n++) { setEntity(node.children[n], entity[i], converter); node.children[n].__ENO_ENTITY = entity[i]; } element.insertBefore(node, element.children[element.__ENO_SETS.before + i * node.childElementCount]); } } // 移除多余元素 n = i * element.__ENO_SETS.fragment.childElementCount; i = element.__ENO_SETS.before + element.__ENO_SETS.after; while (element.childElementCount > i + n) { element.children[element.__ENO_SETS.before + n].remove(); } } else { // null / undefine -> Element i = element.__ENO_SETS.before + element.__ENO_SETS.after; while (element.childElementCount > i) { element.children[element.childElementCount - element.__ENO_SETS.after - 1].remove(); } } return element; } } /** * 获取实体从标签元素 * <input name="AAA" value="123"/> * <span name="AAA">123</span> * <img name="AAA" src="123"/> * <i case="AAA"></i> */ function getEntity(element, entity, converter) { let name = element.getAttribute("name"); if (name && name.length) { let value = converter(element, entity, name); if (value !== undefined) { if (value !== null) { // 返回有效值 setValue(entity, name, value); } // 阻止默认处理 return; } // 默认处理 if (element.type) { // 所有控件具有type属性 // 所有控件具有disabled属性 // <select> <textarea> 没有checked属性,其余均有 if (element.disabled) { // <fieldset> 禁用后其内部控件全部无效,但内部控件的disabled不一定为true // 阻止禁用控件的子元素处理 return; } else { if (element.type === "number" || element.type === "range") { if (!isNaN(element.valueAsNumber)) { setValue(entity, name, element.valueAsNumber); } } else if (element.type === "checkbox" || element.type === "radio") { if (element.checked) { setValue(entity, name, element.value); } } else { if (element.value) { setValue(entity, name, element.value); } } } } else if (element.src) { // img setValue(entity, name, element.src); } else { setValue(entity, name, element.innerText); } } else { if (element.disabled) { // 阻止禁用标签元素的子元素处理 return; } } if (element.childElementCount) { for (let i = 0; i < element.children.length; i++) { getEntity(element.children[i], entity, converter); } } } /** * 设置实体到标签元素 * <input name="AAA" value="123"/> * <span name="AAA">123</span> * <img name="AAA" src="123"/> * <i case="AAA"></i> */ function setEntity(element, entity, converter) { let name = element.getAttribute("name"); if (name && name.length) { let value = converter(element, entity, name); if (value === undefined) { // 无未处理,执行默认处理 value = text(getValue(entity, name)); } else if (value === null) { // 阻断默认处理行为 return; } else { // 返回有效值,执行默认处理 value = text(value); } // 默认处理 if (element.type) { // 所有控件具有type属性 // 设置时不考虑disabled状态 if (element.type === "checkbox" || element.type === "radio") { // Radio / Check element.checked = element.value == value; } else if (element.type === "fieldset") { //忽略 } else { // OTHER element.value = value; } } else if (element.src !== undefined) { // <img /> if (element.__ENO_SRC === undefined) { // 记录默认图像 element.__ENO_SRC = element.src; } element.src = value; if (element.src.length == 0) { element.src = element.__ENO_SRC; } } else { if (element.__ENO_TEXT === undefined) { // 原始内容作为默认值 element.__ENO_TEXT = element.innerText; // 是否已有title // 如果用于已设置title则不在自动设置 element.__ENO_TITLE = element.title ? false : true; } element.innerText = value; if (element.innerText.length == 0) { element.innerText = element.__ENO_TEXT; } if (element.__ENO_TITLE) { // 设置title实现文本提示 element.title = element.innerText; } } } name = element.getAttribute("case"); if (name && name.length) { if (converter(element, entity, name)) { // 继续处理 } else { return; } } if (element.childElementCount) { for (let i = 0; i < element.children.length; i++) { setEntity(element.children[i], entity, converter); } } } /** * 根据名称获取实体对象值 * @param {Object} entity 要获取值的实体对象 * @param {Object} name 字段名称 "Device.Type.Text" 区分大小写 * @returns {Object} 获取的值 */ function getValue(entity, name) { name = name.split("."); for (let i = 0; i < name.length; i++) { if (entity) { if (Array.isArray(entity)) { const items = new Array(); for (let a = 0; a < entity.length; a++) { if (entity[a]) { items.push(entity[a][name[i]]); } } entity = items; } else { entity = entity[name[i]]; } } else { break; } } return entity; } /** * 根据名称设置实体对象值 * @param {Object} entity 要设置值的实体对象 * @param {Object} name 字段名称 "Device.Type.Text" 区分大小写 * @param {Object} value 要设置的值 */ function setValue(entity, name, value) { name = name.split("."); let i = 0; for (; i < name.length - 1; i++) { if (entity[name[i]]) { entity = entity[name[i]]; } else { entity = entity[name[i]] = {}; } } // 点语法最后的名称 name = name[i]; // 相同name多次出现应数组化 if (entity[name] === undefined) { entity[name] = value; } else { if (Array.isArray(entity[name])) { entity[name].push(value); } else { entity[name] = [entity[name], value]; } } } /** * 转换为字符串值 * @param {any} value */ function text(value) { if (Array.isArray(value)) { // 数组值合并(逗号分割) return value.join(','); } if (value !== undefined && value !== null) { return value.toString(); } return ""; } /** * 绑定事件 * @param {Element} element 标签元素 * @param {String} selector 筛选字符 * @param {String} eventName 事件名称 * @param {Function} listener 事件处理 * @example bind(element,eventName,listener); * @example bind(element,selector,eventName,listener); * @return {Element} 绑定事件的标签元素 */ function bind(element, selector, eventName, listener) { if (arguments.length == 3) { // bind(element,eventName,listener); // bind(selector,eventName,listener); element = selects(element); listener = eventName; eventName = selector; } else if (arguments.length == 4) { // bind(element,selector,eventName,listener); element = selects(element, selector); } else { return null; } if (element && element.length) { for (let i = 0; i < element.length; i++) { element[i].addEventListener(eventName, listener); } return element; } return null; } /** * 根据事件或标签元素获取由eno.sets()对应的实体对象 * @param {Event|HTMLElement} e 事件或标签元素 * @param {String} selector 选择器字符串 * @return {Object} 标签元素对应的实体对象 * @example entity(event); * @example entity(element); * @example entity(element,selector); */ function entity(e, selector) { if (arguments.length == 1) { // entity(event); if (e.target) { e = e.target; } else if (e.srcElement) { e = e.srcElement; } else { e = select(e); } } else if (arguments.length == 2) { // entity(element,selector); e = select(e, selector); } else { return null; } while (e) { if (e.__ENO_ENTITY) { return e.__ENO_ENTITY; } else { e = e.parentElement; } } return null; } /** * 根据事件或标签元素获取由eno.sets()对应标签元素 * @param {Event|HTMLElement} e 事件或标签元素 * @return {HTMLElement} 实体对象对应的标签元素 * @example element(event); * @example element(element); */ function element(e) { if (e) { if (e.target) { e = e.target; } else if (e.srcElement) { e = e.srcElement; } else { e = select(e); } while (e) { if (e.__ENO_ENTITY) { return e; } else { e = e.parentElement; } } } return null; } /** * 获取具有指定属性的事件目标 * @param {Event} event * @param {String} name * @param {String} value * @example target(event); 返回事件源标签元素 * @example target(event, name); 返回事件目标指定属性的标签元素 * @example target(event, name, value); 返回事件目标指定属性和值的标签元素 * @example target(event, name, null); 返回事件目标指定属性标签元素的属性值 */ function target(event, name, value) { if (arguments.length == 1) { // target(event); return event.target || event.srcElement; } else if (arguments.length == 2) { // target(event, name); let element = event.target || event.srcElement; while (element && element !== event.currentTarget) { if (element.hasAttribute(name)) { return element; } element = element.parentElement; } } else if (arguments.length == 3) { // target(event, name, value); let element = event.target || event.srcElement; if (value) { while (element && element !== event.currentTarget) { if (element.getAttribute(name) == value) { return element; } element = element.parentElement; } } else { while (element && element !== event.currentTarget) { if (element.hasAttribute(name)) { return element.getAttribute(name); } element = element.parentElement; } } } return null; } /** * 获取 URL 中的 Query String 指定名称的参数值或包含所有参数的实体对象 * @param {String} url URL * @param {String} name 参数名 * @return {String} 参数值 * @example eno.query(url); * @example eno.query(name); * @example eno.query(url,name); */ function query(url, name) { if (arguments.length == 0) { // query() // window.location.search 返回从问号?开始的URL查询部分 url = window.location.search; } else if (arguments.length == 1) { // query(url) // query(name) if (url.startsWith("http://") || url.startsWith("https://")) { let index = url.indexOf("?"); if (index > 0) { url = url.substring(index); } else { return null; } } else { name = url; // window.location.search 返回从问号?开始的URL查询部分 url = window.location.search; } } else if (arguments.length == 2) { // query(url, name) let index = url.indexOf("?"); if (index > 0) { url = url.substring(index); } else { return null; } } else { return null; } if (url) { if (name) { // 查找指定参数值 let start = url.indexOf(name); if (start >= 0) { start += name.length; if (url.charAt(start) == '=') { start++; let end = url.indexOf('&', start); if (end >= 0) { return url.substring(start, end); } return url.substring(start); } } } else { // 获取所有参数值 // ?name1=value1&name2=value2 let start = 1; let index = 1; let name, parameter = {}; while (index >= 0 && index < url.length) { start = url.indexOf("=", index); if (start >= 0) { name = url.substring(start, index); start = ++index; index = url.indexOf("&", index); if (index >= 0) { parameter[name] = url.substring(start, index); start = ++index; } else { parameter[name] = url.substring(start); break; } } else { break; } } return parameter; } } return null; }