CSDN话题挑战赛第2期
参赛话题:学习笔记
Web APIs基础学习三
在上一章中主要学习了关于 事件监听 的处理问题,感兴趣的小伙伴可以回顾一下 Web前端系列技术之Web APIs基础(从基础开始)② 中所介绍的内容;
在学习完事件监听之后,使用事件监听处理对应的DOM对象是项目开发过程中实现用户交互必不可少的操作,例如 动态创建用户评论区 ;当然这里所要实现的功能就不仅仅是要使用到事件侦听操作了,还需要动态的创建实现评论区所用到的标签元素以及评论时间,那么这里就需要学到关于 ==DOM节点操作==以及 时间对象 的知识;
那么今天主要介绍的内容就是:
一、节点操作
二、时间对象
三、重绘与重排(回流)
四、评论区案例
文章目录
一、节点操作
基础理解: 此处所指的节点指的是 DOM节点;在之前学习到过 DOM树 ;那么结合着树的结构,可以知道在树中的每一个点位都被称为 节点 ,同样,这里的DOM树种所包含的每一个内容便都可以称之为 DOM节点,在对于这些节点的操作过程种,主要也就分为增、删、改、查四种操作方式,
一般情况下,增、删、查是用到最多的;
1. DOM节点
节点与节点之间也会有所不同,主要划分的节点类型为三类,当然也有其他的,因为项目开发的过程中并不常用,所以这里就不做过多的赘述了:
- 元素节点(重点): 所有的标签,比如
body
、div
等,其中html
属于根节点; - 属性节点: 所有的属性 比如 href、id等
- 文本节点: 所有的文本
- 其他
⭐注意:元素节点是一个极其重要的节点内容,它可以更好的让我们理清标签元素之间的关系;
2. 查找节点
所谓的查找节点操作,主要是依赖于节点之间的关系实现查找,在DOM节点的关系中,被划分成了三类:父节点、子节点 和 兄弟节点,以便于查找到节点内容;
2.1 父节点查找
基础语法结构:
子元素.parentNode
⭐注意:
parentNode
是属性,而非方法- 返回 最近一级的父节点 找不到返回为
null
2.2 子节点查查找
在子节点查找中,主要分为两种方法;
基础语法结构:
//方法一(了解);
父元素.childNodes
//方法二(重点):
父元素.children
⭐注意:
childNodes
获得所有子节点、包括文本节点(空格、换行)、注释节点等;children
仅获得所有元素节点,返回的还是一个伪数组(重点);
2.3. 兄弟节点查找
在兄弟节点查找中,主要分为两种情况:
基础语法结构:
//下一个兄弟节点
元素.nextElementSibling
//上一个兄弟节点
元素.previousElementSibling
⭐注意:
nextElementSibling
和
previousElementSibling
都属于属性;
3. 增加节点
在项目的开发的过程中,很多功能都需要实现标签的动态添加,例如,评论区功能 ;不过,在实现增加节点的过程中,往往分为两步开发:
① 创建一个新的节点;
② 把创建的新的节点放入到指定的元素内部;
3.1 创建节点
基础概念: 即创造出一个新的网页元素,再添加到网页内,一般先创建节点,然后插入节点;
基础语法结构:
//属于一个方法
document.createElement('标签名')
⭐注意:这里需要写的是标签名,因为要创建的是标签
3.2 追加节点
基础概念: 如果需要在界面有所呈现,那就需要将创建好的标签插入到某个父元素中,这里又分为两种情况:
① 插入到父元素的最后一个子元素:
父元素.appendChild(要插入的元素)
② 插入到父元素中某个子元素的前面:
父元素.insertBefore(要插入的元素, 在哪个元素的前面)
⭐注意:此处该如何定义元素的位置呢?利用父查子生成的伪数组查询下标的方式插入;
父元素.children[i]
3.3 克隆节点
特殊情况下,新增节点也可以通过克隆的方式进行添加,主要操作如下:
- 复制一个原有的节点
- 把复制的节点放入到指定的元素内部
基础语法结构:
//克隆一个已有的元素节点
元素.cloneNode(布尔值)
⭐注意:
cloneNode
会克隆出一个跟原标签一样的元素,括号内传入布尔值:
- 若为true,则代表克隆时会包含后代节点一起克隆
- 若为false,则代表克隆时不包含后代节点
- 默认为false
4. 删除节点
若一个节点在页面中已不需要时,可以删除它,在JavaScript 原生DOM操作 中,要删除元素必须通过父元素删除;
基础语法结构:
父元素.removeChild(要删除的元素)
⭐注意:
- 如不存在父子关系则删除不成功;
- 删除节点 和 隐藏节点(
display:none
) 有区别的: 隐藏节点还是存在的,但是删除,则从html中删除节点;
二、时间对象
基础概念: 用来表示时间的对象,通常用来得到当前系统时间;但是在创建时间对象的时候,需要进行 实例化;
基本语法结构:
//获取当前时间let date =newDate()//获取指定时间let date =newDate(2022-09-17)
效果如下:
⭐注意:在创建时间对象的时候,需要用到
new
关键字来进行实例化操作,这里涉及到了构造函数的用法,后期会详细介绍的
1. 时间对象方法
由于时间对象所返回的数据并不能直接被使用,所以需要转换为实际开发中常用的格式,具体如表所示:
方法作用说明getFullYear()获得年份获取四位年份getMonth()获得月份取值为 0 ~ 11getDate()获取月份中的每一天不同月份取值也不相同getDay()获取星期取值为 0 ~ 6getHours()获取小时取值为 0 ~ 23getMinutes()获取分钟取值为 0 ~ 59getSeconds()获取秒取值为 0 ~ 59
代码样例如下:
//获取元素let div = document.querySelector('div')// 防止留白getime()//获取当前时间functiongetime(){let dt =newDate()let year = dt.getFullYear()let month = dt.getMonth()let date = dt.getDate()let hours = dt.getHours()let minute = dt.getMinutes()let second = dt.getSeconds()let arr =['星期日','星期一','星期二','星期三','星期四','星期五','星期六']let day = dt.getDay()//补零
hours<10?hours+='0':hours
minute<10?minute+='0':minute
second<10?second+='0':second
// 设置内容
div.innerHTML =`现在的北京时间${year}年${month}月${date}日${hours}点${minute}分${second}秒 ${arr[day]}`}// 定时器setInterval(getime,1000)
具体效果:
⭐注意: 当然,在项目开发的过程中,显示时间的功能还是有很多需要注意的地方:
- 在获取月份的过程中,由于
getMonth()
的取值范围为0~11
,所以在开发的过程中,需要将该函数方法进行优化 =>getMonth()+1
- 页面所要呈现的时间是动态跳动的,所要需要将获取的时间对象写进定时器中,并设定每隔1s自动刷新一次
- 在调用定时器的时候,页面调用的第一秒会产生留白,那么主要原因的就是定时器延迟了一秒才开始运行,那么最好的解决方法就是根据程序的执行顺序,先去调用一次时间函数,再紧接着使用定时器
2. 时间戳
什么是时间戳?是指 1970年01月01日00时00分00秒起 至 现在 的 总毫秒数 ,它是一种特殊的计量时间的方式;
时间戳的作用:常用于编写倒计时功能;
获取时间戳的三种方式:
- 使用
getTime()
方法
//1. 实例化let date =newDate()//2. 获取时间戳
console.log(date.getTime())
- 简写
+new Date()
(更常用)
console.log(+newDate())
- 使用
Date.now()
console.log(Date.now())
⭐注意:
+new Date()
的使用方法中,前面的加号相当于一个 正号,用来转换成数字型的Date.now()
的使用方法中,无需实例化,但是只能得到当前的时间戳, 而前面两种是可以返回指定时间的时间戳
3. 时间转换公式(拓展)
因为通过时间戳得到是总毫秒数,所以要想呈现出正常的时间格式,就需要先转换为秒再计算;
- 总秒数 = 总毫秒数 / 1000
时间转换:
- 计算天数:d = parseInt(总秒数/ 60/60 /24);
- 计算小时:h = parseInt(总秒数/ 60/60 %24);
- 计算分数:m = parseInt(总秒数 /60 %60 );
- 计算当前秒数:s = parseInt(总秒数%60);
三、重绘与重排(回流)
在了解 重绘和重排(回流) 之前,需要先了解浏览器是如何进行界面渲染的,如下图所示:
- 解析(Parser)HTML,生成DOM树(DOM Tree) ;
- 同时解析(Parser) CSS,生成样式规则 (Style Rules);
- 根据DOM树和样式规则,生成渲染树(Render Tree);
- 进行布局 **Layout(回流/重排)**:根据生成的渲染树,得到节点的几何信息(位置,大小);
- 进行绘制 **Painting(重绘)**:根据计算和获取的信息进行整个页面的绘制;
- Display: 展示在页面上;
1. 重绘
由于节点(元素)的 样式 的 改变 并 不影响 它在文档流中的 位置 和 文档布局 时(比如:
color
、
background-color
、
outline
等), 称为 重绘。
2. 重排(回流)
当 Render Tree 中部分或者全部元素的 尺寸 、结构 、布局 等发生改变时,浏览器就会重新渲染部分或全部文档的过程称为 重排(回流)。
⭐注意:
- outline不会撑大盒子,所以设置outline是会导致重绘的;
- 重绘不一定引起回流,而回流一定会引起重绘
3. 场景举例
会导致回流(重排)的操作:
- 页面的首次刷新;
- 浏览器的窗口大小发生改变;
- 元素的大小或位置发生改变;
- 改变字体的大小;
- 内容的变化(如:input框的输入,图片的大小);
- 激活css伪类 (如::hover) 脚本操作DOM(添加或者删除可见的DOM元素);
简单理解:影响到布局了,就会有重排(回流)
四、评论区案例
具体代码:
<!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"/><metaname="viewport"content="width=device-width, initial-scale=1.0"/><metahttp-equiv="X-UA-Compatible"content="ie=edge"/><title>微博发布</title><style>*{margin: 0;padding: 0;}ul{list-style: none;}.w{width: 900px;margin: 0 auto;}.controls textarea{width: 878px;height: 100px;resize: none;border-radius: 10px;outline: none;padding-left: 20px;padding-top: 10px;font-size: 18px;}.controls{overflow: hidden;}.controls div{float: right;}.controls div span{color: #666;}.controls div .useCount{color: red;}.controls div button{width: 100px;outline: none;border: none;background:rgb(0, 132, 255);height: 30px;cursor: pointer;color: #fff;font: bold 14px '宋体';transition: all 0.5s;}.controls div button:hover{background:rgb(0, 225, 255);}.controls div button:disabled{background:rgba(0, 225, 255, 0.5);}.contentList{margin-top: 50px;}.contentList li{padding: 20px 0;border-bottom: 1px dashed #ccc;position: relative;}.contentList li .info{position: relative;}.contentList li .info span{position: absolute;top: 15px;left: 100px;font: bold 16px '宋体';}.contentList li .info p{position: absolute;top: 40px;left: 100px;color: #aaa;font-size: 12px;}.contentList img{width: 80px;border-radius: 50%;}.contentList li .content{padding-left: 100px;color: #666;word-break: break-all;}.contentList li .the_del{position: absolute;right: 0;top: 0;font-size: 28px;cursor: pointer;}</style></head><body><divclass="w"><divclass="controls"><imgsrc="./images/9.6/tip.png"alt=""/><br/><!-- maxlength 可以用来限制表单输入的内容长度 --><textareaplaceholder="说点什么吧..."id="area"cols="30"rows="10"maxlength="200"></textarea><div><spanclass="useCount"id="useCount">0</span><span>/</span><span>200</span><buttonid="send">发布</button></div></div><!-- 内容列表 --><divclass="contentList"><ulid="list"></ul></div></div><script>// 模拟数据let dataArr =[{uname:'司马懿',imgSrc:'./images/9.5/01.jpg'},{uname:'女娲',imgSrc:'./images/9.5/02.jpg'},{uname:'百里守约',imgSrc:'./images/9.5/03.jpg'},{uname:'亚瑟',imgSrc:'./images/9.5/04.jpg'},{uname:'虞姬',imgSrc:'./images/9.5/05.jpg'},{uname:'张良',imgSrc:'./images/9.5/06.jpg'},{uname:'安其拉',imgSrc:'./images/9.5/07.jpg'},{uname:'李白',imgSrc:'./images/9.5/08.jpg'},{uname:'阿珂',imgSrc:'./images/9.5/09.jpg'},{uname:'墨子',imgSrc:'./images/9.5/10.jpg'},{uname:'鲁班',imgSrc:'./images/9.5/11.jpg'},{uname:'嬴政',imgSrc:'./images/9.5/12.jpg'},{uname:'孙膑',imgSrc:'./images/9.5/13.jpg'},{uname:'周瑜',imgSrc:'./images/9.5/14.jpg'},{uname:'老夫子',imgSrc:'./images/9.5/15.jpg'},{uname:'狄仁杰',imgSrc:'./images/9.5/16.jpg'},{uname:'扁鹊',imgSrc:'./images/9.5/17.jpg'},{uname:'马可波罗',imgSrc:'./images/9.5/18.jpg'},{uname:'露娜',imgSrc:'./images/9.5/19.jpg'},{uname:'孙悟空',imgSrc:'./images/9.5/20.jpg'},{uname:'黄忠',imgSrc:'./images/9.5/21.jpg'},{uname:'百里玄策',imgSrc:'./images/9.5/22.jpg'},]// 需求1:检测用户输入字数// 1. 注册input事件// 2. 将文本的内容的长度赋值给对应的数值// 3. 表单的maxlength属性可以直接限制在200个数之间let textarea = document.querySelector('textarea')let useCount = document.querySelector('.useCount')// 发布按钮let send = document.querySelector('#send')let ul = document.querySelector('#list')
textarea.addEventListener('input',function(){
useCount.innerHTML =this.value.length
})// 需求2: 输入不能为空// 点击button之后判断// 判断如果内容为空,则提示不能输入为空, 并且直接return 不能为空// 防止输入无意义空格, 使用字符串.trim()去掉首尾空格// 并将表单的value值设置为空字符串// 同时下面红色为设置为0
send.addEventListener('click',function(){if(textarea.value.trim()===''){
textarea.value =''
useCount.innerHTML =0returnalert('内容不能为空')}// 随机数functiongetRandom(min, max){return Math.floor(Math.random()*(max - min +1))+ min
}let random =getRandom(0, dataArr.length -1)// 需求3: 新增留言 写到send 的里面// 创建一个小li,然后里面通过innerHTML追加数据let li = document.createElement('li')// 随机获取数据数组里面的内容, 替换newNode的图片和名字以及留言内容//img图片中,动态添加链接的时候,就不要写/>中的/了,因为会改变图片地址
li.innerHTML =`
<div class="info">
<img class="userpic" src=${dataArr[random].imgSrc}>
<span class="username">${dataArr[random].uname}</span>
<p class="send-time"> ${newDate().toLocaleString()} </p>
</div>
<div class="content">${textarea.value}</div>
<span class="the_del">X</span>`// 需求4:删除留言 放到追加的前面// 在事件处理函数里面获取点击按钮, 注册点击事件// 必须在事件里面获取, 外面获取不到// 删除对应的元素(通过this获取对应的那条需要删除的元素)// 放到追加进ul的前面,这样创建元素的同时顺便绑定了事件,方便后续删除留言// 使用 li.querySelector()let del = li.querySelector('.the_del')
del.addEventListener('click',function(){// 删除操作 点击的是X 删除的小li 父元素.removeChild(子元素)
ul.removeChild(li)})// 利用时间对象将时间动态化new Date().toLocaleString()// 追加给 ul 用 父元素.insertBefore(子元素, 那个元素的前面)
ul.insertBefore(li, ul.children[0])// 需求5:重置// 将表单域内容重置为空// 将userCount里面的内容重置为0
textarea.value =''
useCount.innerHTML =0})</script></body></html>
具体效果:
总结
今天是继续学习Web APIs的第三天,内容不多,但练习极为重要,今天所总结出来的所有知识,希望对大家有用,同时也希望这篇文章可以有一个好的展现量和得到更多人的支持,谢谢每一位浏览文章的人,要相信小柴码文,必是好文,欢迎各位 点赞+收藏+关注 啦! ! !
以上就是所要介绍的Web APIs基础学习的第三节内容,后续即将更新前端开发的学习目标。感谢关注和支持,让我们一起成长!
有兴趣可回顾一下JavaScript基础学习的文章内容,再结合之前所介绍的CSS基础学习以及HTML基础学习,大脑里的内容会更加丰富而充实的,毕竟综合性复习和学习是更会加深印象的哟!!!
版权归原作者 小柴爱程序 所有, 如有侵权,请联系我们删除。