webAPI-DOM-节点操作

回顾

  • 函数表达式:let fn = function(){} 和传统函数声明调用都是一样fn()【先声明,再调用】
  • 自调用函数 :
  1. (function(){
  2. // 为了防止变量污染;(函数内部变量,外面是用不了!)
  3. })();
  • 回调函数:

    • 当一个函数(回调函数)被作为参数传入另外一个函数的时候。
    • 回:回头才调用,未来才会执行;dom.addEventListener(“click”,回调函数)
  • 事件级别:

    • 发展历程

      • L0 :dom.on事件类型= 事件执行函数;
      • L1:推出个标准,没有具体代码模型;
      • L2:dom.addEventListener("事件类型",回调函数,false)
      • L3:添加新的事件类型、鼠标事件、键盘事件、表达
    • L0 L2:

      • 注册:L0多次注册同样事件类型,被覆盖!L2不会被覆盖
      • 移除:确认不需要dom具有某个事件,L0:dom.on事件类型 = null; L2:dom.removeEventListener("事件类型",函数名)
  • L3鼠标事件:

    • mouseover:移入
    • mouseout:移出
    • mousemove:移动;给谁注册?在页面或者文档上移动:document;

      • 事件对象:把用户的一次行为看做一个对象;对象获取鼠标位置
      • 语法:

        • 1.形参e;
        • 2.坐标:e.pageX 页面左上角 e.clientX 窗口左上角 e.offsetX 当前dom节点左上角
    • mousedown:落下
    • mouseup:弹起;

目录

递归函数

目标:知道递归函数的本质及特征

  1. **递归**是函数的高级用法,本质上是函数自己调用自己,他的行为非常类似循环学习路径:
  1. 递归函数的介绍
  2. 递归函数的特征

递归函数的介绍

如果一个函数内部调用自己本身,并且通过 条件控制及避免陷入死循环,那么我们称这个函数为递归函数。

  1. 基本使用
  1. function f00(){
  2. console.log('普通函数......');
  3. foo(); //函数内部调用自己
  4. }
  5. //调用函数
  6. foo();
  7. -----------------------------------------------------------
  8. //递归函数;;基本样子,函数内部自己会调用自己配和条件
  9. function fn() {
  10. console.log('你好,128');
  11. fn()
  12. }
  13. fn();
  • 注意:上述代码会导致foo一直重复被调用,会陷入死循环,浏览器会以报错形式终止执行

目标:递归是函数的高级用法,本质上函数自己调用自己,他的行为非常类型循环

  • 递归是要加结束条件

  • 特点:循环执行、自己调用自己,一定退出条件。

    1. //递归函数特点:循环执行 、自己调用自己、一定退出条件;
    2. let i=9; //全局变量,在任务中
    3. function fn(){
    4. i++;//自增1,通过条件控制是否调用自己
    5. if(i<3){
    6. fn();
    7. }
    8. }
    9. fn();

递归函数的特性

目标: 能够说出递归函数的3个特性

  • 递归函数有3个特征

    1. 重复执行
    2. 调用自身
    3. 【必须】要有条件控制,避免死循环
  1. //利用递归要求1~100的和
  2. let s=0;i=0
  3. function foo(){
  4. //条件控制避免陷入死循环
  5. if(i >= 100) return;
  6. i++;
  7. s += 1
  8. foo();//自调用
  9. }
  10. foo();

DOM-节点操作事件流

目标: 掌握元素节点操作, 知道事件执行时的事件流动过程

本次学习元素节点创建、 复制、 插入、 删除等操作的方法, 元素节点的结构关系查找节点, 事件执行时的事件流动过程。

  • 学习路径:

    1. 节点操作
    2. 事件流

节点操作

掌握节点常见的增删改查操作

插入节点

  • 即创造出一个新的网页元素, 再添加到网页内, 一般先创建节点, 然后插入节点

  • 创建元素节点方法:

  • ```javascript //创建一个新的元素节点 document.createElement(‘标签名’) //克隆一个已有的元素节点 元素.cloneNode(布尔值)


//1.创建新节点 // create:创建 // Element:元素对象 // 参数:标签字符串,写一个! // 返回:创建出新的dom字点(拥有属性和方法都是学过的!),目前只是存在与js层面,没有在页面中显示 let div = document.createElement(“div”) div.innerText = ‘我是一个新的div’ div.style.backgroundColor = ‘red’ // 2.插入dom节点 //从后添加:父元素节点appendChild(要添加的元素节点); let father = document.querySelector(‘.father’) father.appendChild(div)

  1. -
  2. cloneNode会克隆出一个跟原标签一样的元素, 括号内传入布尔值
  3. 1. 若为true,则代表克隆时会包含后代节点一起克隆
  4. 2. 若为false,则代表克隆时不包含后代节点
  5. 3. 默认为false
  6. ```javascript
  7. // 3.克隆复制节点
  8. // 被克隆元素节点.cloneNode(Boolean值)
  9. // false:不会克隆后代,默认
  10. // true:也会克隆后代
  11. // 得到:dom节点(拥有都是学过属性和方法)
  12. let ul = document.querySelector("ul")
  13. let cp = ul.cloneNode(true);
  • 插入节点

    1. 要想在界面看到, 还得插入到某个父元素中
    2. 插入到父元素的最后一个子元素
    3. 插入到父元素中某个子元素的前面
    1. // 4.指定在某个元素的前面添加
    2. // 父元素的节点:.insertBefore(要添加的元素,添加这个元素的前面)
    3. let p = document.querySelector('p')
    4. father.insertBefore(cp, p)

案例-微博发布
  1. <textarea name="" id="" cols="30" rows="10"></textarea><br>
  2. <button>发布</button>
  3. <ul>
  4. <li>我要发布微博 </li>
  5. </ul>
  6. <script>
  7. //需求:用户输入内容后,点击发布按钮,UL列表里边有发布内容显示
  8. // 步骤:
  9. // 1.获取DOM节点
  10. let btn = document.querySelector("button")
  11. let ipt = document.querySelector("textarea")
  12. // 2.添加事件
  13. btn.addEventListener("click", function () {
  14. //用户点击后,获取输入框的内容
  15. let value = ipt.value //点播
  16. //把获取的内容,添加到一个新的dom里面,创建li
  17. let li = document.createElement("li")
  18. li.innerText = value;
  19. //把新的dom添加到UL后面
  20. let ul = document.querySelector("ul")
  21. ul.appendChild(li);
  22. ipt.value = ' ';
  23. if (li = 'none') {
  24. alert('请输入内容')
  25. }
  26. })
  27. </script>

删除节点

  • 若一个节点在页面中已不需要时, 可以删除它

  • 在 JavaScript 原生DOM操作中, 要删除元素必须通过父元素删除

  • 语法:父元素.removeChold(要删除的元素)

  • 注: 如不存在父子关系则删除不成功

    1. <ul>
    2. <li>1</li>
    3. <li>2</li>
    4. <li class="last">3</li>
    5. </ul>
    6. <script>
    7. //删除点:
    8. // 父元素节点.removeChild(被删除的元素节点)
    9. let ul = document.querySelector("ul")
    10. let last = document.querySelector('.last')
    11. ul.removeChild(last);
    12. </script>

替换节点

  • 替换节点是指把一个已经存在页面中的元素替换成新的元素

  • 方法一语法:

    • 父元素.replaceChild(新节点,被替换节点)
  • 方法二语法:

    • 父元素.innerHTML=内容
  • 方法二的innerHTML本质上是修改双标签里面的内容, 只不过遇到标签也会解析成元素

    1. // 语法:
    2. // 父元素.replaceChild(新节点,被替换的节点旧);
    3. // 元素:准备3个
    4. let ul = document.querySelector('ul')
    5. let last = document.querySelector('.last')
    6. let div = document.createElement('div')
    7. div.innerText = '我是新的节点'
    8. ul.replaceChild(div, last)
    9. //替换:属性学过 innerHTML
    10. let p = document.querySelector("p")
    11. p.innerHTML = '<h1>128</h1>'

查找节点

  • 父子关系查找:

    1. 获取父节点方法

      • parentNode 属性 返回最近一级的父节点 找不到返回为null
    2. 获取子节点

      • childNodes

        • 获得所有子节点、包括文本节点(空格、换行)、注释节点等
      • children

        • 仅获得所有元素节点 ```javascript //获取接点:获取页面中已经存在的节点,得到节点,通过方法获取; // 节点属性; // 节点添加事件监听; // 操作节点; // 查找节点:得到节点,dom数有父子关系;通过属性获取;

// 获取某个元素的父级节点;子元素.parentNode ====>dom节点(有关dom学习所有知识都看可以用) let li = document.querySelector(‘li’) console.log(li.parentNode.parentNode);

  1. -
  2. 第一个子节点和最后一个子节点
  3. <a name="f08ef9b3"></a>
  4. ##### 案例-变色
  5. ```html
  6. <table>
  7. <tr>
  8. <td width="60">序号</td>
  9. <td>课程名</td>
  10. <td>难度</td>
  11. <td width="80">操作</td>
  12. </tr>
  13. <tr>
  14. <td>1</td>
  15. <td><span>HTML</span></td>
  16. <td>初级</td>
  17. <td><button>变色</button></td>
  18. </tr>
  19. <tr>
  20. <td>2</td>
  21. <td><span>CSS</span></td>
  22. <td>初级</td>
  23. <td><button>变色</button></td>
  24. </tr>
  25. <tr>
  26. <td>3</td>
  27. <td><span>Web APIs</span></td>
  28. <td>中级</td>
  29. <td><button>变色</button></td>
  30. </tr>
  31. </table>
  32. <script>
  33. // 需求:点击每个btn按钮,都需要让其所在整行变色;
  34. // 获取所有按钮
  35. let btn = document.querySelectorAll("tr button")
  36. // 添加点击事件
  37. for (let i = 0; i < btn.length; i++) {
  38. btn[i].addEventListener("click", function () {
  39. this.parentNode.parentNode.style.backgroundColor = 'red'
  40. })
  41. }
  42. </script>
  • 查找兄弟的属性

    • previousSibling

      • 找到上一个兄弟节点,包含文本、注释等节点
    • prevuisElementSibling

      • 找到上一个兄弟元素,只找到元素
    • nextSibling

      • 找到下一个兄弟节点,包含文本、注释等节点
    • nextElementSibling

      • 找到下一个兄弟元素,只找到元素

事件流

  • 学习路径:

    1. 事件流与两个阶段说明
    2. 事件捕获和事件冒泡
    3. 阻止事件流动
    4. 事件委托

事件流与两个阶段说明

能够说出事件流经过的2个阶段

  • 事件流指的是事件完整执行过程中的流动路径
  • 说明: 假设页面里有个div, 当触发事件时, 会经历两个阶段, 分别是捕获阶段、 冒泡阶段

  • 简单来说: 捕获阶段是 从父到子 冒泡阶段是从子到父

事件捕获和事件冒泡

  • 事件冒泡是默认存在的
  • 它指的是: 当一个元素触发事件后, 会依次向上调用所有父级元素的同名事件
  • 事件捕获需要写对应代码才能看到效果
  • 代码: 元素.addEventListener(事件名,回调函数,true)
  • 说明:

    1. addEventListener第三个参数传入true代表是捕获阶段触发(很少使用)
    2. 若传入false代表冒泡阶段触发,默认就是false
    3. 若是用 L0 事件监听,则只有冒泡阶段,没有捕获

阻止事件流动

目标: 能够写出阻止事件流动的代码

  • 因为默认就有冒泡模式的存在, 所以容易导致事件影响到父级元素
  • 若想把事件就限制在当前元素内, 就需要阻止事件流动
  • 阻止事件流动需要拿到事件对象
  • 语法:事件对象.stopPropagation()
  • 此方法可以阻断事件流动传播, 不光在冒泡阶段有效, 捕获阶段也有效
  • 鼠标经过事件:

    • mouseover和mouseont会有冒泡效果
    • mouseenter 和 mouseleave没有冒泡效果(推荐)
  1. <div class="father">
  2. <div class="user"></div>
  3. <div class="set"></div>
  4. </div>
  5. <script>
  6. // 需求:左侧,显示用户功能
  7. // 右侧 显示配置功能
  8. // 中间:显示时间功能
  9. let user = document.querySelector(".user");
  10. user.addEventListener("click", function (e) {
  11. console.log("大儿子,说疼");
  12. //事件对象,阻止冒泡
  13. // Propagation:传播 1
  14. e.stopPropagation();
  15. })
  16. let set = document.querySelector(".set");
  17. set.addEventListener("click", function (e) {
  18. document.write("小儿子喊,舒服")
  19. e.stopPropagation();
  20. });
  21. let father = document.querySelector(".father");
  22. father.addEventListener("click", function (e) {
  23. console.log("父亲打哪个儿子");
  24. e.stopPropagation();
  25. });
  26. // 阻止冒泡:从目标节点--->根节点流动路径,切断!
  27. // 大白话:
  28. </script>

事件委托

目标: 能够说出事件委托的好处

  • 事件委托是利用事件流的特征解决一些开发需求的知识技巧

  • 总结:

    • 事件委托其实是利用事件冒泡的特点,给父级元素加事件
    • 事件对象.target 可以获得真正触发事件的元素

      1. <body>
      2. <div class="box">
      3. <button>1</button>
      4. <button>2</button>
      5. <button>3</button>
      6. <button>4</button>
      7. <button>5</button>
      8. </div>
      9. <script>
      10. let btn = document.querySelectorAll("button")
      11. for (let i = 0; i < btn.length; i++) {
      12. btn[i].addEventListener("click", function () {
      13. // 打印当前文本内容
      14. console.log(this.innerText);
      15. })
      16. }
      17. //优化写法:事件委托,不是直接注册btn;注册给父亲
      18. // 应用场景:遇到给一堆元素注册同样事件类型;全部获取,循环注册!
      19. // 找着堆元素公共级父级,把事件添加给、委托给父亲上,
      20. // 知道用户刚才触发时哪个节点就可以!
      21. /* let box = document.querySelector('.box')
      22. box.addEventListener('click', function (e) {
      23. console.log(e.target.innerText);
      24. }) */
      25. // 好处:只需要注册一个事件
      26. </script>
      27. </body>

事件流小结

  1. 事件流与两个阶段说明

    1. 完整事件的流动过程
    2. 捕获阶段 -> 真正触发事件的元素 -> 冒泡阶段
  2. 事件捕获和事件冒泡

    • 事件捕获是从document一级一级往下到真正触发事件的元素
    • 事件冒泡是从真正触发事件的元素一级一级往上到document
    • 默认就有事件冒泡
    • 捕获必须用L2事件,并第三个参数给true
  3. 阻止事件流动

    • 事件对象.stopPropgation()
  4. 事件委托

    • 利用事件冒泡的特点把事件委托给父级元素

mouseenter和mousemover的区别

  1. <body>
  2. <div class="father">
  3. <div class="son">1</div>
  4. </div>
  5. <script>
  6. // mouseenter / mouseleave鼠标移入移出 focus blur不会冒泡
  7. //大部分都是默认在冒泡阶段执行;
  8. let son = document.querySelector(".son");
  9. son.addEventListener("mouseenter", function () {
  10. console.log("移入了son");
  11. })
  12. let father = document.querySelector(".father");
  13. father.addEventListener("mouseenter", function () {
  14. console.log("移入了father")
  15. })
  16. </script>
  17. </body>

综合案例-表格渲染

  1. <body>
  2. <h3>添加课程</h3>
  3. <div class="con">
  4. 课程名称:<input type="text" class="title"> 课程难度: <input type="text" class="hard">
  5. <button class="add">添加</button>
  6. </div>
  7. <table>
  8. <thead>
  9. <tr>
  10. <th width="80">序号</th>
  11. <th>课程名</th>
  12. <th>难度</th>
  13. <th>操作</th>
  14. </tr>
  15. </thead>
  16. <tbody>
  17. <tr>
  18. <td>1</td>
  19. <td>HTML</td>
  20. <td>初级</td>
  21. <td>
  22. <button>删除</button>
  23. </td>
  24. </tr>
  25. <tr>
  26. <td>2</td>
  27. <td>CSS</td>
  28. <td>初级</td>
  29. <td>
  30. <button>删除</button>
  31. </td>
  32. </tr>
  33. <tr>
  34. <td>3</td>
  35. <td>JavaScript</td>
  36. <td>中级</td>
  37. <td>
  38. <button>删除</button>
  39. </td>
  40. </tr>
  41. </tbody>
  42. </table>
  43. <script>
  44. // -------------------------------------------1.add
  45. // 步骤:
  46. // 1.获取
  47. let add = document.querySelector(".add");
  48. let title = document.querySelector(".title");
  49. let hard = document.querySelector(".hard");
  50. let tbody = document.querySelector("tbody");
  51. // 2.添加点击事件
  52. add.addEventListener("click", function () {
  53. // 3.1 获取用户输入的内容
  54. let kecheng = title.value;
  55. let nandu = hard.value;
  56. // 3.2 先创建某些个dom节点,
  57. let tr = document.createElement("tr");
  58. // 3.3 把内容放入某些dom节点
  59. tr.innerHTML = `<td>${kecheng}</td>
  60. <td>${nandu}</td>
  61. <td>
  62. <button>删除</button>
  63. </td>`;
  64. // 3.4 添加到tbody后面:父级.appendChild(tr)
  65. tbody.appendChild(tr);
  66. // 4.置空
  67. title.value = "";
  68. hard.value = "";
  69. });
  70. // *****************************************************************************删除
  71. // 1.找相对适合父级
  72. tbody.addEventListener("click", function (e) {
  73. // 知道用户点击是哪个类型dom节点
  74. // tr td button e.target.tagName
  75. if (e.target.tagName == "BUTTON") {
  76. let father = e.target.parentNode.parentNode;
  77. tbody.removeChild(father);
  78. }
  79. });
  80. </script>
  81. </body>