PHP 学习之路:第十一天—— DOM常用操作详解

一、类数组

1.类数组的定义

// 类数组,其实是一个特殊的对象,长得像数组,但它又不是数组
// 类数组有二个特征:
//   1. 有一个length属性
//   2. 有递增的正整数索引
const brand = {
    0: 'HUAWEI',
    1: 'APPLE',
    2: 'XIAOMI',
    length: 3,
};
console.log(brand);
console.log(brand.length);
console.log(brand[0], brand[1], brand[2]);
console.log(Array.isArray(brand)); // false
console.log(brand instanceof Object); // true
复制代码
  1. 类数组和数组的区别
// 数组可以使用 push(): 从尾部向数组追加一个成员
// 类数组则会报错 "brand.push is not a function"
const arr = [1, 2, 3];
console.log(arr);  // [1, 2, 3]
arr.push(4);
console.log(arr); // [1, 2, 3, 4]

const brand = {
    0: 'HUAWEI',
    1: 'APPLE',
    2: 'XIAOMI',
    length: 3,
};
brand.push("OnePlus"); // "brand.push is not a function"
复制代码
  1. 类数组转为真正的数组
const brand = {
    0: 'HUAWEI',
    1: 'APPLE',
    2: 'XIAOMI',
    length: 3,
};
// 将“类数组”转为真正的数组,方便我们使用强大的数组方法来操作
// 1. Array.from()
let arr1 = Array.from(brand);
console.log(Array.isArray(arr1)); // true
arr1.push("vivo");
console.log(arr1); // ["HUAWEI", "APPLE", "XIAOMI", "vivo"]

// 2. [...rest]:归并参数,rest语法
// 直接转换时报错 "brand is not iterable"
// let arr2 = [...brand];  // "brand is not iterable"
// js为一些预置的类型创建了迭代器接口,但是自定义的类型就没有,只有我们自己手工创建
Object.defineProperty(brand, Symbol.iterator, {
value() {
  let index = 0;
  const keys = Object.keys(this);
  return {
    next: () => {
      return {
        done: index >= keys.length - 1,
        value: this[keys[index++]],
      };
    },
  };
},
});
let arr2 = [...brand];
console.log(arr2, Array.isArray(arr2)); // ["HUAWEI", "APPLE", "XIAOMI"] true
arr2.push('OPPO');
console.log(arr2); // ["HUAWEI", "APPLE", "XIAOMI", "OPPO"]
复制代码

二、快速获取 DOM 元素

1.使用 js 基本语法,仿写 jQuery 的 “$”

<body>
    <ul class="list">
      <li class="item">item1</li>
      <li class="item">item2</li>
      <li class="item">item3</li>
      <li class="item">item4</li>
      <li class="item">item5</li>
    </ul>
    <script>
      // $("body"): jQuery 用这个语法来获取'body'元素
      let $ = selector => document.querySelector(selector);
      console.log($);
      console.log($("body"));
      // 设置 body 的背景颜色
      $('body').style.background = "lightcyan";
    </script>
</body>
复制代码

2.获取所有满足条件的元素的集合

<ul class="list">
    <li class="item">item1</li>
    <li class="item">item2</li>
    <li class="item">item3</li>
    <li class="item">item4</li>
    <li class="item">item5</li>
</ul>
<script>
    // 获取满足条件的元素的集合
    const items = document.querySelectorAll(".list .item");
    // NodeList: 类数组
    // 遍历 items 元素
    // NodeList有一个forEach()接口
    // item: 正在遍历的当前元素,必选
    // index: 当前元素的索引
    // items: 当前遍历的数组对象
    items.forEach(function (item, index, items) {
    console.log(item, index, items);
    });
    // 使用箭头函数简化,以后这个语法使用更多
    items.forEach(item => console.log(item));

    // 思考:如何获取第一个满足条件的元素?
    let firstItem = items[0];
    console.log(firstItem);
    firstItem.style.background = "lightgreen";
</script>
复制代码

3.获取满足条件的元素集合中的第一个元素

<ul class="list">
  <li class="item">item1</li>
  <li class="item">item2</li>
  <li class="item">item3</li>
  <li class="item">item4</li>
  <li class="item">item5</li>
</ul>
<script>
  // 获取满足条件的元素集合中的第一个元素
  firstItem = document.querySelector(".list .item");
  console.log(firstItem);
  firstItem.style.background = "green";
  // querySelector()总是返回唯一元素,常用于 id

  // querySelectorAll, querySelector, 也可以用在元素上
  let list = document.querySelector(".list");
  let items = list.querySelectorAll(".item");
  console.log(items);
  // NodeList它自了一个迭代器接口, for-of 进行遍历
  for (let item of items) {
    console.log(item);
  }

  //  以下传统方式, es6 以后不推荐使用
  //   document.getElementById()
  //   document.getElementsByTagName()
  //   document.getElementsByName()
  //   document.getElementsByClassName()
</script>
复制代码

4.快速获取一些特定的元素

<ul class="list">
  <li class="item">item1</li>
  <li class="item">item2</li>
  <li class="item">item3</li>
  <li class="item">item4</li>
  <li class="item">item5</li>
</ul>

<form action="" name="hello" id="login">
  <input type="email" placeholder="demo@email.com" />
  <button>提交</button>
</form>
<script>
  // 快速获取一些特定的元素
  // body
  console.log(document.body);
  // head
  console.log(document.head);
  // title
  console.log(document.title);
  // html
  console.log(document.documentElement);

  //forms
  console.log(document.forms);
  console.log(document.forms[0]);
  // <form action="" name="hello" id="login">
  console.log(document.forms["hello"]);
  console.log(document.forms["login"]);
  console.log(document.forms.item(0));
  console.log(document.forms.item("hello"));
  console.log(document.forms.item("login"));
  console.log(document.forms.namedItem("hello"));
  // forms.id
  // 推荐用id,因为id方便添加样式
  console.log(document.forms.login);
  console.log(document.forms.hello);
</script>
复制代码

三、DOM 树的遍历和元素的获取

1. 将类数组转为真正的数组类型

<ul class="list">
  <li class="item">item1</li>
  <li class="item">item2</li>
  <li class="item">item3</li>
  <li class="item">item4</li>
  <li class="item">item5</li>
  <li class="item">item6</li>
</ul>

<script>
  // dom树中的所有内容都是:节点
  // 节点是有类型的: 元素,文本,文档,属性..
  let nodes = document.querySelector(".list");
  console.log(nodes.childNodes);
  // 通常只关注元素类型的节点
  console.log(nodes.children);
  let eles = nodes.children;

  // 遍历
  // 将类数组转为真正的数组类型
  console.log([...eles]);
  [...eles].forEach(ele => console.log(ele));
  // 获取第一个
  let firstItem = eles[0];
  firstItem.style.background = "yellow";
  // 最后一个
  //   let lastItem = eles[4];
  let lastItemIndex = eles.length - 1;
  let lastItem = eles[lastItemIndex];
  lastItem.style.background = "lightblue";
</script>
复制代码

2. 使用 js 提供的快捷方式来获取第一个和最后一个

  • firstElementChild 获取第一个
  • lastElementChild 获取最后一个
<ul class="list">
  <li class="item">item1</li>
  <li class="item">item2</li>
  <li class="item">item3</li>
  <li class="item">item4</li>
  <li class="item">item5</li>
  <li class="item">item6</li>
</ul>

<script>
  // js提供一些快捷方式来获取第一个和最后一个
  const list = document.querySelector(".list");
  firstItem = list.firstElementChild;
  firstItem.style.background = "seagreen";

  lastItem = list.lastElementChild;
  lastItem.style.background = "yellow";

  console.log(eles.length);
  console.log(list.childElementCount);
</script>
复制代码

3. 兄弟节点的获取

  • nextElementSibling 下一个兄弟节点
  • previousElementSibling 前一个兄弟节点
<ul class="list">
  <li class="item">item1</li>
  <li class="item">item2</li>
  <li class="item">item3</li>
  <li class="item">item4</li>
  <li class="item">item5</li>
  <li class="item">item6</li>
</ul>

<script>
  //   如何想获取第二个元素怎么办?
  //   第二个元素就是第一个元素的下一个兄弟节点
  let secondItem = firstItem.nextElementSibling;
  secondItem.style.background = "red";

  // 获取第5个, 是最后一个元素的前一个兄弟节点
  let fiveItem = lastItem.previousElementSibling;
  fiveItem.style.background = "cyan";
</script>
复制代码

四、DOM 元素的内容

<div class="box">
  <p></p>
</div>

<script>
  const box = document.querySelector(".box");
  const p = document.querySelector("p");
  // textContent: 添加文本
  p.textContent = "hello world";
  // html字符串
  p.textContent = '<em style="color:red">php.cn</em>';

  // 如果想将html字符串渲染出来应该使用innerHTML
  p.innerHTML = '<em style="color:red">php.cn</em>';

  // outerHTML: 使用当成的文本将当前节点直接替换掉(实际上就是当前内容的父节点)
  p.outerHTML = '<em style="color:red">php.cn</em>';
  console.log(box);
</script>
复制代码

五、dataset 自定义数据属性

<p id="user" email="a@qq.com" data-email="admin@php.cn" data-my-age="99">我的档案</p>

<script>
  const p = document.querySelector("p");
  // id是默认的内置的标准属性,所以可以直接用点语法进行访问
  console.log(p.id);
  // email是非内置属性
  console.log(p.email);

  // 1.对于自定义的数据属性"data-",使用dataset对象来操作
  console.log(p.dataset.email);

  // console.log(p.dataset["my-age"]);
  // 2.多个单词要转换为驼峰式
  console.log(p.dataset.myAge);
</script>
复制代码

六、DOM 树元素的增删改查

1.创建 DOM 元素,并添加到页面显示

// 创建dom元素
let div = document.createElement("div");
let span = document.createElement("span");
span.textContent = "hello";

// append(ele,'text'),将参数做为父元素的最后一个子元素追加到列表中,无返回值
// span 添加到 div中
// div.append(span);
// 将 span,"world",添加到 div中
div.append(span, " world");
// 方式一: 将 div 添加到页面
document.body.append(div);
console.log(div)

// 方式二:将 span, " world" 添加到页面
// document.body.append(span, " world");
// console.log(div)
复制代码

2.为什么div中的span消失了?

image.png

image.png

// 为什么div中的span消失了?
// 新元素span只能插入到一个地方;span在div,现在span在body中,相当于剪切操作
// 如果想保留span在div中,要克隆span
// cloneNode(true), true: 是完整的保留元素内部结构
document.body.append(span.cloneNode(true), " world");
复制代码

效果如图:

image.png

3. DOM 树元素的增删改

  • append():在尾部追加
  • prepend():在头部追加
  • before():在参考点之前添加一个新节点
  • after():在参考点之后添加一个新节点
  • replaceWith():替换元素
  • remove(无参数):删除元素
  • afterBegin: 开始标签之后,第一个子元素
  • beforeBegin: 开始标签之前,是它的前一个兄弟元素
  • afterEnd: 结束标签之后,它的下一个兄弟元素
  • beforeEnd: 结束标签之前,它的最后一个子元素
// append()创建一个列表
const ul = document.createElement("ul");
// 循环来生成多个列表项 li
for (let i = 1; i <= 5; i++) {
let li = document.createElement("li");
li.textContent = `item${i}`;
ul.append(li);
}
document.body.append(ul);

// append():在尾部追加
// prepend():在头部追加
li = document.createElement("li");
li.textContent = "first item";
li.style.color = "red";
ul.prepend(li);

// 如果想在除了头尾之外的地方添加怎么操作?
// 必须要有一个参考节点的位置,否则就不知道要添加到哪个节点的前面或后面
// 以第四个节点为参考
const referNode = document.querySelector("li:nth-of-type(4)");
referNode.style.background = "cyan";
// 在它之前添加一个新节点
li = document.createElement("li");
li.textContent = "在参考节点之前插入";
li.style.background = "yellow";
// referNode.before(el),在插入位置(参考节点)上调用
referNode.before(li);

// 在它之后添加一个新节点
li = document.createElement("li");
li.textContent = "在参考节点之后插入";
li.style.background = "violet";
// referNode.after(el),在插入位置(参考节点)上调用
referNode.after(li);

// 替换节点
// 将最后一个节点用链接替换
let lastItem = document.querySelector("ul li:last-of-type");
let a = document.createElement("a");
a.textContent = "php中文网";
a.href = "https://php.cn";
lastItem.replaceWith(a);

// 删除节点,在被删除的节点上直接调用
// 将ul的第6个删除,remove(无参数)
ul.querySelector(":nth-of-type(6)").remove();

// 再介绍几个更牛的
// insertAdjacentElement('插入位置', 元素)
// 插入位置有四个
// afterBegin: 开始标签之后,第一个子元素
// beforeBegin: 开始标签之前,是它的前一个兄弟元素
// afterEnd: 结束标签之后,它的下一个兄弟元素
// beforeEnd: 结束标签之前,它的最后一个子元素
// 插入第一个子元素之前(在起始标签之后);
li = document.createElement("li");
li.textContent = "第一个子元素";
ul.insertAdjacentElement("afterbegin", li);
ul.insertAdjacentElement("beforebegin", li);

// 还有一个plus,可以直接使用html字符串当元素,省去了创建元素的过程
// 追加到结尾
ul.insertAdjacentHTML("beforeEnd", '<li style="color:red">最后一个子元素</li>');

// 还可以直接插入文本
const h2 = document.createElement("h2");
h2.insertAdjacentText("beforeend", ul.lastElementChild.textContent);
console.log(h2);
document.body.insertAdjacentElement("afterend", h2);
复制代码

七、css 操作

1.行内样式

<p>Hello World</p>
<script>
  const p = document.querySelector("p");
  // 添加行内样式
  p.style.color = "red";
  console.log(p);
    </script>
复制代码

2. 类样式 classList

<style>
  .bgc-cyan {
    background-color: cyan;
  }
  .bgc-yellow {
    background-color: #ff0;
  }
  .border {
    border: 3px solid #000;
  }
  .bolder {
    font-weight: bolder;
  }
</style>

<p>Hello World</p>
<button id="btn" onclick="toggleBorder">切换边框</button>

<script>
  const p = document.querySelector("p");
  // add() 添加样式,可同时添加多个
  p.classList.add("bgc-cyan");
  p.classList.add("border", "bolder");
  // remove() 删除样式
  p.classList.remove("border");
  // replace() 替换样式
  p.classList.replace("bgc-cyan", "bgc-yellow");

  btn.onclick = function () {
    // toggle: 样式自动切换, 如果已存在则删除, 如果不存在则添加;
    p.classList.toggle("border");
  };

  // className 每次只能添加一个样式,不推荐使用
  // p.className = "bgc-yellow";
  // p.className = "bgc-yellow border";
</script>
复制代码

3.计算样式

<div style="height: 50px; background-color: #ff0; color: red">Hello World</div>

<script>
  const div = document.querySelector("div");
  // 一个元素最终应该渲染成什么样式,由浏览器来决定
  // 浏览器根据一个元素的行内样式,内部样式,外部样式表来计算出最终的样式
  
  // getComputedStyle(要查看样式的元素 , 伪元素)
  let styles = window.getComputedStyle(p, null);
  
  //得到背景色,不同浏览器得到的不一样,chrom 浏览器报错
  // let styles = document.defaultView.getComputedStyle("p", null);
  
  // 计算样式都是只读的
  // console.log(styles);
  console.log(styles.getPropertyValue("height"));
  console.log(styles.getPropertyValue("background-color"));
  console.log(styles.getPropertyValue("color"));
</script>
复制代码
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享