• Web前端系列技术之Web APIs基础(从基础开始)③


    CSDN话题挑战赛第2期
    参赛话题:学习笔记

    Web APIs基础学习三

    在上一章中主要学习了关于 事件监听 的处理问题,感兴趣的小伙伴可以回顾一下 Web前端系列技术之Web APIs基础(从基础开始)② 中所介绍的内容;

    在学习完事件监听之后,使用事件监听处理对应的DOM对象是项目开发过程中实现用户交互必不可少的操作,例如 动态创建用户评论区 ;当然这里所要实现的功能就不仅仅是要使用到事件侦听操作了,还需要动态的创建实现评论区所用到的标签元素以及评论时间,那么这里就需要学到关于 ==DOM节点操作==以及 时间对象 的知识;

    那么今天主要介绍的内容就是:
    一、节点操作
    二、时间对象
    三、重绘与重排(回流)
    四、评论区案例



    一、节点操作

    基础理解: 此处所指的节点指的是 DOM节点;在之前学习到过 DOM树 ;那么结合着树的结构,可以知道在树中的每一个点位都被称为 节点 ,同样,这里的DOM树种所包含的每一个内容便都可以称之为 DOM节点,在对于这些节点的操作过程种,主要也就分为四种操作方式,

    一般情况下,是用到最多的;

    1. DOM节点

    节点与节点之间也会有所不同,主要划分的节点类型为三类,当然也有其他的,因为项目开发的过程中并不常用,所以这里就不做过多的赘述了:

    1. 元素节点(重点) 所有的标签,比如 bodydiv等,其中html 属于根节点;
    2. 属性节点 所有的属性 比如 href、id等
    3. 文本节点 所有的文本
    4. 其他

    在这里插入图片描述

    ⭐注意:元素节点是一个极其重要的节点内容,它可以更好的让我们理清标签元素之间的关系;

    2. 查找节点

    所谓的查找节点操作,主要是依赖于节点之间的关系实现查找,在DOM节点的关系中,被划分成了三类:父节点子节点兄弟节点,以便于查找到节点内容;

    2.1 父节点查找

    基础语法结构:

    子元素.parentNode
    
    • 1

    ⭐注意:

    1. parentNode 是属性,而非方法
    2. 返回 最近一级的父节点 找不到返回为 null

    2.2 子节点查查找

    在子节点查找中,主要分为两种方法;

    基础语法结构:

    //方法一(了解);
    父元素.childNodes
    
    //方法二(重点):
    父元素.children
    
    • 1
    • 2
    • 3
    • 4
    • 5

    ⭐注意:

    • childNodes 获得所有子节点、包括文本节点(空格、换行)、注释节点等;
    • children 仅获得所有元素节点,返回的还是一个伪数组(重点);

    2.3. 兄弟节点查找

    在兄弟节点查找中,主要分为两种情况:

    基础语法结构:

    //下一个兄弟节点
    元素.nextElementSibling
    //上一个兄弟节点
    元素.previousElementSibling
    
    • 1
    • 2
    • 3
    • 4

    ⭐注意: nextElementSiblingpreviousElementSibling 都属于属性;

    3. 增加节点

    在项目的开发的过程中,很多功能都需要实现标签的动态添加,例如,评论区功能 ;不过,在实现增加节点的过程中,往往分为两步开发:
    ① 创建一个新的节点;
    ② 把创建的新的节点放入到指定的元素内部;

    3.1 创建节点

    基础概念: 即创造出一个新的网页元素,再添加到网页内,一般先创建节点,然后插入节点;

    基础语法结构:

    //属于一个方法
    document.createElement('标签名')
    
    • 1
    • 2

    ⭐注意:这里需要写的是标签名,因为要创建的是标签

    3.2 追加节点

    基础概念: 如果需要在界面有所呈现,那就需要将创建好的标签插入到某个父元素中,这里又分为两种情况:

    ① 插入到父元素的最后一个子元素:

    父元素.appendChild(要插入的元素)
    
    • 1

    ② 插入到父元素中某个子元素的前面:

    父元素.insertBefore(要插入的元素, 在哪个元素的前面)
    
    • 1

    ⭐注意:此处该如何定义元素的位置呢?利用父查子生成的伪数组查询下标的方式插入;父元素.children[i]

    3.3 克隆节点

    特殊情况下,新增节点也可以通过克隆的方式进行添加,主要操作如下:

    1. 复制一个原有的节点
    2. 把复制的节点放入到指定的元素内部

    基础语法结构:

    //克隆一个已有的元素节点
    元素.cloneNode(布尔值)
    
    • 1
    • 2

    ⭐注意:cloneNode会克隆出一个跟原标签一样的元素,括号内传入布尔值:

    • 若为true,则代表克隆时会包含后代节点一起克隆
    • 若为false,则代表克隆时不包含后代节点
    • 默认为false

    4. 删除节点

    若一个节点在页面中已不需要时,可以删除它,在JavaScript 原生DOM操作 中,要删除元素必须通过父元素删除;

    基础语法结构:

    父元素.removeChild(要删除的元素)
    
    • 1

    ⭐注意:

    1. 如不存在父子关系则删除不成功;
    2. 删除节点隐藏节点display:none) 有区别的: 隐藏节点还是存在的,但是删除,则从html中删除节点;

    二、时间对象

    基础概念: 用来表示时间的对象,通常用来得到当前系统时间;但是在创建时间对象的时候,需要进行 实例化

    基本语法结构:

    //获取当前时间
    let date = new Date()
    
    //获取指定时间
    let date = new Date(2022-09-17)
    
    • 1
    • 2
    • 3
    • 4
    • 5

    效果如下:
    在这里插入图片描述

    ⭐注意:在创建时间对象的时候,需要用到 new 关键字来进行实例化操作,这里涉及到了构造函数的用法,后期会详细介绍的

    1. 时间对象方法

    由于时间对象所返回的数据并不能直接被使用,所以需要转换为实际开发中常用的格式,具体如表所示:

    方法作用说明
    getFullYear()获得年份获取四位年份
    getMonth()获得月份取值为 0 ~ 11
    getDate()获取月份中的每一天不同月份取值也不相同
    getDay()获取星期取值为 0 ~ 6
    getHours()获取小时取值为 0 ~ 23
    getMinutes()获取分钟取值为 0 ~ 59
    getSeconds()获取秒取值为 0 ~ 59

    代码样例如下:

    //获取元素
    let div = document.querySelector('div')
    
    // 防止留白
    getime()
    
     //获取当前时间
     function getime() {
          let dt = new Date()
          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)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    具体效果:
    在这里插入图片描述

    ⭐注意: 当然,在项目开发的过程中,显示时间的功能还是有很多需要注意的地方:

    1. 在获取月份的过程中,由于 getMonth() 的取值范围为 0~11 ,所以在开发的过程中,需要将该函数方法进行优化 => getMonth()+1
    2. 页面所要呈现的时间是动态跳动的,所要需要将获取的时间对象写进定时器中,并设定每隔1s自动刷新一次
    3. 在调用定时器的时候,页面调用的第一秒会产生留白,那么主要原因的就是定时器延迟了一秒才开始运行,那么最好的解决方法就是根据程序的执行顺序,先去调用一次时间函数,再紧接着使用定时器

    2. 时间戳

    什么是时间戳?是指 1970年01月01日00时00分00秒起现在总毫秒数 ,它是一种特殊的计量时间的方式;

    时间戳的作用:常用于编写倒计时功能;

    获取时间戳的三种方式:

    1. 使用 getTime() 方法
    //1. 实例化
    let date = new Date()
    //2. 获取时间戳
    console.log(date.getTime())
    
    • 1
    • 2
    • 3
    • 4
    1. 简写 +new Date()(更常用)
    console.log(+new Date())
    
    • 1
    1. 使用 Date.now()
    console.log(Date.now())
    
    • 1

    ⭐注意:

    • +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. 重绘

    由于节点(元素)的 样式改变不影响 它在文档流中的 位置文档布局 时(比如:colorbackground-coloroutline等), 称为 重绘

    2. 重排(回流)

    当 Render Tree 中部分或者全部元素的 尺寸结构布局 等发生改变时,浏览器就会重新渲染部分或全部文档的过程称为 重排(回流)

    ⭐注意:

    1. outline不会撑大盒子,所以设置outline是会导致重绘的;
    2. 重绘不一定引起回流,而回流一定会引起重绘

    3. 场景举例

    会导致回流(重排)的操作:

    • 页面的首次刷新;
    • 浏览器的窗口大小发生改变;
    • 元素的大小或位置发生改变;
    • 改变字体的大小;
    • 内容的变化(如:input框的输入,图片的大小);
    • 激活css伪类 (如::hover)  脚本操作DOM(添加或者删除可见的DOM元素);

    简单理解:影响到布局了,就会有重排(回流)


    四、评论区案例

    具体代码:

    DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8" />
      <meta name="viewport" content="width=device-width, initial-scale=1.0" />
      <meta http-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>
      <div class="w">
        <div class="controls">
          <img src="./images/9.6/tip.png" alt="" /><br />
          
          <textarea placeholder="说点什么吧..." id="area" cols="30" rows="10" maxlength="200">textarea>
          <div>
            <span class="useCount" id="useCount">0span>
            <span>/span>
            <span>200span>
            <button id="send">发布button>
          div>
        div>
        
        <div class="contentList">
          <ul id="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 = 0
            return alert('内容不能为空')
          }
          // 随机数
          function getRandom(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 = `
           
    ${dataArr[random].imgSrc}> ${dataArr[random].uname}

    ${new Date().toLocaleString()}

    ${textarea.value}
    X
    `
    // 需求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>
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210

    具体效果:

    在这里插入图片描述


    总结

    今天是继续学习Web APIs的第三天,内容不多,但练习极为重要,今天所总结出来的所有知识,希望对大家有用,同时也希望这篇文章可以有一个好的展现量和得到更多人的支持,谢谢每一位浏览文章的人,要相信小柴码文,必是好文,欢迎各位 点赞+收藏+关注 啦! ! !


    以上就是所要介绍的Web APIs基础学习的第三节内容,后续即将更新前端开发的学习目标。感谢关注和支持,让我们一起成长!

    有兴趣可回顾一下JavaScript基础学习的文章内容,再结合之前所介绍的CSS基础学习以及HTML基础学习,大脑里的内容会更加丰富而充实的,毕竟综合性复习和学习是更会加深印象的哟!!!

  • 相关阅读:
    五、线程池和定时器
    神经网络算法简单例子,图神经网络推荐算法
    Spring Cloud(Spring全家桶)
    .NET MVC第三章、三种传值方式
    Mysql的安装配置教程(详细)
    张量-算术操作函数
    CTF常见编码及加解密(超全)第二篇
    ActiViz中不规则网络数据体绘制技术介绍
    【面试题】- Docker
    神经网络常见评价指标AUROC(AUC-ROC)、AUPR(AUC-PR)
  • 原文地址:https://blog.csdn.net/IAMLSD550/article/details/126903740