【H2O2|全栈】JS入门知识(八)DOM(2)

server/2024/10/25 5:43:09/

目录

JS

前言

准备工作

排他操作

概念

案例

开关

概念

案例

自定义属性

设置属性

获取属性

移除属性

H5标准自定义属性格式规范 

案例

节点

层级

父节点

子节点

兄弟节点

创建节点

添加节点

案例

结束语


JS

前言

本系列博客主要分享JavaScript的基础语法知识,本期为第八期,包含一些简单的js语法——排他操作、开关思想、自定义属性和节点的相关内容。

与HTML和CSS相比,JS加入了很多逻辑性的元素在里面,所以需要一定的逻辑思维能力,要求能够整合一些知识。如果遇到不理解之处,可以参阅同系列之前的章节。

准备工作

软件:【参考版本】Visual Studio Code

插件(扩展包):Open in browser, Live Preview, Live Server, Tencent Cloud AI Code Assistant, htmltagwrap

浏览器版本:Chrome

系统版本: Win10/11/其他非Windows版本

*我的电脑是Win10的版本,仅供参考*

排他操作

概念

所谓排他操作,就是指在一个元素实现指定的样式时,让同级的其余元素清除该样式。

排他操作的算法步骤如下: 

  1. 所有元素全部清除样式(干掉其他)
  2. 给当前元素设置样式 (留下自己)

注意顺序不能颠倒,首先干掉其他,再设置自己。

案例

Q:让下面的按钮,只有一个按钮处于特殊的状态——

A:实现一下上面的效果(比较简陋)——

    <button>按钮1</button><button>按钮2</button><button>按钮3</button><button>按钮4</button><button>按钮5</button><script>// 1. 获取所有按钮元素var btns = document.getElementsByTagName('button');for (var i = 0; i < btns.length; i++) {btns[i].onclick = function() {// (1) 我们先把所有的按钮背景颜色去掉for (var i = 0; i < btns.length; i++) {btns[i].style.backgroundColor = '';}// (2) 然后才让当前的元素背景颜色为redthis.style.backgroundColor = 'red';}}</script>

开关

概念

开关通常是一个boolean类型的变量, 通过操作开关,可以保存一组操作的最终状态

通常用于涉及逻辑运算(与或非)的情况。

案例

Q:在一组checkbox中,实现全选和全不选效果。

具体效果如下——

A:首先,我们需要清除我们需要做到下面的几个效果——

  • 点击全选使之被选中,则A、B、C均被选中
  • 取消全选,A、B、C均取消选中
  • 如果A、B、C都被选中了,则全选框也被选中
  • 只要A、B、C中有一个被取消选择,则全选框也被取消选中

参考HTML代码如下——

     <table><tr><th><input type="checkbox" name="" id="all"><label for="all">全选</label></th><th>商品名</th><th>价格</th></tr><tr><td><input type="checkbox" name="" id="type-a" class="tp"><label for="type-a">A类</label></td><td>1</td><td>666</td></tr><tr><td><input type="checkbox" name="" id="type-b" class="tp"><label for="type-b">B类</label></td><td>2</td><td>555</td></tr><tr><td><input type="checkbox" name="" id="type-c" class="tp"><label for="type-c">C类</label></td><td>3</td><td>444</td></tr></table>

CSS样式如下——

        * {margin: 0;padding: 0;list-style: none;text-decoration: none;box-sizing: border-box;}table,tr,th,td {border: 2px solid;border-collapse: collapse;}table {margin: 30px auto;}th,td {height: 40px;padding: 0 10px;}input {width: 20px;}

上述部分不是我们本章的重点,略过,关键来看JS实现。

首先,获取我们的全选框和三个选择框——

javascript">    var cbs = document.querySelectorAll('.tp')var cbAll = document.querySelector('#all')

添加全选框单击事件,让所有的其他复选框在全选框选中时选中,取消时取消,即所有checkbox的状态都和全选框状态保持一致——

javascript">    cbAll.onclick = function () {for (var i = 0; i < cbs.length; i++) {// 所有按钮的状态可以由全选按钮的状态统一决定cbs[i].checked = this.checked}}

如此一来,我们已经实现了由全选框向其他复选框的单向控制。

接下来实现由其他复选框向全选框的反向控制。

遍历其他的选择框,绑定单击事件,然后设置一个开关(flag),让所有其他选择框元素来控制这个开关,最后再由开关的状态来决定全选框的选中状态——

javascript">    for (var i = 0; i < cbs.length; i++) {cbs[i].onclick = function() {// 开关var flag = true// 检查所有按钮for (var j = 0; j < cbs.length; j++) {if (!cbs[j].checked) {// 只要有一个没被选到,就关闭开关flag = falsebreak}}cbAll.checked = flag}}

如此一来,我们的复选框的功能就全部实现了。

自定义属性

设置属性

有时,原本的属性并不能完全满足我们的要求,在部分情况下使用已有的属性可能会出现意想不到的错误。

比如,当我们利用for循环为一组元素绑定事件之后,实质上该绑定行为已经将for中的 var i 遍历走完到最后,即 i 的值已经来到循环条件退出的情况了。

此时,如果我们还需要用 elements[i] 的方式获取指定元素,将获取不到当前元素,因为此时的 i = elements.length

想要解决这个问题,我们就可以绑定一个自定义的属性——index,用于在绑定事件之前记录当前元素的索引值。

我们知道,以往想要给一个元素的属性赋值,可以这么做——

e.属性 = '值'

但是,这个操作的前提是该属性是元素e本身具有的内置属性

而自定义属性在设置时,不但要赋值,还需要设置该属性——

e.setAttribute( '属性' , '值' )

获取属性

同样的,在获取属性时,如果该属性为内置属性,则可以这样操作——

e.属性

如果该属性为由 setAttribute() 设置的自定义属性,则可以用与之对应的方式获取该属性——

e.getAttribute( '属性' )

当然,该方式也可以获取内置属性。

移除属性

如果我们不再需要使用我们的自定义属性,则也有对应的移除方式——

e.removeAttribute( '属性' )

H5标准自定义属性格式规范 

自定义属性目的是为了保存并使用数据,有些数据可以保存到页面中而不用保存到数据库中。

但是有些自定义属性很容易引起歧义,不容易判断是元素的内置属性还是自定义属性。

因此,H5规定自定义属性以 data- 开头作为属性名。

此外,H5新增了使用下面两种方式获取自定义属性(以data-index为例)——

e.dataset.index

e.dataset[ 'index' ]

这两种方式只有较新版本才支持,考虑兼容性时还是使用 getAttribute() 较为稳妥。 

案例

Q:完成下面需求(不要求样式一致,重点在JS代码实现)——

A:分析案例——

这里主要讲解JS原理,所以我给出一个简化版的效果——

参考HTML代码——

    <ul class="tabs"><li class="current">区域一</li><li class="">区域二</li><li class="">区域三</li></ul><div class="box"><div class="content">内容一</div><div class="content">内容二</div><div class="content">内容三</div></div>

参考CSS代码——

        * {margin: 0;padding: 0;list-style: none;text-decoration: none;box-sizing: border-box;}.tabs {width: 540px;height: 90px;margin: 30px auto;display: flex;justify-content: space-between;}.tabs li {width: 160px;height: 100%;display: flex;justify-content: center;align-items: center;border: 2px solid #ccc;background: #fff;font-weight: bold;font-size: 32px;cursor: pointer;}.tabs li.current {background: #f00;}.box {width: 540px;height: 200px;margin: 0 auto;background: #5ad6f5;}.box .content {display: none;font-size: 40px;}.box .content:first-child {display: block;}

来到JS部分,首先是获取必要的元素(事件源)——

javascript">    var tabs = document.querySelector('.tabs')var lis = tabs.querySelectorAll('li')var box = document.querySelector('.box')var contents = box.querySelectorAll('.content')

然后是遍历获取所有事件源(图中的区域),并且在绑定事件之前提前设置好data-index属性——

javascript">for (var i = 0; i < lis.length; i++) {lis[i].setAttribute("data-index", i)// ...}

接下来,绑定鼠标单击事件,利用排他操作,为当前选中的元素设置current类名(激活时的样式表)——

javascript">    for (var i = 0; i < lis.length; i++) {// ...for (var j = 0; j < lis.length; j++) {lis[j].className = ""}this.className = "current"// ...}

最后,还是利用排他操作,仅让当前index对应的内容显示。

完整的for循环如下——

javascript">    for (var i = 0; i < lis.length; i++) {lis[i].setAttribute("data-index", i)lis[i].onclick = function () {for (var j = 0; j < lis.length; j++) {lis[j].className = ""}this.className = "current"for (var j = 0; j < contents.length; j++) {contents[j].style.display = 'none'}contents[this.dataset.index].style.display = 'block'}}

节点

在上一期中,我们讲到了DOM树的概念,即网页中的所有内容都是节点(标签、属性、文本、注释等)。

在DOM 中,节点使用 node 来表示,所有节点均可通过 JavaScript 进行访问,所有 HTML 元素(节点)均可被修改,也可以创建或删除。

一般地,节点至少拥有nodeType(节点类型)、nodeName(节点名称)和nodeValue(节点值)这三个基本属性。

常见的节点类型有下面三种——

  • 元素节点 nodeType = 1
  • 属性节点 nodeType = 2
  • 文本节点 nodeType = 3

在我们的实际开发中,更多的是使用元素节点。 

层级

由DOM树从上到下, 不同节点之间存在亲代兄弟关系,即存在层级关系。

父节点

我们把当前节点称为node,想要获取父节点(最近),可以这么做——

node.parentNode

子节点

想要获取子节点,则有下面两种方式——

node.childNodes // 标准方式

node. children // 非标准方式

前者返回的是包含指定节点的子节点的集合,这个集合实时更新,包含所有nodeType的节点,如果只想获取其中的元素节点,则不提倡使用该方式

后者是一个只读属性,返回所有的子元素节点。由于它只返回元素节点,所以很方便。

如果想要返回特定的子元素节点,可以使用类数组的索引方式操作——

parentNode.children[i] 

兄弟节点

获取兄弟节点或仅获取兄弟元素节点(后者存在兼容性问题)的方式有下面四种——

1.nextSibling 下一个兄弟节点 包含元素节点或者 文本节点 等等
        div.nextSibling
        div.previousSibling
2. nextElementSibling 得到下一个兄弟元素节点
        div.nextElementSibling
        div.previousElementSibling

创建节点

此前,我们知道可以通过JS获取HTML元素,同样的,我们也可以将HTML元素节点添加到HTML文档中。但是在此之前,我们需要先讲新的节点创建出来——

document.creatElement( 'tagName' )

其中,tagName是我们的标签名称,与getElementsByTagName()相对应。

该方式也叫做动态创建元素节点

添加节点

添加节点的方式有两种,分别是在父节点的最后一个子节点的末尾添加和在父节点的指定子节点的前面添加,二者的作用类似于 :after 和 :before ——

parentNode.appendChild(child)

parentNode.insertBefore(child, node)

案例

Q:完成一个简单的公屏聊天功能——

A:分析案例——

参考的HTML代码如下——

    <textarea name="" id="" placeholder="输入内容"></textarea><button>发送</button><div class="screen"><ul></ul></div>

参考的CSS代码如下——

        * {margin: 0;padding: 0;list-style: none;text-decoration: none;box-sizing: border-box;}textarea {width: 300px;height: 100px;padding: 10px;resize: none;}button {cursor: pointer;}.screen {width: 300px;height: 300px;overflow: auto;border: 2px solid #ccc;}ul {width: 100%;}li {margin: 10px 10%;background: #f3afaf;}

来到JS部分,首先还是获取事件源——

javascript">    var ta = document.querySelector('textarea')var btn = document.querySelector('button')var screen = document.querySelector('.screen')var ul = screen.querySelector('ul')

随后,绑定按钮的鼠标单击事件,同时检测是否有内容输入,如果输入值为空则弹出警告框。

最后在ul创建子节点并添加。使用appendChild()和insertBefore() 均可——

javascript">    btn.onclick = function () {if (ta.value == '') {alert("请输入内容")} else {var li = document.createElement('li')li.innerHTML = ta.valueul.insertBefore(li, ul.children[0])}}

结束语

本期的内容到这里就结束了,在后续的本系列博客中,我会继续更新js的基础语法知识,并适当地配合上一些案例。

在全栈领域,博主也只不过是一个普通的萌新而已。本系列的博客主要是记录一下自己学习的一些经历,然后把自己领悟到的一些东西总结一下,分享给大家。

文章全篇的操作过程都是笔者亲自操作完成的,一些定义性的文字加入了笔者自己的很多理解在里面,所以仅供参考。如果有说的不对的地方,还请谅解。

==期待与你在下一期博客中再次相遇==

——还在漏气的【H2O2】

 


http://www.ppmy.cn/server/134621.html

相关文章

C++算法练习-day18——15.三数之和

题目来源&#xff1a;. - 力扣&#xff08;LeetCode&#xff09; 题目思路分析 题目描述&#xff1a; 给定一个包含 n 个整数的数组 nums&#xff0c;判断 nums 中是否存在三个元素 a&#xff0c;b&#xff0c;c &#xff0c;使得 a b c 0 &#xff1f;找出所有独特三元组…

Android 13 SPRD 如何临时修改 Android 系统版本

在 Android 开发或调试过程中,有时需要临时修改系统版本号,例如为了适应特定的应用需求或进行特定版本的兼容性测试。通过修改 Android 系统的构建文件,可以轻松实现这个目的。本文将介绍如何在 Android 源码中快速更改系统版本号。 步骤一:修改 sysprop.mk 首先,我们需…

C++ 虚函数问题理解[虚函数指针位于内存哪里]

虚函数是我们在C开发中最基本的多态中 常用的东西那么对于以下代码看看是否有哪些问题呢? class Base { public:virtual void foo() {printf("Base foo\n");} };void overwriteVtable() {Base obj;memset(&obj, 0, sizeof(obj)); obj.foo(); } 现在大家应该…

用Python将Office文档(Word、Excel、PowerPoint)批量转换为PDF

在处理不同格式的Office文档&#xff08;如Word、Excel和PowerPoint&#xff09;时&#xff0c;将其转换为PDF格式是常见的需求。这种转换不仅确保了文件在不同设备和操作系统间的一致性显示&#xff0c;而且有助于保护原始内容不被轻易修改&#xff0c;非常适合于正式报告、提…

初识jsp

学习本章节前建议先安装Tomcat web服务器&#xff1a;tomcat下载安装及配置教程_tomcat安装-CSDN博客 1、概念 我的第一个JSP程序&#xff1a; 在WEB-INF目录之外创建一个index.jsp文件&#xff0c;然后这个文件中没有任何内容。将上面的项目部署之后&#xff0c;启动服务器…

Java八股文-Mysql

Mysql&#xff1a; 1.Mysql数据库索引的类型有哪些&#xff1f; 普通索引唯一索引主键索引全文索引组合索引 2.主键索引&#xff0c;唯一索引区别&#xff1a; 唯一索引列允许空值&#xff0c;而主键列不允许空值 &#xff08;MySQL 允许在唯一索引列中包含多个 NULL 值&am…

python-PyQt项目实战案例:制作一个视频播放器

文章目录 1. 关键问题描述2. 通过OpenCV读取视频/打开摄像头抓取视频3. 通过PyQt 中的 QTimer定时器实现视频播放4. PyQt 视频播放器实现代码参考文献 1. 关键问题描述 在前面的文章中已经分享了pyqt制作图像处理工具的文章&#xff0c;也知道pyqt通过使用label控件显示图像的…

RK3588开发笔记-麦克风阵列多pdm通道合并成一个声卡

目录 前言 一、RK3588音频架构概述 二、PDM简介 PDM基本原理 PDM的工作流程 PDM接口信号 三、原理图连接 四、设备树配置 五、设备调试 总结 前言 在音频设备的开发中,特别是在多通道音频数据处理场景中,如何将多个PDM(Pulse Density Modulation)通道整合成一个声卡…