css提取页面元素唯一性_获取网页指定元素的原生方法回顾

当页面存在相同属性的元素时,如何使用CSS选择器和JavaScript的document方法选择特定元素?本文通过实例探讨了document.querySelector、getElementById等方法,以及innerText属性在选取元素中的应用。
摘要由CSDN通过智能技术生成

那是个夜黑风高的夜晚,我遇到了一个按钮:

搜索

嗯,我要选中它,我敲下了一行代码:

const submitButton = document.querySelector('button[type="submit"]');

这对于精通 document.querySelector 的函数名书写方式的我来说,简直就像吃下四两饭一样简单!

但是。

我们知道,document.querySelector 接收一个选择器字符串,返回第一个匹配的 DOM 元素,所以如果页面上只有一个 button[type="submit"] 或者这个 button[type="submit"] 在 html 中是第一个时,我这个方法是无懈可击的。

然后,我发现页面上竟然存在两个 button[type="submit"] 类型的按钮(黑人问号???)。

我对比了一下差异:

提交

搜索

先不八卦为什么页面上有两个差不多的按钮,但能初步判定的是,他们长得很像,嗯。

那么,问题来了,我怎么选中那个搜索框,我把问题抛给了自以为是的自己,得到了几个回答。

分身 A:改用 selectorSelectorAll 拿到第二个不就行了嘛!

const allSubmitButton = document.querySelectorAll('button[type="submit"]');

const submitButton = allSubmitButton[1];

这方法貌似不错,但万一这两个按钮对调位置了怎么办?

分身 B: 那选择器写全一点,也匹配『搜索』这两个字不就可以把『提交』那个按钮给拍除掉了嘛!

const submitButton = document.querySelector('button[type="submit"][innerText="搜索"]');

打印出来一看,嗯,怎么输出是 null???

分身 B: 那个,那个。。。innerText 是我编出来的,我不知道正确的要怎么写。

嗯,虽然 B 写错了语法(哪个程序员会不写错语法?),但限定了两个条件,type="submit" 和 innerText="搜索", 能唯一匹配搜索按钮了,这个思路是对的。

那么,正确的语法是什么呢?

苦苦搜索半天,无果。

分身 C: 那就是写不出这样的选择器吧,还是用 JS 来做吧 :)

分身 A: 这么简单的需求,CSS 是万能的,为什么要用 Javascript?

分身 B: 对,Hail CSS!

。。。那我们就借此机会温习一下找到一个 DOM 元素有哪些方法吧。

浏览器原生提供的几个找到 DOM 元素的方法

document.getElementById

Id 为网页全局唯一。

document.getElementById('id');

注意,与其他方法不一样,getElementById 只能被全局对象 document 调用,否则会报错:

document.getElementById('parentId').getElementById('childId');

// Uncaught TypeError: document.getElementById(...).getElementById is not a function

因为 Id 是全局唯一的,所以上面第二种写法自然也显得没有必要。

Id 对大小写敏感(除非文档被声明为特殊类型如: XHTML, XUL),所以以下两种写法并不等同:

document.getElementById('id');

documen.getElementById('ID');

element.getElementsByClassName

这里的 element 指代网页中有效的 DOM 元素,包含 document。

返回一个 HTMLCollection。

// 匹配 class 包含 'submit' 的元素

document.getElementsByClassName('submit');

// 匹配 class 包含 'submit' 和 'button' 的元素

document.getElementsByClassName('submit button');

// 级联

cons selectedElement = document.getElementById('app-container');

selectedElement.getElementsByClassName('submit button');

element.getElementsByName

用法和 getElementsByClassName 相似, 返回一个 HTMLCollection。

element.getElementsByTagName

用法和 getElementsByClassName 相似, 返回一个 HTMLCollection。

element.querySelector

再熟悉不过的接口了,传入 CSS 选择器,返回第一个找到的元素。

element.querySelectorAll

以上返回数组的方法,getElementsByName、getElementsByTagName、getElementsByTagNameNS、querySelectorAll 返回的都是 Array-like 的 HTMLCollection。

要像对数组一样对 HTMLCollection 进行操作(使用数组的 forEach、filter 等方法),则需要将他们转化为数组:

const buttonCollection = document.getElementsByClassName('submit');

// const buttonArray = Array.prototype.slice.call(buttonCollection);

const buttonArray = [].slice.call(buttonCollection);

buttonArray.forEach(item => {

// do something

});

querySelector 与 getElementsByName、getElementsByClassName 和 getElementsByTagName 的细微差异

注意,对于都是返回 HTMLCollection 的方法,与 querySelector 不同的是,getElementsByName、getElementsByClassName、getElementsByTagName 返回的 HTMLCollection 是一个引用类型的 HTMLCollection 。

也就是:

querySelectorAll 获取的是当时文档中匹配选择器的 DOM 元素,不包含后面插入到文档中的元素,如果文档有更新,则需要重新获取

而 getElementsByName、getElementsByClassName 和 getElementsByTagName 则能随时反映文档中匹配对应规则的元素,包含后面插入到文档中的元素,如果文档有更新,不需要重新获取

这个说法有点类似拷贝和引用的关系。

话不多说,我们直接写点代码做个测试:

const createElement = (func) => {

const key = 'myCustomElement';

let element;

switch (func) {

case 'getElementsByName':

element = document.createElement('div');

element.setAttribute('name', key);

break;

case 'getElementsByClassName':

element = document.createElement('div');

element.setAttribute('class', key);

break;

case 'getElementsByTagName':

element = document.createElement(key);

break;

case 'querySelectorAll':

element = document.createElement('div');

element.className = key;

break;

default:

element = document.createElement('div');

}

return element;

}

const getCollection = (root, func) => {

const key = 'myCustomElement';

let element;

if (func === 'getElementsByName') {

return document.getElementsByName(key);

}

if (func === 'querySelectorAll') {

return root.querySelectorAll(`.${key}`);

}

return root[func](key);

}

const testFunc = (func) => {

const result = [];

// 避免 getElementsByClassName 和 querySelectorAll 在统一环境的影响,创建一个独立的容器测试

const container = document.createElement('div');

document.body.append(container);

// 1. 插入一个

container.append(createElement(func));

// 2. 看下现在有多少个

const collection = getCollection(container, func);

result.push(collection.length);

// 3. 继续插入一个

container.append(createElement(func));

// 4. 看下现在有多少个

result.push(collection.length);

return result;

};

console.log('getElementsByName', testFunc('getElementsByName')); // [1, 2]

console.log('getElementsByClassName', testFunc('getElementsByClassName')); // [1, 2]

console.log('getElementsByTagName', testFunc('getElementsByTagName')); // [1, 2]

console.log('querySelectorAll', testFunc('querySelectorAll')); // [1, 1] // 注意这个输出

// 输出的是:

/*

getElementsByName [1, 2]

getElementsByClassName [1, 2]

getElementsByTagName [1, 2]

querySelectorAll [1, 1]

*/

还有什么方法可以根据 innerText 找到指定元素

回到本文讨论的问题,貌似浏览器原生并没有提供类似 document.getElementByInnerText ?

找了一圈貌似没有,那只能借用 Javascript 了。

回忆一下需要找到的元素是:

搜索

使用原生 Javascript

可以使用 querySelectorAll :

let foundElement = null;

const elementsCollection = document.querySelectorAll('button[type="submit"]');

const elementArray = [].slice.call(elementsCollection);

/*

// 使用 Array.forEach 遍历,缺点是找到后没法 break

elementArray.forEach(element => {

if (element.innerText.trim() === '搜索') {

foundElement = element;

}

// 或者使用正则

/*

if (/^\s{0,}搜索\s{0,}$/.test(element.innerText)) {

foundElement = element;

}

*/

});

*/

/*

// 或使用 for-loop 找到后提前 break

const len = inputElementArray.length;

for (let i = 0; i < len; i++) {

if (elementArray[i].innerText.trim()) {

foundElement = elementArray[i];

break;

}

}

*/

// 或使用 filter

const foundElementArray = elementArray.filter(element => element.innerText.trim() === '搜索');

if (foundElementArray.length) {

foundElement = foundElementArray[0];

}

题外话:innerText 与 innerHTML、textContent 的差异?

简而言之:

innerText 获取元素第一层的文本内容,不包含标签;

innerHTML 如其名获取内部 HTML 片段,包含标签;

textContent 类似 innerText,不过会在去掉标签后将嵌套的纯文本内容也获取出来。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值