quiz
quiz copied to clipboard
DOM基础测试29
本期DOM小测题目如下:
大家提交回答的时候,注意缩进距离,起始位置从左边缘开始;另外,github自带代码高亮,所以请使用下面示意的格式。
```js // 你的JS代码写在这里 ```
if (!Element.prototype.matches) {
Element.prototype.matches = Element.prototype.msMatchesSelector ||
Element.prototype.webkitMatchesSelector;
}
if (!Element.prototype.closest) {
Element.prototype.closest = function(s) {
var el = this;
do {
if (el.matches(s)) return el;
el = el.parentElement || el.parentNode;
} while (el !== null && el.nodeType === 1);
return null;
};
}
没听过这个API,搜了一下MDN 没想到就有答案了...
if (!Element.prototype.matches) {
Element.prototype.matches = Element.prototype.msMatchesSelector ||
Element.prototype.webkitMatchesSelector;
}
Element.prototype.closestAll = function(s) {
var el = this;
var closests = [];
do {
if (el.matches(s)) {
closests.push(el)
}
el = el.parentElement || el.parentNode;
} while (el !== null && el.nodeType === 1);
return closests.length > 0 ? closests : null;
};
//matches的polyfill
if (!Element.prototype.matches) {
Element.prototype.matches =
Element.prototype.matchesSelector ||
Element.prototype.mozMatchesSelector ||
Element.prototype.msMatchesSelector ||
Element.prototype.oMatchesSelector ||
Element.prototype.webkitMatchesSelector ||
function(s) {
var matches = (this.document || this.ownerDocument).querySelectorAll(s),
i = matches.length;
while (--i >= 0 && matches.item(i) !== this) {}
return i > -1;
};
}
//第一题
if (!Element.prototype.closest){
Element.prototype.closest = function(s) {
var el = this;
if (!((el.document || el.ownerDocument.documentElement)).contains(el)){
return null;
}
do {
if (el.matches(s)) return el;
el = el.parentElement;
} while (el !== null);
return null;
};
}
//第二题
if (!Element.prototype.closestAll){
Element.prototype.closestAll = function(s) {
var el = this,
closests = [];
if (!((el.document || el.ownerDocument.documentElement)).contains(el)){
return closests;
}
do {
if (el.matches(s)){
closests.push(el);
};
el = el.parentElement;
} while (el !== null);
return closests;
};
}
//Element.matches
if (!Element.prototype.matches) {
Element.prototype.matches =
Element.prototype.matchesSelector ||
Element.prototype.mozMatchesSelector ||
Element.prototype.msMatchesSelector ||
Element.prototype.oMatchesSelector ||
Element.prototype.webkitMatchesSelector
}
//Element.closest
if (!Element.prototype.closest) {
Element.prototype.closest = function(selector) {
var element = this;
while (element && element.nodeType === 1) {
if (element.matches(selector)) {
return element;
}
element = element.parentNode;
}
return null;
};
}
//Element.closestAll
Element.prototype.closestAll = function (selector) {
var element = this;
var nodeList = [];
while (element && element.nodeType === 1) {
if (element.matches(selector)) {
nodeList.push(element);
}
element = element.parentNode;
}
return nodeList;
};
要不是这个测试,都不知道还有这方法
Element.prototype.myClosest = function myClosest(value){
if (value === '') {
return null;
}
if (this.closest) {
return this.closest(value);
}
let nodeAry = document.querySelectorAll(value),
nodeLength = nodeAry.length,
lastCloseNode = null;
if (nodeLength <= 0) {
return null;
}
if (nodeLength === 1 && nodeAry[0] === this) {
return this;
}
for (let i = 0; i < nodeLength; i += 1) {
if (nodeAry[i].contains(this)) {
lastCloseNode = nodeAry[i];
}
}
return lastCloseNode;
};
Element.prototype.closestAll = function closestAll(value){
if (value === '') {
return [];
}
let nodeAry = document.querySelectorAll(value),
nodeLength = nodeAry.length,
allCloseNode = [];
if (nodeLength <= 0) {
return [];
}
for (let i = 0; i < nodeLength; i += 1) {
if (nodeAry[i].contains(this) || nodeAry[i] === this) {
allCloseNode.push(nodeAry[i]);
}
}
return allCloseNode;
};
// 题1
if (!Element.prototype.closest) {
if(!Element.prototype.matches){
Element.prototype.matches = Element.prototype.msMatchesSelector
}
Element.prototype.closest = function (selector) {
let el = this
do {
if (el.matches(selector)) return el;
el = el.parentElement
} while (el && el.nodeType === Node.ELEMENT_NODE)
return null
}
}
// 题二
// zhangxinxu: 有bug,本题无分
Element.prototype.closestAll = function (selector) {
let NodeLists = []
let el = this
let selected = null
do {
selected = Element.prototype.closest.call(el, selector)
selected && NodeLists.push(selected) && (el = el.parentElement)
} while (selected && el && el.nodeType === Node.ELEMENT_NODE)
return NodeLists
}
;(function() {
if (!Element.prototype.matches) {
Element.prototype.matches = Element.prototype.msMatchesSelector || Element.prototype.webkitMatchesSelector
}
if (!Element.prototype.closest) {
Element.prototype.closest = function(selector) {
const el = this
let current = this
if (!selector || el.nodeType !== 1) return null
if (current.matches(selector)) return current
while (current.parentElement || current.parentNode) {
current = current.parentElement || current.parentNode
if (current.matches(selector)) return current
}
return null
}
}
// zhangxinxu: 没对current做合法性判断,导致无匹配选择器时候出错,本题无分
Element.prototype.closestAll = function(selector) {
const el = this
let current = this
let closestList = []
if (!selector || el.nodeType !== 1) return closestList
if (current.matches(selector)) closestList.push(current)
while (current.parentElement || current.parentNode) {
current = current.parentElement || current.parentNode
if (current.matches(selector)) closestList.push(current)
}
return closestList
}
})()
matches
部分 两个都需要
// Polyfill for Element.prototype.matches
if (!Element.prototype.matches) {
var ep = Element.prototype;
ep.matches = ep.msMatchesSelector || ep.webkitMatchesSelector || ep.mozMatchesSelector || ep.oMatchesSelector;
if (!ep.matches) {
ep.matches = function () {
throw new Error('浏览器实在太老,该换代了!!!');
};
}
ep = null;
}
1. Polyfill for Element.prototype.closest
if (!window.Element.prototype.closest) {
window.Element.prototype.closest = function (selector) {
if (selector === void(0)) {
throw new TypeError("Failed to execute 'closest' on 'Element': 1 argument required, but only 0 present.");
}
if (selector + '' !== selector) {
throw new TypeError("Failed to execute 'closest' on 'Element': the argument must be string.");
}
var el = this;
do {
if (el.matches(selector)) {
return el;
}
el = el.parentElement || el.parentNode;
} while (el !== null && el.nodeType === Node.ELEMENT_NODE)
return null;
}
}
2. Polyfill for Element.prototype.closestAll
if (!window.Element.prototype.closestAll) {
window.Element.prototype.closestAll = function (selector) {
if (selector === void(0)) {
throw new TypeError("Failed to execute 'closest' on 'Element': 1 argument required, but only 0 present.");
}
if (selector + '' !== selector) {
throw new TypeError("Failed to execute 'closest' on 'Element': the argument must be string");
}
var el = this;
var arr = [];
do {
if (el.matches(selector)) {
arr.push(el);
}
el = el.parentElement || el.parentNode;
} while (el !== null && el.nodeType === Node.ELEMENT_NODE)
return arr;
}
}
(function(){
//Element.matches
if(!Element.prototype.matches){
Element.prototype.matches =
Element.prototype.matchesSelector ||
Element.prototype.msMatchesSelector ||
Element.prototype.webkitMatchesSelector ||
Element.prototype.oMatchesSelector ||
Element.prototype.mozMatchesSelector;
}
//Element.closest
if(!Element.prototype.closest){
Element.prototype.closest = function(selector){
var el = this;
if(!document.documentElement.contains(el)){
return null;
}
do{
if(el.matches(selector)) return el;
el = el.parentElement;
}while(el != null)
return null;
}
}
//Element.closestAll
Element.prototype.closestAll = function(selector){
var el = this;
var closestArr = [];
do{
if(el.matches(selector)){
closestArr.push(el)
}
el = el.parentElement;
}while(el != null);
return closestArr;
}
})()
// 1
if(!Element.prototype.closest){
Element.prototype.closest = function (selector) {
if (!arguments.length) {
throw new Error("Failed to execute 'closest' on 'Element': 1 argument required, but only 0 present.")
return
}
var el = this
while (el && el.ndoeType === 1) {
el = el.parentNode || el.parentElement
if (el.matches(selector)) {
return el
}
}
return null
}
}
// 2
// zhangxinxu: 有非常严重的bug,会死循环,本题无分
Element.prototype.closestAll = function (selector) {
var el = this,
closestEls = [];
while (el) {
el = el.closest(selector)
if (el)
closestEls.push(el)
}
return closestEls
}
ie9都支持 matches了, 不知道为啥上面很多还要写一个matches。
if (!Element.prototype.closest) {
Element.prototype.closest = function (s) {
var el = this;
if (!document.documentElement.contains(el)) return null;
do {
if (el.matches(s)) return el;
el = el.parentNode;
} while (el !== null);
return null;
}
}
Element.prototype.closestAll = function (s) {
var el = this,
resultArr = [];
if (!document.documentElement.contains(el)) return null;
while(el.nodeType === 1) {
if (el.matches(s)) resultArr.push(el);
el = el.parentNode;
}
return resultArr;
};
if (!Element.prototype.closest){
Element.prototype.closest = function (selector) {
if (!(this instanceof HTMLElement)) return null
var now = this.parentElement
while(now !== null ){
if(now.matches(selector) && now.nodeType === Node.ELEMENT_NODE){
return now
}
now = now.parentElement
}
return null
}
}
Element.prototype.closestAll = function (selector) {
if (!(this instanceof HTMLElement)) return null
var now = this.parentElement, result = []
while(now !== null ){
if(now.matches(selector) && now.nodeType === Node.ELEMENT_NODE) {
result.push(now)
}
now = now.parentElement
}
return result
}
if (!Element.prototype.matches) {
Element.prototype.matches = Element.prototype.msMatchesSelector || Element.prototype.webkitMatchesSelector;
}
/*第一题*/
if (!Element.prototype.closest) {
Element.prototype.closest = function (s) {
var el = this;
do {
if (el.matches(s)) return el;
el = el.parentElement;
} while (el !== null);
return null;
}
}
/*第二题*/
Element.prototype.closestAll = function (s) {
var el = this;
var output = [];
do {
if (el.matches(s)) {
output.push(el);
};
el = el.parentElement;
} while (el !== null);
return output.length === 0 ? null : output;
}
(function() {
// closest
if (!Element.prototype.closest) {
Element.prototype.closest = function(selector) {
var nodeList = document.querySelectorAll(selector);
var targetElement;
var flag = false;
var findTarget = function(ele) {
if (nodeList.length > 0) {
for (var i = 0; i < nodeList.length; i++) {
if (ele == nodeList[i]) {
targetElement = ele;
flag = true;
}
}
if (!flag){
findTarget(ele.parentElement);
}
} else { // 没有匹配的元素
return null;
}
}
findTarget(this);
return targetElement;
}
}
// closestAll 第二题我理解的是获取第一题中匹配元素的所有祖先元素
Element.prototype.closestAll = function(selector) {
var _this = this.closest(selector); // 获取到当前匹配元素
// 查找匹配元素的所有祖先元素
var parentElements = [];
var findParent = function(ele) {
if (ele.parentElement) {
parentElements.push(ele.parentElement);
findParent(ele.parentElement);
}
}
findParent(_this);
return parentElements;
}
// closestAll 如果第二题是返回所有匹配元素的话
Element.prototype.closestAll = function(selector) {
return document.querySelectorAll(selector);
}
})();
if (!Element.prototype.matches) {
Element.prototype.matches = Element.prototype.msMatchesSelector ||
Element.prototype.webkitMatchesSelector;
};
if (!Element.prototype.closest) {
Element.prototype.closest = function(selector) {
let element = this;
if (typeof selector !== 'string') {
return null;
};
if (!document.querySelector(selector)) {
return null;
};
while (element) {
if (element.matches(selector)) {
return element;
}
element = element.parentElement;
};
return null;
};
}
Element.prototype.closestAll = function(selector) {
let element = this;
if (typeof selector !== 'string') {
return [];
}
if (!document.querySelectorAll(selector).length) {
return [];
}
let closestParents = [];
while (element) {
if (element.matches(selector)) {
closestParents.push(element);
}
element = element.parentElement;
}
return closestParents;
}
if (!Element.prototype.matches)
Element.prototype.matches = Element.prototype.msMatchesSelector ||
Element.prototype.webkitMatchesSelector
if (!Element.prototype.closest)
Element.prototype.closest = function (s) {
var el = document.documentElement.contains(this)?this:null
while (el && el.nodeType===1 && !el.matches(s))
el = el.parentElement || el.parentNode
return el
}
Element.prototype.closestAll = function (s) {
var el = document.documentElement.contains(this)?this:null
for(var closests = []; el&&el.nodeType===1; el=el.parentElement||el.parentNode)
el.matches(s) && closests.push(el)
return closests.length>0 ? closests : null
}
特地看了看 Difference between DOM parentNode and parentElement - stackoverflow
In Internet Explorer, parentElement
is undefined for SVG elements, whereas parentNode
is defined.
然后我手动测了下继承关系:
- EventTarget
- Node(chrome 把 parentElement 放这)
- Element
- SVGElement
- HTMLElement(IE 把 parentElement 放这)
- Element
- Node(chrome 把 parentElement 放这)
Element.prototype.closest = function(selector) {
let nodeList = [].slice.call(this.ownerDocument.querySelectorAll(selector));
let firstChildren = [].slice.call(this.ownerDocument.childNodes);
if (nodeList.length === 0) {
return null;
} else {
let ele = this;
while (nodeList.indexOf(ele) < 0 && firstChildren.indexOf(ele) < 0) {
ele = ele.parentElement;
}
return nodeList.indexOf(ele) < 0 ? null : ele;
}
}
Element.prototype.closestAll = function(selector) {
let nodeList = [].slice.call(this.ownerDocument.querySelectorAll(selector));
let firstChildren = [].slice.call(this.ownerDocument.childNodes);
if (nodeList.length === 0) {
return [];
} else {
let ele = this, result = [];
while (firstChildren.indexOf(ele) < 0) {
if (nodeList.indexOf(ele) >= 0) {
result.push(ele)
}
ele = ele.parentElement;
}
return result;
}
}
表示这个方法没见过,查了mdn文档之后发现matchs也没见过,然后弄懂了。 matchs的作用是判断调用他的dom是否能被这个表达式找到,closest返回第一个满足matchs为true的自身或者自身的祖先元素。既然mdn都有答案了,那就学习一下对于closest和matchs的polyfill的正确答案吧。
1. matchs polyfill
if (!Element.prototype.matches) {
Element.prototype.matches =
Element.prototype.matchesSelector ||
Element.prototype.mozMatchesSelector ||
Element.prototype.msMatchesSelector ||
Element.prototype.oMatchesSelector ||
Element.prototype.webkitMatchesSelector ||
function(s) {
var matches = (this.document || this.ownerDocument).querySelectorAll(s),
i = matches.length;
while (--i >= 0 && matches.item(i) !== this) {}
return i > -1;
};
}
2. closest polyfill
if (!Element.prototype.closest) {
Element.prototype.closest = function(s) {
var el = this;
do {
if (el.matches(s)) return el;
el = el.parentElement || el.parentNode;
} while (el !== null && el.nodeType === 1); // 这里是为了向上遍历的时候排除document节点
return null;
};
}
3. closestAll
Element.prototype.closestAll = function(domString) {
var el = this;
var NodeList = [];
while(el && el.nodeType === 1) {
if (el.matches(domString)) NodeList.push(el);
el = el.parentElement || el.parentNode;
}
return NodeList;
}
(function() {
// matches 的 polyfill
if (!Element.prototype.matches) {
Element.prototype.matches =
Element.prototype.matchesSelector ||
Element.prototype.mozMatchesSelector ||
Element.prototype.msMatchesSelector ||
Element.prototype.oMatchesSelector ||
Element.prototype.webkitMatchesSelector ||
function(s) {
var matches = (this.document || this.ownerDocument).querySelectorAll(s),
i = matches.length;
while (--i >= 0 && matches.item(i) !== this) {}
return i > -1;
};
}
if (!Element.prototype.closest) {
// 第一题
Element.prototype.closest = function (selector) {
let el = this;
while (el && el.nodeType === 1) {
if (el.matches(selector)) {
return el;
}
el = el.parentNode;
}
return null;
}
// 第一题 END
}
if (!Element.prototype.closestAll) {
// 第二题
Element.prototype.closestAll = function (selector) {
let el = this.parentNode;
let nodeList = null;
while (el && el.nodeType === 1) {
if (el.matches(selector)) {
if (!nodeList) {
nodeList = [];
}
nodeList.push(el);
}
el = el.parentNode;
}
return nodeList;
}
// 第二题 END
}
})()
我的回答:用 jQuery 的 closest()
方法。开个玩笑 :laughing:
先说下思路:根据传入的参数,使用 querySelectorAll()
方法找出所有匹配的选择器,再匹配出包含当前元素的 nodeList 列表。
第二题
第一题依赖这个方法,所以它先上
Element.prototype.closestAll = function(targetEl) {
var el = this;
var nodelist;
// 参数校验
if (typeof targetEl !== 'string' || !targetEl.trim()) {
throw Error('\' + targetEl + \' is not a valid selector');
}
nodelist = document.querySelectorAll(targetEl);
// 使用 ES5 的 filter 过滤出包含 el 的元素
return Array.prototype.slice.call(nodelist)
.filter(function(node) {
return node.contains(el)
})
.reverse(); // 反转数组,最近的排前面,依次从近到远
}
第一题
获取
closestAll()
方法返回的第一项即可
// closest polyfill
window.Element && 'closest' in Element.prototype || +function() {
Element.prototype.closest = function(targetEl) {
var result = this.closestAll(targetEl);
return result.length === 0 ? null : result[0];
}
}();
开始工作使用的是jquery的closest方法,通过查询mdn文档得知Element
对象上也存在一个closest
方法,同时官方提供了一个很好的polyfill方法,也算是学习到了。closestAll
也是稍微改造一下也可以实现。
if (!Element.prototype.matches)
Element.prototype.matches = Element.prototype.msMatchesSelector ||
Element.prototype.webkitMatchesSelector;
if (!Element.prototype.closest)
Element.prototype.closest = function(s) {
var el = this;
if (!document.documentElement.contains(el)) return null;
do {
if (el.matches(s)) return el;
el = el.parentElement;
} while (el !== null);
return null;
};
Element.prototype.closestAll = function(s) {
var el = this;
var arr = [];
if (!document.documentElement.contains(el)) return null;
do {
if (el.matches(s)){
arr.push(el);
};
el = el.parentElement;
} while (el !== null);
return (arr.length > 0 ? arr : null);
};
这次混一个参与分就好了,大家写的都大同小异,感觉再写一样的就没啥意思了。我有一种思路,主要是要 做事件的兼容性处理(偷懒没有做),其他的应该没啥问题,仅供参考交流。
if (!Element.prototype.closestAll) {
Element.prototype.closestAll = function (selector) {
const self = this
var path = []
function getPath(e) {
// 通过事件冒泡传播的路径来获取祖先元素
for (let i = 0, length = e.path.length - 2; i < length; i++) {
if(e.path[i].matches(selector)) {
path.push(e.path[i])
}
}
// 移除事件监听
self.removeEventListener('my-closest-all', getPath)
}
// 创建一个 冒泡但是不能取消的事件
var ev = new Event('my-closest-all', { 'bubbles': true, 'cancelable': false })
// 监听这个事件
self.addEventListener('my-closest-all', getPath)
// 派发这个事件
self.dispatchEvent(ev)
return path
}
}
if (!Element.prototype.closest) {
Element.prototype.closest = function (selector) {
const self = this
var path = null
function getPath(e) {
// 通过事件冒泡传播的路径来获取祖先元素
for (let i = 0, length = e.path.length - 2; i < length; i++) {
if(e.path[i].matches(selector)) {
path = e.path[i]
break
}
}
// 移除事件监听
self.removeEventListener('my-closest', getPath)
}
// 创建一个 冒泡但是不能取消的事件
var ev = new Event('my-closest', { 'bubbles': true, 'cancelable': false })
// 监听这个事件
self.addEventListener('my-closest', getPath)
// 派发这个事件
self.dispatchEvent(ev)
return path
}
}
先上mdn答案
// MDN提供polyfill
if (!Element.prototype.matches) {
Element.prototype.matches = Element.prototype.msMatchesSelector ||
Element.prototype.webkitMatchesSelector;
}
if (!Element.prototype.closest) {
Element.prototype.closest = function(s) {
var el = this;
if (!document.documentElement.contains(el)) {
return null;
}
do {
if (el.matches(s)) {
return el;
}
el = el.parentElement;
} while (el !== null);
return null;
};
}
接下来自己写的
/**
* 1.closest匹配特定选择器且离当前元素最近的祖先元素
* 2.选择器错误给错误提示
* 3.查询不到返回null
* */
if (!Element.prototype.closest) {
Element.prototype.myClosest = function(select) {
try {
// 全部的选择器元素;
const selectDom = document.querySelectorAll(select);
const selectDomLength = selectDom.length;
// 没有特定选择器元素,直接返回null
if (selectDomLength === 0) {
return null
}
// 当前元素第一个父元素
let el = this.parentElement;
if (el === null) {
return null;
}
do {
for (let i = 0; i < selectDomLength; i++) {
if (el === selectDom[i]) {
return el;
}
}
// 不用parentNode,因为到最外层parentNode会返回#document,parentElement返回null
el = el.parentElement;
} while (el !== null)
} catch(error) {
// 选择器异常,抛出错误
throw new SyntaxError(`Failed to execute 'myClosest' on 'Element': '${select}' is not a valid selector.`);
}
}
}
closestAll的思路也差不多,只是返回值变成了数组
Element.prototype.closestAll = function(select) {
try {
// 全部的选择器元素;
const selectDom = document.querySelectorAll(select);
const selectDomLength = selectDom.length;
const nodeList = [];
// 没有特定选择器元素,直接返回null
if (selectDomLength === 0) {
return nodeList
}
// 当前元素第一个父元素
let el = this.parentElement;
if (el === null) {
return nodeList;
}
do {
for (let i = 0; i < selectDomLength; i++) {
if (el === selectDom[i]) {
nodeList.push(el);
}
}
// 不用parentNode,因为到最外层parentNode会返回#document,parentElement返回null
el = el.parentElement;
} while (el !== null)
return nodeList;
} catch(error) {
// 选择器异常,抛出错误
throw new SyntaxError(`Failed to execute 'myClosest' on 'Element': '${select}' is not a valid selector.`);
}
}
// zhangxinxu: 有bug
Element.prototype.closest = Element.prototype.closest || function(selector) {
/* 修改开始: 若没传参,返回最近父级元素 */
if(!selector) return this.parentNode;
// if(!selector) return this;
/* 修改结束 */
var el = document.querySelectorAll(selector);
if(el.length === 0) return null;
function getParentNode(node) {
var parent = node.parentNode;
if(parent.nodeType === 9) return null;
for(var i=0;i<el.length;i++){
if(parent === el[i]) return parent;
}
/* 修改开始,原来少了return */
return getParentNode(parent);
// getParentNode(parent);
/* 修改结束 */
}
return getParentNode(this);
}
// zhangxinxu: 我测下来结果相差甚远,本题无分
Element.prototype.closestAll = Element.prototype.closestAll || function(selector) {
var result = [];
/* 修改开始: 若没传参,返回最近父级元素 */
if(!selector) return this.parentNode? [this.parentNode] : [];
// if(!selector) return [this];
/* 修改结束 */
var el = document.querySelectorAll(selector);
if(el.length === 0) return [];
function getParentNode(node) {
var parent = node.parentNode;
if(parent.nodeType === 9) return result;
for(var i=0;i<el.length;i++){
if(parent === el[i]) {
result.push(parent);
break;
}
}
/* 修改开始,原来少了return */
return getParentNode(parent);
// getParentNode(parent);
/* 修改结束 */
}
return getParentNode(this);
}
if (!Element.prototype.matches) {
var eleProtoType = Element.prototype
eleProtoType.matches =
eleProtoType.webkitMatchesSelector ||
eleProtoType.msMatchesSelector ||
eleProtoType.mozMatchesSelector ||
eleProtoType.oMatchesSelector||
function(s) {
var matches = (this.document || this.ownerDocument).querySelectorAll(s),
i = matches.length;
while (--i >= 0 && matches.item(i) !== this) {}
return i > -1;
};
}
if (!Element.prototype.closest || true) {
Element.prototype.closest = function (s) {
if (!s) {
throw Error('errMsg')
}
var el = this;
if (!document.documentElement.contains(el)) {
return null;
}
for (; el !== null;) {
if (el.matches(s)) {
return el;
}
el = el.parentElement
}
return null
}
}
Element.prototype.closestAll = function (s) {
if (!s) {
throw Error('errMsg')
}
var el = this;
if (!document.documentElement.contains(el)) {
return null;
}
var result = [];
for (; el !== null;) {
if (el.matches(s)) {
result.push(el);
}
el = el.parentElement
}
return result
};
本期小测学习目的:
- 了解Element.closest()原生API方法;
- 了解Element,matches()元素API方法,非常有用的API;
- 学会自定义扩展需要的Element API。
if (!Element.prototype.matches) Element.prototype.matches = webkitMatchesSelector || msMatchesSelector || mozMatchesSelector
if (!Element.prototype.closest){
Element.prototype.closest = function(s){
if (!document.documentElement.contains(this)) return null
let cur = this
do{
if (cur.matches(s)) return cur
cur = cur.parentElement
}while(cur)
return null
}
}
if (!Element.prototype.closestAll){
Element.prototype.closestAll = function(s){
if (!document.documentElement.contains(this)) return null
let cur = this, ret = []
do{
if (cur.matches(s)) ret.push(cur)
cur = cur.parentElement
}while(cur)
return ret
}
}