JavaScript:创建内容

修改页面内容

DuckDuckGo 为例,了解如何创建、修改、删除 DOM 元素。

打开 DuckDuckGo 首页在搜索框下方有一行字:「一款不追踪你的搜索引擎。 协助推广 DuckDuckGo!」

现在来处理它!首先通过开发者工具发现这行文本的 HTML 代码是这样的

<div class="tag-home__item">
    一款不追踪你的搜索引擎。
    <span class="hide--screen-xs"> <a class="tag-home__link js-tag-item-link" href="/spread">协助推广 DuckDuckGo</a>!
    </span>
</div>

首先先将这个元素存入变量中,之后每次修改它就不用重新操作 DOM 进行获取。

const duckSays = document.querySelector('.tag-home__item');
// 当然,使用另一种方法也是可以的
// 注意如果你选择第二种就注释掉上面那行代码或者换个名字,const 不允许重复声明
// 注意去掉 CSS 的 .符号,且因为返回的是合集所以通过索引下标选择第一个
const duckSays = document.getElementsByClassName('tag-home__item')[0];

innerHTML

每个元素都从元素接口继承属性和方法(记得这是上节课的内容!)。这意味着,每个元素都有一个 .innerHTML 属性。这个属性顾名思义,表示元素内容的标记。我们可以使用这个属性来:

  • 获取元素(及其所有子代!)的 HTML 内容
  • 设置元素的 HTML 内容
duckSays.innerHTML;

返回:
"一款不追踪你的搜索引擎。<span class=\"hide--screen-xs\"> <a class=\"tag-home__link js-tag-item-link\" href=\"/spread\">协助推广 DuckDuckGo</a>!</span>"

注:如果你使用的是 Google Chrome 那么就不会有反斜杠转义符

如上返回结果可以知道,使用 innerHTML 返回的是一个字符串

我不喜欢广告,此时我想修改「协助推广 DuckDuckGo!」这几个可以这样

let duckAdText = document.querySelector('.tag-home__link');
duckAdText.innerHTML = "我已经<strong>推广</strong>咯";

在控制台输入以上代码看看有什么变化?「协助推广 DuckDuckGo!」变成了「我已经推广咯」,其中「推广」二字因为 strong 标签有了加粗效果,说明 innerHTML 可以放置 HTML 代码

outerHTML

duckSays.outerHTML;

返回:
"<div class=\"tag-home__item\">一款不追踪你的搜索引擎。<span class=\"hide--screen-xs\"> <a class=\"tag-home__link js-tag-item-link\" href=\"/spread\">协助推广 DuckDuckGo</a>!</span></div>"

注:如果你使用的是 Google Chrome 那么就不会有反斜杠转义符

除了 innerlHTML 还有个 outerHTML 不过不常用,在此略过。

textContent

如前所述,.innerHTML 可以获取/设置元素的 HTML 内容。如果我们只是想要文本内容,则可以使用简单明了的 .textContent 属性!

.textContent 属性可以:

  • 设置元素及其所有子代的文本内容
  • 返回元素及其所有子代的文本内容

刷新 Duck 官网再次运行

let duckAdText = document.querySelector('.tag-home__link');
duckAdText.textContent = "我已经<strong>推广</strong>咯";

发现这次 strong 标签也显示出来了,也就是说要添加 HTML 代码时使用 innerHTML,若只是添加修改文本内容则使用 textContent

innerText

innerText 和 textContent 相比比较特别,首先刷新网页。

索要操作的 DOM 结构如下

<div class="tag-home__item">
    一款不追踪你的搜索引擎。
    <span class="hide--screen-xs"> <a class="tag-home__link js-tag-item-link" href="/spread">协助推广 DuckDuckGo</a>!
    </span>
</div>
const duckSays = document.querySelector('.tag-home__item');
// 此时先使用 textContent,现在都还是正常的
duckSays.textContent; // "一款不追踪你的搜索引擎。 协助推广 DuckDuckGo!"
// 但是如果将 协助推广 DuckDuckGo 也就是 span 标签隐藏掉然后在操作
// 获取 <span class="hide--screen-xs">
const duckAdText = document.querySelector('.hide--screen-xs');
// 使用 CSS display 将其隐藏
duckAdText.style.display = "none";
duckSays.textContent; // "一款不追踪你的搜索引擎。 协助推广 DuckDuckGo!"
duckSays.innerText; // "一款不追踪你的搜索引擎。"

innerText 方法相比于 textContent 会忽略掉 displaynone 的内容。

小结

修改页面内容的几种方法

  • .innerHTML
  • .textContent
  • .innerText

首先,要为元素设置 HTML 内容,在上面列出的三个属性中,我们只能使用 .innerHTML。使用 .textContent 会错误地将 HTML 字符作为纯文本包含在元素中。

其次,.textContent 会完全忽略任何 CSS 样式,并返回该元素的所有 HTML,就像在 HTML 中列出的一样。而.innerText 属性会考虑 CSS 样式,并返回在页面上以可见方式呈现的文本。

延伸

添加页面内容

createElement

要向页面添加 HTML 结构首先要创建 HTML 标签然后往标签里加东西,这就需要用到 .createElement()

// 创建一个 P 标签并存入变量里方便后续使用
let pTag = document.createElement('p');
// 向创建的 P 标签填入内容
pTag.textContent = "hi";
console.log(pTag); // <p>hi</p>

运行上述代码你会发现打印 pTag 也会有 HTML 代码了但是页面并没有变化,因为 .createElement() 仅仅是创建而已

appendChild

向页面添加元素的方法之一是 .appendChild()

// 要放入到谁的下面就先获取谁
const duckSays = document.querySelector('.tag-home__item');
// 创建标签并填入内容
let text = document.createElement('span');
text.textContent = "真棒!";
// 向谁的子项插入元素
duckSays.appendChild(text);

这时就看到 Duck 搜索框下文字「一款不追踪你的搜索引擎。 协助推广 DuckDuckGo!」后多了「真棒!」

使用 .appendChild() 要注意要给它一个现有的元素(比如此处的 duckSays),不能直接在 document 对象上调用它,也就是下面这样

const newSpan = document.createElement('span');

createTextNode

.createTextNode() 用于创建文本节点

const myPara = document.createElement('p');
const textOfParagraph = document.createTextNode('I am the text for the paragraph!');
myPara.appendChild(textOfParagraph);
document.body.appendChild(myPara);
const myPara = document.createElement('p');
myPara.textContent = 'I am the text for the paragraph!'; document.body.appendChild(myPara);

如上,其实两段代码实现的效果都是一样的,与其创建一个新的文本节点,并将其附加到一个元素上,使用 .textContent 属性来更新元素的文本更加快捷方便。

insertAdjacentHTML

根据定义,.appendChild() 方法会添加一个元素作为父元素的最后一个子元素。你不能把它添加为第一个子元素或放在其他位置…它必须是最后一个子元素。

这时就需要 .insertAdjacentHTML() 方法,它必须使用两个参数来调用:

  • HTML 的位置
  • 要插入的 HTML 文本

这个方法的第一个参数可以让我们在四个不同的位置之一插入新的 HTML

  • beforebegin – 插入 HTML 文本作为前一个子元素
  • afterbegin – 插入 HTML 文本作为第一个子元素
  • beforeend – 插入 HTML 文本作为最后一个子元素
  • afterend – 插入 HTML 文本作为后一个子元素
<!-- 开始之前 -->
<p>
    <!-- 开始之后 -->
    Existing text/HTML content
    <!-- 结束之前 -->
</p>
<!-- 结束之后 -->

还是以 Duck 为例

const duckSays = document.querySelector('.tag-home__item');
const htmlTextToAdd = '<h2>Hail Hydra!</h2>';

duckSays.insertAdjacentHTML('afterend', htmlTextToAdd);

小结

  • .createElement(),创建新的元素
  • .appendChild(),将子元素添加到父元素作为其最后一个子元素
  • .createTextNode(),创建文本节点
  • .insertAdjacentHTML(),将 HTML 文本放在元素的任何位置

需要注意的一些要点包括:

  • 如果 DOM 中已经存在一个元素,并将该元素传递给 .appendChild(),则 .appendChild() 方法会移动它,而不是复制它
  • 元素的 .textContent 属性比使用 .createTextNode()方法创建文本节点更经常被用到
  • .insertAdjacentHTML() 方法的第二个参数必须是文本,而不能传递一个元素

延伸

删除页面内容

removeChild

.appendChild() 方法完全相反 .removeChild() 方法用来移除子元素。

const duckSays = document.querySelector('.tag-home__item');
const duckAdText = document.querySelector('.hide--screen-xs');

duckSays.removeChild(duckAdText);

parentElement

但实际上每次操作都要先获取父元素再操作子元素是挺烦人的,这时候可以使用 .parentElement 属性

const duckAdText = document.querySelector('.hide--screen-xs');
// 删除 duckAdText 的父级下的 duckAdText
duckAdText.parentElement.removeChild(duckAdText);

firstElementChild

.firstElementChild 总是返回子元素的第一个元素。

const duckSays = document.querySelector('.tag-home__item');
const duckAdText = duckSays.firstElementChild;

duckSays.removeChild(duckAdText);

remove

但说了这么多其实有个最直接的方法…

const duckAdText = document.querySelector('.hide--screen-xs');
duckAdText.remove();

小结

  • .removeChild()
  • .remove()

二者的不同之处在于,.removeChild() 必须在将要移除的元素的父元素上调用,并且必须传递将要移除的子元素,而 .remove() 则可以直接在将要删除的元素上调用。

还了解了以下有用的属性:

  • .firstElementChild
  • .parentElement

还有个相似的.firstChild.firstChild.firstElementChild 的不同之处在于,.firstElementChild总是返回第一个元素,而 .firstChild可能返回空白(如果有的话)以保留底层 HTML 源代码的格式。

延伸

设置页面内容样式

CSS 特异性

根据 MDN,“特异性”是指:浏览器用于确定哪个 CSS 属性值与元素最相关,因此将被应用的方式。

有的把这个特点称为 CSS 的权重或者优先级,基本而言样式规则越接近元素其特异性就越高。比如对于页面上某个元素,ID的特异性高于。而特异性最高的就是写在元素里的 style

查看 MDN 文档上的优先级

style

const duckSays = document.querySelector('.tag-home__item');
duckSays.style.color = "red";

在控制台运行以上代码,Duck 的「一款不追踪你的搜索引擎。 协助推广 DuckDuckGo!」字体会变成红色。

而通过开发者工具发现 HTML 代码上被修改成了

<div class="tag-home__item" style="color: red;">

增加了行间样式 style="color: red;",且注意每次只能修改一条样式,并且对于有连字符的属性需要修改成驼峰式大小写,比如

const duckSays = document.querySelector('.tag-home__item');
// .style 方法一次只能修改一个样式
duckSays.style.color = 'blue';
// 比如 font-size 带有连字符的属性需要修改成驼峰式大小写
duckSays.style.backgroundColor = 'orange';
duckSays.style.fontSize = "14px";

cssText

这样是挺繁琐的,这时可以使用 .cssText

const duckSays = document.querySelector('.tag-home__item');
duckSays.style.cssText = 'color: blue; background-color: orange; font-size: 3.5em'

使用 .cssText 时就可以像往常一样写 CSS 样式不需要转成驼峰式大小写。

且注意,与 .style 不同,.style 每次新增的样式都会保留现有的行间样式,而 .cssText 会覆盖之前存在的行间样式。

setAttribute

.setAttribute() 用于设置元素的属性

.font-color {
    color: orange;
}
const duckSays = document.querySelector('.tag-home__item');
// 像之前一样添加一个 style 属性,第二个参数是属性值,内容是样式内容
duckSays.setAttribute('style', 'color: blue; background-color: orange; font-size: 3.5em;');
// 添加一个 class 属性,属性值为 CSS 的类名
duckSays.setAttribute('class', 'font-color');

现在基本讲究结构(HTML)、样式(CSS)、行为(JS)三者分离,也就是各干各的的尽量不要混淆代码,所以比较好的方法就是提前将要用到的样式写入样式表,待需要用时通过 JavaScript 添加 CSS 的类名,而不是在 HTML 中直接写 CSS。也就是上面的第二种做法。

className

const duckAdText = document.querySelector('.tag-home__link');
// 将类的列表存储在一个变量中
const listOfClasses = duckAdText.className;
console.log(listOfClasses);

返回:
“tag-home__link js-tag-item-link”

.className 属性会返回一个有空格的类字符串。遗憾的是,这并不是最理想的格式。不过,我们可以使用 JavaScript 字符串方法 .split() 将这个有空格的字符串转换为一个数组:

const arrayOfClasses = listOfClasses.split(' ');
// 打印出字符串数组 ["ank-student", "jpk-modal"]
console.log(arrayOfClasses);

现在,借助这个类数组,我们可以进行任何大规模的数据计算:

  • 使用 for 循环遍历类名列表
  • 使用 .push() 向列表中添加项目
  • 使用 .pop() 从列表中移除项目

.className 是一个属性,因此我们可以通过给该属性赋一个字符串来设置它的值:

duckAdText.className = "im-the-new-class";

以上代码会抹掉 元素的 class 属性中原有的任何类,并将其替换为单个类 im-the-new-class

由于 .className 会返回一个字符串,因此很难添加或移除单个类。 如前所述可以将该字符串转换为数组,然后使用不同的数组方法来搜索一个类,并将其从列表中移除,然后使用剩余的类来更新 .className。但是这样还是过于麻烦了,所以使用 .classList 属性吧。

classList

const duckAdText = document.querySelector('.tag-home__link');
// 将类的列表存储在一个变量中
const listOfClasses = duckAdText.classList;
console.log(listOfClasses);

返回:
“[ “tag-home__link”, “js-tag-item-link” ]”

.classList 属性拥有自己的一些属性,其中一些最常用的是:

  • .add() – 向列表中添加类
  • .remove() – 从列表中移除类
  • .toggle() – 如果某个类尚不存在,则向列表中添加它;如果某个类已经存在,则从列表中移除它
  • .contains() – 根据该类是否存在于列表中返回一个布尔值
// 如上得知当前的 class 名有 "tag-home__link" 和  "js-tag-item-link"
console.log(duckAdText.classList.contains("tag-home__link")); // true
// 检查 "js-tag-item-link" 是否存在,没有就添加,存在则删除。
duckAdText.classList.toggle("js-tag-item-link"); // false
console.log(listOfClasses); // [ "tag-home__link" ] 删除掉了
// .add() 和 .remove() 相信都知道怎么用了就此略过

小结

  • 使用 .style.<prop> 修改个别样式
  • 使用 .style.cssText 一次更新多个样式
  • 使用 .className 获取/设置类列表
  • 使用 .classList 获取/设置/切换 CSS 类

.classList 是目前为止这些技能中最有用的属性,而且它可以帮助你将 CSS 样式与 JavaScript 代码保持分开,所以尽量多的使用 .classList

延伸

您可能还喜欢...

发表评论

电子邮件地址不会被公开。 必填项已用*标注