当前位置: 首页 > news >正文

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

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

Web APIs基础学习三

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

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

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


文章目录

  • Web APIs基础学习三
  • 一、节点操作
    • 1. DOM节点
    • 2. 查找节点
      • 2.1 父节点查找
      • 2.2 子节点查查找
      • 2.3. 兄弟节点查找
    • 3. 增加节点
      • 3.1 创建节点
      • 3.2 追加节点
      • 3.3 克隆节点
    • 4. 删除节点
  • 二、时间对象
    • 1. 时间对象方法
    • 2. 时间戳
    • 3. 时间转换公式(拓展)
  • 三、重绘与重排(回流)
    • 1. 重绘
    • 2. 重排(回流)
    • 3. 场景举例
  • 四、评论区案例
  • 总结


一、节点操作

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

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

1. DOM节点

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

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

在这里插入图片描述

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

2. 查找节点

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

2.1 父节点查找

基础语法结构:

子元素.parentNode

⭐注意:

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

2.2 子节点查查找

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

基础语法结构:

//方法一(了解);
父元素.childNodes

//方法二(重点):
父元素.children

⭐注意:

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

2.3. 兄弟节点查找

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

基础语法结构:

//下一个兄弟节点
元素.nextElementSibling
//上一个兄弟节点
元素.previousElementSibling

⭐注意: nextElementSiblingpreviousElementSibling 都属于属性;

3. 增加节点

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

3.1 创建节点

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

基础语法结构:

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

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

3.2 追加节点

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

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

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

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

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

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

3.3 克隆节点

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

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

基础语法结构:

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

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

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

4. 删除节点

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

基础语法结构:

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

⭐注意:

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

二、时间对象

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

基本语法结构:

//获取当前时间
let date = new Date()

//获取指定时间
let date = new Date(2022-09-17)

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

⭐注意:在创建时间对象的时候,需要用到 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}秒 &nbsp;&nbsp;&nbsp;${arr[day]}`
}
// 定时器
setInterval(getime, 1000)

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

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

  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. 简写 +new Date()(更常用)
console.log(+new Date())
  1. 使用 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. 重绘

由于节点(元素)的 样式改变不影响 它在文档流中的 位置文档布局 时(比如: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 />
      <!-- maxlength 可以用来限制表单输入的内容长度 -->
      <textarea placeholder="说点什么吧..." id="area" cols="30" rows="10" maxlength="200"></textarea>
      <div>
        <span class="useCount" id="useCount">0</span>
        <span>/</span>
        <span>200</span>
        <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 = `
       <div class="info">
      <img class="userpic" src=${dataArr[random].imgSrc}>
      <span class="username">${dataArr[random].uname}</span>
      <p class="send-time"> ${new Date().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基础学习,大脑里的内容会更加丰富而充实的,毕竟综合性复习和学习是更会加深印象的哟!!!

相关文章:

  • 线段树基本操作——建树+单点修改+区间查询
  • python/php/java/nodejs通讯录管理系统vue+elementui
  • 【老生谈算法】matlab实现蒙特卡罗定积分源码——蒙特卡罗定积分
  • 卷积神经网络 - 从全连接层到卷积
  • selenium爬虫如何绕过反爬,看这一篇文章就足够了
  • c语言进阶:冒泡排序函数初步实现到逐步优化
  • 5年测试经验要个20K不过分吧,谁料面试官三个问题把我打发走了···
  • 内网渗透之Msf-Socks代理实战(CFS三层靶场渗透过程及思路)
  • 命令执行漏洞——远程命令执行
  • M0007 四则运算
  • 【机器学习】李宏毅——生成式对抗网络GAN
  • osi七层模型
  • 【Vue五分钟】五分钟了解webpack的高级概念
  • 【Linux】云服务器的购买与Linux远程连接
  • c++介绍与入门基础(详细总结)
  • [iOS]Core Data浅析一 -- 启用Core Data
  • 【个人向】《HTTP图解》阅后小结
  • Apache Spark Streaming 使用实例
  • JavaScript 是如何工作的:WebRTC 和对等网络的机制!
  • java取消线程实例
  • java中的hashCode
  • jdbc就是这么简单
  • jquery ajax学习笔记
  • Mithril.js 入门介绍
  • mysql常用命令汇总
  • spring security oauth2 password授权模式
  • 回顾2016
  • 前端 CSS : 5# 纯 CSS 实现24小时超市
  • 入门到放弃node系列之Hello Word篇
  • 微信小程序--------语音识别(前端自己也能玩)
  • No resource identifier found for attribute,RxJava之zip操作符
  • Semaphore
  • 不要一棍子打翻所有黑盒模型,其实可以让它们发挥作用 ...
  • #NOIP 2014# day.2 T2 寻找道路
  • (12)Linux 常见的三种进程状态
  • (android 地图实战开发)3 在地图上显示当前位置和自定义银行位置
  • (二) Windows 下 Sublime Text 3 安装离线插件 Anaconda
  • (附源码)springboot家庭财务分析系统 毕业设计641323
  • (更新)A股上市公司华证ESG评级得分稳健性校验ESG得分年均值中位数(2009-2023年.12)
  • (九十四)函数和二维数组
  • (利用IDEA+Maven)定制属于自己的jar包
  • (六)Hibernate的二级缓存
  • (转)Linux整合apache和tomcat构建Web服务器
  • **Java有哪些悲观锁的实现_乐观锁、悲观锁、Redis分布式锁和Zookeeper分布式锁的实现以及流程原理...
  • .mysql secret在哪_MYSQL基本操作(上)
  • .NET 4 并行(多核)“.NET研究”编程系列之二 从Task开始
  • .NET Core 通过 Ef Core 操作 Mysql
  • .NET LINQ 通常分 Syntax Query 和Syntax Method
  • .NET 服务 ServiceController
  • .Net的DataSet直接与SQL2005交互
  • /3GB和/USERVA开关
  • @cacheable 是否缓存成功_Spring Cache缓存注解
  • [ C++ ] STL priority_queue(优先级队列)使用及其底层模拟实现,容器适配器,deque(双端队列)原理了解
  • [Angular 基础] - 指令(directives)
  • [C++]C++类基本语法