【JS进阶知识点】

Web API 导读

APl ( Application Programming Interface 应用程序编程接口 ) 是一些预先定义的函数,目的是提供应用程序与开发人员基于某软件或硬件得以访问一组例程的能力,而又无需访问源码,或理解内部工作机制的细节。

// API是给程序员提供的一种工具,以便能更轻松的实现想要完成的功能

Web API浏览器提供的一套操作浏览器功能和页面元素的API ( BOM 和 DOM )。现阶段我们主要针对于浏览器讲解常用的API,主要针对浏览器做交互效果。

// 将js实现的功能给予 Web API 所获取的标签对象。实现各种界面互动、处理、反馈等相关的操作

所以,我们明白。Web APIs 是浏览器提供的 接口。就像是我们给手机充电,我们不需要知道电流在手机里怎么存储。也不用知道电线运输原理。我们只要关注的是充电口与线的插口是否连接,是否适配。

Web API 接口参考
HTML事件

事件组成

事件由 事件源 事件类型 事件处理程序 三部分组成

JavaScript使我们有能力创建动态页面,而事件是可以被JavaScript侦测到的行为

事件 描述
onchange HTML 元素改变
onscroll HTML 元素被滚动
onclick 鼠标点击左键后触发
onmouseover 鼠标经过触发(会受事件流多次触发)
onmouseenter 鼠标经过触发(只经过自身触发)
onmouseout 鼠标离开触发(会受事件流多次触发)
onmouseleave 鼠标离开触发(只离开自身触发)
onfocus 获得鼠标焦点触发
onblur 失去鼠标焦点触发
onmousedown 鼠标按下触发
onmouseup 鼠标弹起触发
onmousemove 鼠标移动触发
onkeyup 用户松开键盘按键
onload 浏览器已完成页面的加载
input (不兼容IE)输入框内容发生改变时立即触发

传统注册事件

<!– 绑定事件函数 –>
<button onclick=”seyHi()”>说你好</button>
<script>
    //方法1 引用方法
    function seyHi(){
        alert(‘你好’);
    }
    //方法2 注册事件
    let btn = document.querySelector(‘button’);
    btn.onclick = function () {
     alert(‘你好’);
    }
</script>

上述所用到的 onclick 是一个 点击事件 ,当程序捕获 事件源 发生 onclick 事件。将执行 onclick 绑定的 事件处理程序。

// onclick 点击事件 onmouseover 触摸事件 都是 HTML事件;一般都是触发事件=执行方法();

删除事件

element.事件=null;

//这是一个简单直接的删除的方式

//删除元素对象 btn 下 onclick 事件的方法
    btn.onclick = null;

DOM 导读

什么是DOM?

DOMdocument object model)就是文档对象模型,是针对HTML和XML的一个API(应用程序接口)。是W3C组织推荐的处理可扩展标记语言(HTML或XML)的标准编程接口。

DOM可以改变网页的内容、结构、样式

DOM树

当网页被加载时,浏览器会创建页面的文档对象模型(Document Object Model),
HTML DOM 模型被结构化为 对象树

%title插图%num

DOM的用途

DOM 会把网页的所有元素都看为 对象节点。通过这个对象模型,JavaScript 通过DOM可以实现很多功能:

JavaScript 能改变页面中的所有 HTML 元素
JavaScript 能改变页面中的所有 HTML 属性
JavaScript 能改变页面中的所有 CSS 样式
JavaScript 能删除已有的 HTML 元素和属性
JavaScript 能添加新的 HTML 元素和属性
JavaScript 能对页面中所有已有的 HTML 事件作出反应
JavaScript 能在页面中创建新的 HTML 事件

利用 DOM 获取元素

DOM 根据 标签ID 获取

 使用 document.getElementById()  动态获取id下的标签

    <p id="Pid">元素</p>
    <script>
        let Pid = document.getElementById('Pid');
    </script>

DOM 根据 标签名 获取

使用 getElementsByTagName() 方法可以动态返回带有指定标签名的对象的集合

//注意该方法返回的是对象,引用需要附带变量里的对象的成员下标。而不是变量名;

    <h5>你好</h5>
    <h5>HTML</h5>
    <script>
        //获取页面上所有h5标签对象,返回伪数组,动态赋值给变量get
        let get = document.getElementsByTagName('h5');
        console.log(get); //[{<h5>你好</h5>,<h5>HTML</h5>}]
    </script>

DOM 根据 标签类名 获取

使用 getElementsByClassName() 方法可以动态返回指定类名下的 标签对象集合

//注意该方法返回的是对象,引用需要附带变量里的对象的成员下标。而不是变量名;

    <p class="top">你好</p>
    <p class="top">HTML</p>
    <script>
        //获取在CCS类名为 top 下的所有对应标签
        let tops = document.getElementsByClassName('top');
        //以对象名称获取标签
        console.log(tops[0]);  //p.top
        console.log(tops[1]);  //p.top
    </script>

DOM 多类型 指定选择器

使用 querySelector() 返回指定选择器的第一个元素对象

// 该方式简单自由,可采用 #id名 .类名 标签名 或者组合名(如 .sm li 为:sm类下的 第一个 <li>)
// 如若需要获得所有对象,可采用 querySelectorAll()

    <p id="text">你好DOM</p>
    <p class="box">你好HTML</p>
    <span>你好JavaScript</span>
    <script>
        //获取元素id为 text 对应的首个标签元素
        let texts = document.querySelector('#text');
        console.log(texts); //<p id="text">你好DOM</p>
        //获取CSS类为 box 对应的首个标签元素
        let boxs = document.querySelector('.box');
        console.log(boxs); //<p class="box">你好HTML</p>
        //获取标签 span 下的首个标签元素
        let spans = document.querySelector('span');
        console.log(spans); //<span>你好JavaScript</span>
        let all_P = document.querySelectorAll('p');
        console.log(all_P); //获取所有P标签元素,返回一个数组对象
    </script>

DOM 获取 特殊元素 <body> <html>

一个完整的 网页文档 只有一个 <body> 和一个 <html>,所以我们可以用指定的方式提取这两个标签元素

    <script>
        //获取网页<body>下的所有标签元素
        let bodys = document.body;
        //获取<html>整个网页下的所有标签元素
        let HTMLall = document.documentElement;
    </script>

DOM 获取元素 的 补充知识

获取标签不一定只能用 document 作为对象,也可以用 元素 作为对象,提取该 标签元素 下的 标签元素

附上整合实例:改变颜色案例

<ul id="list_1">
    <li>第一元素</li>
    <li>第一元素</li>
    <li>第一元素</li>
</ul>
<ul id="list_2">
    <li>第二元素</li>
    <li>第二元素</li>
    <li>第二元素</li>
</ul>
<script>
    //获取网页文档对象中标签id为 list_1 的元素 返回对象
    let lists=document.getElementById('list_1'); //<ul id="list_1">
    //获取在 list_1对象中 标签名 为 li 的元素 返回对象集合
    let lists_li=lists.getElementsByTagName('li');
    console.log(lists_li); 
</script>
DOM 常用方法

DOM可以改变网页内容、结构和样式,
我们可以利用DOM操作元素来改变元素中的属性和内容。

利用 innerTextinnerHTML,我们可以直接让元素改变内容。

例: Pid.innerText = ‘你好Dart’; //改变内容 不保留空格换行,也不识别右边存在的HTML标签
例: Pid.innerHTML=’你好HTML’; //改变内容,同时转义HTML标签,保留空格换行
*这两个方法不仅可以修改标签内容,还可以读取标签内容并用于赋值;

利用 console.log(”); console.dir(”); 查看所取的元素;

例:console.log(Pid);  //<p id=”Pid” style=”color: #ccc;”>元素</p>
例:console.dir(Pid); //p#Pid

利用 className 可进行 类名操作 和 改变类名;

例:tops[0].className = “bot”; //适用于替换样式较多的标签
//将原下标0位置的成员对应的 ‘top’ class样式引用改为 ‘botclass样式

对象 style 实现行内式css操作,改变标签样式;

例:div.style.width = “200px”;
div.style.backgroundColor=”red”;
//适用于替换样式较少的标签
// 操作属性的时候, 需要用到驼峰格式
//style 对象 实现的效果为行内样式,优先级高,会因此替换原元素类CSS样式

利用 标签自有属性 改变样式;

例:but.onmousedown=function(){
a.href=’https://smmcat.cn’; //此时a标签的href属性动态改变
img.src=”images/1000.png”; //此时img的src属性动态改变
}

利用 表单元素属性 改变表单样式;

表单元素属性 描述
type 样式类型属性
value 值属性
checked 表单选择
disabled 禁用input元素

例:buts[0].onclick=function(){
inputs[0].value=’改变了内容!’; //改变input标签中的值(内容)
this.disabled=true; //该按钮被禁用
check.checked = true; //变量check绑定的单选框被选中
}

排他思想(算法)

排他思想常用于单选内容,让所有相关元素还原后,再改变某元素
(如 内容替换)

点击 按钮,呈现 选中效果。其他未选中按钮 还原

  • 按钮A
  • 按钮B
  • 按钮C
  • 按钮D

  • //该原理为在该目标单击事件响应后,会用 循环 将所有相关元素标签属性重置。最后改变该标签元素


    例:for(let i=0;i<button.length;i++){
    button[i].onclick=function(){
    for(let v=0;button.length;v++){
    button[v].style.backgroundColor="#66ccff";
    //重置所有按钮颜色
    }

    this.style.backgroundColor="brow";
    }
    }

    附上整合实例:表单全选取消全选案例

    自定义属性的操作

    获取标签默认属性值\自定义属性值

    element.属性 //获取属性值(用于默认属性)
    element.className //获取标签类名
    element.getAttribute(“属性”); //获取属性值(用于自定义属性)

    // element.属性 获取内置属性值(元素本身自带的属性)
    // element.getAttribute(); 主要获得自定义属性(标准),也可以获得内置属性
    // 标签用对象获取方式获取class名需要注意为className

    修改标签默认属性值\自定义属性值

    element.属性="值" //赋值或替换对应的属性值(用于默认属性)
    element.className=“类名” //替换标签类名
    element.setAttribute(“属性”,""); //参数左侧的值赋值或替换对应参数右侧属性值(用于自定义属性)

    //如若找不到对应的该目标属性,择新建该属性,并赋值
    // 标签用对象获取方式获取class名需要注意为className

    删除标签默认属性值\自定义属性值

    element.removeAttribute(“属性”); //删除该标签属性

    H5 自定义属性 命名规范

    //因为存在团队协作时无法区分 自定义属性 与 默认属性 的问题;H5提供了新的规范

    <div id="demo" data-index="1" class="box">你好</div> //添加 data- 表示这为自定义属性

    H5 自定义属性 获取方式

    //通过这个规则,搭配H5新增的获取自定义属性的方法 可获取属性该值
    //多个"-"的值,如 data-box-image 需要用驼峰命名 调用 例:div.dataset.boxImage
    //dataset 是存放了 所有 自定义属性 (前缀 data-) 的集合

    <div id="demo" data-index="1" class="box">你好</div>
        <script>
            let div=document.querySelector('div');
            console.log(div.dataset.index);
    //H5新增获取自定义属性方法 dataset
        </script>

    节点概述

    什么是节点

    网页中所有内容都是节点标签、属性、文本、注释等),在DOM中。节点使用node来表示

    HTML DOM树中的所有节点均可通过JavaScript进行访问,所有HTML元素(节点)均可被修改,也可以创建或者删除。

    节点的使用

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

    %title插图%num
    • 元素节点 nodeType 为 1
    • 属性节点 nodeType 为 2
    • 文本节点 nodeType 为 3(文本节点包含文字、空格、换行等)
    获取节点

    *红色标注为该代码存在IE9以下兼容问题

    获取类型 [推荐]获取标签节点 获取标签+文本+属性节点
    获取父级节点 node.parentNode -
    获取子级节点集合 node.children node.childNodes
    获取子级节点首个 node.firstElementChild node.firstChild
    获取子级节点末尾 node.lastElementChild node.lastChild
    获取兄弟上一个节点 node.previousElementSibling node.previousSibling
    获取兄弟下一个节点 node.nextElementSibling node.nextSibling

    获取 元素父级 节点

    利用 element.parentNode 获取父级节点

    //将一个元素作为子级元素节点,可以获取离它最近的父级元素的节点
    //如果该节点没有父级节点则返回为null

    <div class="box">
           
     <span class="imgBox"></span>
        
    </div>
        <script>
            let img_box = document.querySelector('.imgBox'); 
            img_box.parentNode
    //获取img_box的父级 节点 
       </script>

    获取 元素子级 节点集合

    利用 element.children 获取父级节点(非标准)(推荐)

    //element.children(又可叫做 parentNode.children) 返回元素之下最近的所有子元素节点集合。
    //element.children只返回元素节点,其余节点(文本,属性)不获取。解决回车获取问题

     <ul>
            <li></li>
            <li></li>
            <li></li>
        </ul>
        <script>
            let ul = document.querySelector('ul');
            ul.children; //获取ul的子级元素标签集合 [ li, li, li ]
        </script>

    利用 element.childNodes 获取子级节点集合 (不推荐)

    //将一个元素作为父级元素节点,可以获取离它最近的子级元素的节点集合
    //该方法同时也会获得代码书写的文本节点 [回车],返回的集合将附带回车集合,影响使用。一般不提倡使用

        <ul>
            <li></li>
            <li></li>
            <li></li>
        </ul>
        <script>
            let ul = document.querySelector('ul');
            ul.childNodes//获取ul的子级元素所有节点集合 [ text, li, text, li, text, li, text ]
        </script>

    解决 childNodes 会将 text元素 一并获取的 办法

    //for循环依次判断获取的元素是否为元素节点,并对元素节点进行操作

            let ul = document.querySelector('ul');
            console.log(ul);
            for (let i = 0; i < ul.childNodes.length; i++) { 
               //依据类型比较 判断是否为需要的内容
                if (ul.childNodes[i].nodeType == 1) {
                    console.log( ul.childNodes[ i ] );
                 }
            }

    获取 元素 兄弟 节点

    //node.nextSibling ,node.previousSibling 返回当前元素下的一个兄弟节点,找不到返回null。该方法同时也获得文本节点[回车]

    node.nextSibling //获取 同级 元素下一个节点 [#text]
    node.previousSibling //获取 同级 元素上一个节点 [#text]

    // 语句增加 Element 后。返回当前元素下的一个兄弟标签元素节点,找不到返回null。

    //该方法有兼容性问题,IE9以上才支持

    node.nextElementSibling // <p></p>
            node.previousElementSibling // <p></p>

    获取 首尾 第一个元素子级 节点

    【1】利用 element.firstChild 获取父级 首个 子节点

    //firstChild返回第一个子节点。找不到返回null。
    //该方法同时也会获得代码书写的文本节点 [回车],返回的集合将附带回车集合,影响使用。一般不提倡使用

            node.firstChild//获取ul的子级的首个li元素 [ #text ]

    【1】利用 element.lastChild 获取父级 尾个 子节点

            node.lastChild//获取ul的子级的尾个li元素 [ #text ]

    【2】利用 element.firstElementChild 获取父级 首个 元素子节点

    //该方法有兼容性问题,IE9以上才支持

    node.firstElementChild//获取ul的子级的首个li元素 <li>1</li>

    【2】利用 element.lastElementChild 获取父级 尾个 元素子节点

    //该方法有兼容性问题,IE9以上才支持

            node.lastElementChild//获取ul的子级的尾个li元素 <li>3</li>

    操作节点

    创建 标签元素 节点

    我们想要页面添加一个标签元素节点需要的步骤有:
    1.创建 标签元素
    2.添加 标签元素

    创建标签元素节点 node.createElement('标签名');

    //创建标签节点
            let li=document.createElement( 'li' );
    //可直接赋值 该变量存储的标签则为 <li>你好HTML</li>
    li.innerHTML='你好HTML';

    在 父级下 子元素集合 末尾 添加元素节点 node.appendChild(元素节点);

            let ul=document.querySelector('.box');
            //末尾添加 已有 标签节点
            ul.appendChild( li );

    在父级下 指定子元素位置前 添加元素节点 node.insertBefore(元素节点 , 指定子元素);

            //在父级ul节点下的 第一个子元素前添加 li元素
            ul.insertBefore( li,ul.children[0] );

    删除 标签元素 节点

    父级节点 删除 指定位置的子级节点 node.removeChild(子级节点);  

    //删除 父级ul节点下 的 第一个子级标签元素
            ul.removeChild(ul.children[0]);

    复制 标签元素 节点

    复制目标节点并返回该值 node.cloneNode();  

    //如果cloneNode();函数内 为空 或者 false 则为浅拷贝(只复制节点本身,不复制该节点下的子节点)
    //在cloneNode();函数内 为 true 或者任意返回值为 true 的内容。将为 深拷贝 (复制节点内所有内容)

            //深拷贝 复制 目标节点 并赋值给 变量 newli
            let newli = ul.children[0].cloneNode(true);
            //在 父级 ul 下 子元素集合 末尾 添加元素节点
            ul.appendChild(newli);

    插入 HTML/XML 片段

    插入HTML/XML片段到元素的指定位置 node.insertAdjecentHTML(position , text);

    insertAdjacentHTML() 方法是将文本解析为 element 元素,并将结果节点插入到DOM树中的指定位置。
    它不会重新解析它正在使用的元素,因此它不会破坏元素内的现有元素。这避免了额外的序列化步骤,
    使其比直接使用innerHTML操作更快

    // position 参数有 'beforebegin' (元素自身的前面)、'atterbegin' (插入元素内部的第一个子节点之前)、
    '
    beforeend' (插入元素内部的最后一个子节点之后)、'afterend' (元素自身的后面)
    // 该操作比 innerHTML 更高效;相关内容可查阅 博客园CSDN

    let ul = document.querySelector('ul');
    // 在 ul 标签里面的子元素的末尾插入参数二的 HTML 字符串片段
    ul.insertAdjacentHTML('beforeend', '你好');

    附上实例:简单版发布留言案例表格动态生成

    创建元素方法的区别

    doncument.write()

    doncument.write 是直接将内容写入页面的内容流,但是当文档加载完毕后执行,则它会导致页面全部重绘

    //方法一 可用于页面加载前直接将变量的值呈现在页面上 (需在 该方法前已有该变量 否则为空)

    <head>
        let temp='大家好~';
    </head>
    <body>
        <div>
            <script>document.write(temp)</script>
        </div>
    </body>

    //方法二 用于重新绘制新的页面 将原来的标签内容全部清除 (下方效果为,按钮单击后,重绘页面,绘制write中内容)

        <button>显示内容</button>
        <p>我想说...</p>
        <script>
            let but = document.querySelector('button');
            but.onclick = function () {
                document.write('<h3>恭喜,这是我想说的内容。页面重新绘制了!</h3>');
            }
        </script>

    element.innerHTML

    element.innerHTML 用于 <标签> 内容的添加,支持以 字符串的方式 添加标签样式

    //下方效果为 单击按钮后 改变 <h2>标签 内容为 哼哼哼阿啊...

        <h2>你好</h2> 
      <button onclick="seyhi()">改变内容</button>
    <script>
        function seyhi(){
            document.querySelector('h2').innerHTML='哼哼哼阿啊...';
        }
     </script>

    document.createElement()

    document.createElement(标签名) 用于创建标签

    //当需要循环创建多个标签时,createElement 要比 innerHTML 多次字符拼接方式 更加高效 (下方效果为 创建 10个 <a> 标签)

    //但如果结构合理, innerHTML 的效率 要比 createElement 高一点 (如多个标签内容一次性以字符串方式赋值给 innerHTML

        <div></div>
        <script>
            let div = document.querySelector('div');
                 for (let i = 0; i <= 10; i++) {
                div.appendChild(document.createElement('a'));
            }
        </script>

    事件监听

    添加监听事件

    eventTarget.addEventListener()

    addEventListener() 方法将指定的监听器注册到 目标对象 上,当该对象触发指定的事件时,就会执行事件处理函数



    该方法接收三个参数:

    type】事件类型字符串,比如click、mouseover(这里不再是带 on)
    listener事件处理函数,事件发生时,会调用该监听函数
    useCapture可选参数,为布尔值,默认为false 描述略

    //下方为获取按钮元素 添加监听事件 单击后 执行某项函数

        <div class="box">
            <button>单击弹出</button>
        </div>
        <script>
            let btn = document.querySelector('.box').querySelector('button'); 
          console.log(btn);
            btn.addEventListener('click', function () {
                alert('hello word');       
    });
        </script>

    addEventListener() 与 传统 事件写法 的 函数不同是,它会依次执行 代码行 从上往下所有绑定事件

    //传统事件绑定如 元素.onclick=function(){} 有唯一性的特点,即只能执行一个事件

        <div class="box">
            <button>单击弹出</button>
        </div>
        <script>
            let btn = document.querySelector('.box').querySelector('button'); 
          console.log(btn);
          btn.addEventListener('click', function () {
                alert('hello word');
            });
            btn.addEventListener('click', function () {
                alert('hello smm~');
            });
            btn.addEventListener('click', function () {
                alert('do you like VanGame');
            });
        </script>

    事件监听效果展示:

    eventTarget.attachEvent()

    //该函数目的是兼容旧版IE8以及之前版本的替代性方法,且与新版不互通;一般情况下不建议使用
    //该函数使用方法同 addEventListener(); 但是缺少第三个参数

    该方法有两个参数
    eventNameWithon 事件类型字符串;此处需要带 on (如 onclick);
    callback 事件处理函数,当目标触发事件时回调函数被调用

    存在兼容性问题 解决办法

    //解决 IE8 以及之前版本 该方法 兼容性
            function addEventListener(element, enentName, fn) {
                //判断当前浏览器是否支持 addEventListener 方法
                if (element.addEventListener) {
                    element.addEventListener(enentName, fn); 
              } else if (element.attachEvent) {
                    element.attachEvent('on' + eventName, fn);
                } else {
                    //相当于 element.onclick = fn;
                    element['on' + eventName] = fn;
                }
            }

    删除 监听事件

    eventTarget.removeEventListener();

    //该方法将删除监听事件 指定事件类型 下绑定的 指定的 函数名称方法。因此,不能用匿名函数

    该方法接收三个参数:

    type】事件类型字符串,比如click、mouseover(这里不再是带 on)
    listener事件处理函数,事件发生时,会调用该监听函数
    useCapture可选参数,为布尔值,默认为false 描述略

    //单击按钮后 删除事件 (相当于实现 首次单击有效 效果)

        <div class="box">
            <span>事件监听效果展示:</span>
            <button id="open_eve">单击弹出</button>
        </div>
        <script>
            let btn = document.querySelector('#open_eve');
            //注册监听事件 在该参数下 绑定方法 不需要加括号
            btn.addEventListener('click', fn);
            function fn() {
                alert('hello word');
                //删除监听事件
                btn.removeEventListener('click',fn);
            }
        </script>

    事件流

    事件流 描述的是从页面中接收事件的顺序

    %title插图%num

    事件发生时候会在元素节点之间按照特定的顺序传播,这个 传播过程 即 DOM事件流

    DOM事件流分为三个阶段:
    1.捕获阶段
    2.当前目标阶段
    3.冒泡阶段

    addEventListener([useCapture]);

    //useCapture=true 捕获阶段:从外向内依次触发事件
    useCapture=false 冒泡阶段:从内向内依次触发事件

    //可选参数 [useCapture] 可设置捕获或冒泡方式 (下方为捕获事件)

    <body>
        <div class="demo">
            <div class="box">
                <span>事件流</span>
            </div>
        </div>
        <script>
            let demo = document.querySelector('.demo');
          let box = demo.children[0];
            let seyhi = box.children[0];
            demo.addEventListener('click', function () {
                alert('第一层事件');
             }, true);
             box.addEventListener('click', function () {
                alert('第二层事件');
             }, true);
             seyhi.addEventListener('click', function () {
                alert('第三层事件');
             }, true);
        </script>
    </body>

    捕获阶段事件流

    //实际开发中问们很少用事件捕获,我们更关注事件冒泡
    //有些事件是没有冒泡的,如:onblur、onfocus、onmouseenter、onmouseleave

    事件对象

    什么是事件对象?

    当用户触发了一个事件以后,里面储存着事件发生之后的信息 (如单击位置、坐标、键位等),对该事件的一些描述信息的集合就是 事件对象

    我们可以根据这些信息做很多判断,或者是获取信息来显示。

    1.事件 通常 与 函数 结合使用,函数 不会 在 事件 发生前 被执行!
    2.event 对象 只在 事件发生 的 过程 中 才有效。
    3.event 的某些属性只对特定的事件有意义。比如,fromElementtoElement 属性只对 onmouseoveronmouseout 事件有意义

    //获取单击鼠标的方位 并显示在 <div> 标签上

        <div class="box">单击事件监听</div>
        <script>
            let box =document.querySelector('.box');
            box.onclick=function(event){
                console.log(event);
                box.innerHTML+='<br>当前鼠标位置<br/>X轴'+event.clientX+'---Y轴'+event.clientY;
            }
       </script>

    事件对象存在兼容问题

    IE6 - 7 - 8无法使用 自定义的 方式获得事件对象。对此我们可用以下方式:

    e = e ||window.event

    //让 事件对象 兼容IE6-7-8

    <div class="box">单击事件监听</div>
        <script>
            let box = document.querySelector('.box');
            box.onclick = function (e) {
                //当 找不到 e 这个变量 返回假 便将右侧赋值给变量e
                e = e || window.event;
                box.innerHTML += '<br>当前鼠标位置<br/>X轴' + event.clientX + '---Y轴' + event.clientY;
            }
        </script>

    this 与 e.target

    this 指向 事件绑定对象 | e.targrt 指向事件触发目标

    按照事件流的逻辑,this 始终指向的是我们 事件所绑定的对象

    //(例如 div.onclick=function(){})this 指向的就是这个div

    而 e.targrt 指向的是事件对象中 事件触发的那个对象(如 绑定对象 下的子元素

    //(例如标签结构 <div> → <li>) 当 div 绑定事件后,我们点击 div 下的 li ,e.targrt 可以获取事件对象下的 实际触发对象

        <ul class="div_a">
            <li>单击我</li>
            <li>单击我</li>
        </ul>
        <ul class="div_b">
            <li>单击我</li>
            <li>单击我</li>
        </ul>
        <script>
            let SMSjLeft = document.querySelector('.div_a'); 
          let SMSjRight = document.querySelector('.div_b');
            div_a.onclick = function (e) {
                console.log(this);
            }
            div_b.onclick = function (e) {
                console.log(e.target);
            }
        </script>

    建议浏览器审查元素F12进行比较

    • 单击我
    • 单击我

    console.log(this);

    • 单击我
    • 单击我

    console.log(e.target);

    e.targrt存在兼容问题

    IE6 - 7 - 8无法使用 e.targrt ,对此我们可用以下方式:

            div.onclick = function (e) {
                e = e || window.event;
    //ie6-7-8-9 仅支持e.srcElement 对此需要判断是否存在 e.target
                let target = e.target || e.srcElement;
                console.log(target);
            }

    阻止默认行为

    事件对象属性方法 说明
    e.target 返回触发事件对象 标准
    e.srcElement 返回触发事件对象 非标准 ie6-8使用
    e.type 返回事件的类型 比如 click mouseover 不带no
    e.cancelBubble 该属性阻止冒泡 非标准 ie6-8使用
    e.returnValue 该属性 阻止默认事件 (默认行为) 非标准 ie6-8使用
    e.preventDefault() 该属性 阻止默认事件 (默认行为) 标准
    e.stopPropagation() 阻止冒泡 标准

    有的标签都有自带的默认行为,比如 <a> 标签的默认行为 是 跳转;submit 单击后 提交表单

    e.preventDefault();

    当我们在某些时段不希望让 <a> 标签跳转时,我们就应该用 e.preventDefault(); 阻止 该标签的 默认行为了

        <div class="box">
            <a href="http:smmcat.cn">无名喵站</a>
        </div>
        <script>
            let a = document.querySelector('a');
    //dom 标准写法
            a.addEventListener('click', fn);
            function fn(e) {
                //阻止跳转行为
                e.preventDefault();
            }
        </script>

    禁止区域右键菜单和鼠标选中 案例

        <div class="contextmenu_No">禁止右键菜单和选中</div>
        <script>
            let contextmenu_No = document.querySelector('.contextmenu_No');
            // contextmenu 为鼠标右键菜单事件
            contextmenu_No.addEventListener('contextmenu', function (e) {
                e.preventDefault();
            });
    // contextmenu 为鼠标选中事件
            contextmenu_No.addEventListener('selectstart', function (e) {
                e.preventDefault();
            });
        </script>

    该区域文字无法以正常的方式复制选中

    阻止默认行为 兼容性方法

            a.onclick = function (e) {
                // 普通浏览器方法
                e.preventDefault();
                // 低版本浏览器 ie6-8
                e.returnValue;
                // 返回 false 阻止默认行为 无兼容性问题 只限于传统注册方式
                return false;
            }

    阻止事件冒泡

    当我们对某元素与其父级元素均绑定了同样的事件后,理论事件都会依次响应。

    e.stopPropagation();

    当需要为了避免事件多次执行造成一些潜在问题,我们有时需要阻止事件冒泡

        <div class="box">
            <a href="JavaScript:;">无名喵站</a>
        </div>
        <script>
            let a = document.querySelector('a');
            let box = document.querySelector('.box');
            // <a> 与其父级 <div> 标签皆注册了 点击事件
            a.addEventListener('click', function (e) {
                alert('我是<a>标签的事件');
                // 阻止事件冒泡 (阻止事件向外响应)
                e.stopPropagation();
            }
            );
            box.addEventListener('click', function (e) {
                alert('我是<div>标签的事件');
            }
            );
        </script>

    阻止事件冒泡 兼容性方法

                if (e && e.stopPropagation) {
                    e.stopPropagation();
                } else {
                    window.event.cancelBubble = true;
                }
            }

    事件委派

    当我们需要给父级下的多个子元素注册事件时候。为了优化效率。我们某些情况下可以使用事件委托。

    e.target

    事件委托的原理 依赖 冒泡事件。给父级注册事件后,当子元素触发事件,因着事件冒泡最终会依次传递到父级节点。父级触发事件后 使用 e.target 指向的触发事件的目标子元素。

    • A
    • B
    • C
    • D
    • E

    <ul class="EventBox">
            <li>A</li>
            <li>B</li>
            <li>C</li>
            <li>D</li>
            <li>E</li>
        </ul> 
      <script>
            let EventBox = document.querySelector('.EventBox');
            EventBox.addEventListener('click', function (e) {
                e.target.style.backgroundColor = '#ccc';
            });
        </script>

    鼠标 + 键盘事件

    获取鼠标光标位置


    MouseEvent 鼠标事件 的 X轴 与 Y轴 是根据 鼠标 与 参考目标 左边的距离(X) 和 上边 的距离(y)

    鼠标事件对象 说明
    e.clientX 返回鼠标相对于浏览器窗口可视区 X 坐标
    e.clientY 返回鼠标相对于浏览器窗口可视区 Y 坐标
    e.pageX 返回鼠标相对于文档页面的 X 坐标 IE9+ 支持
    e.pageY 返回鼠标相对于文档页面的 Y 坐标 IE9+ 支持
    e.screenX 返回鼠标相对于电脑屏幕的 X 坐标
    e.screenY 返回鼠标相对于电脑屏幕的 Y 坐标

    e.page 与 e.client 区别

    e.page 是基于 事件元素 最顶部与最左侧距离计算 XY轴 数值。当文档超过浏览器长度,page会继续计算 与该元素 距离

    e.client 是基于浏览器的可视距离 计算 XY轴 数值。即使 文档元素 拉长超过浏览器长度,计算的数值依据浏览器固定

    附上案例:图片跟随替换鼠标案例

    键盘事件

    常用键盘事件

    键盘事件 触发条件
    onkeyup 某个键盘按键被松开时触发
    onkeydown 某个键盘按键被按下时触发
    onkeypress 某个键盘按键被按下时触发 但它不识别功能键位 (例如ctrl、shift)

    不同键盘事件所执行的效果

            // keyup 事件将在按下按键松开后 响应一次
            document.addEventListener('keyup', function () {
                console.log('按键按下松开后事件响应');
            });
            // keydown 事件将在按下按键时 持续响应
            document.addEventListener('keydown', function () {
                console.log('按键按下事件响应');
            });
            // keypress 事件将在键盘的非功能键按下时 持续响应
            document.addEventListener('keypress', function () {
                console.log('按钮按下事件响应');
            });

    keyup、keydown、keypress 键盘事件执行的优先级

    keydown(按键被按下)=> keypress (非功能键被按下)=> keyup(按键松开)

    KeyboardEvent 键盘事件对象

    键盘事件对象 说明
    e.key 返回该键位对应键位值
    e.keCode 返回键位对应 Ascll码

    keydownkeyup 的 键盘事件对象中 keCode 是不区分大小写的,而 keypress 区分大小写


    ASCII值 控制字符 ASCII值 控制字符 ASCII值 控制字符 ASCII值 控制字符
    0 NUT 32 (space) 64 @ 96
    1 SOH 33 ! 65 A 97 a
    2 STX 34 " 66 B 98 b
    3 ETX 35 # 67 C 99 c
    4 EOT 36 $ 68 D 100 d
    5 ENQ 37 % 69 E 101 e
    6 ACK 38 & 70 F 102 f
    7 BEL 39 , 71 G 103 g
    8 BS 40 ( 72 H 104 h
    9 HT 41 ) 73 I 105 i
    10 LF 42 * 74 J 106 j
    11 VT 43 + 75 K 107 k
    12 FF 44 , 76 L 108 l
    13 CR 45 - 77 M 109 m
    14 SO 46 . 78 N 110 n
    15 SI 47 / 79 O 111 o
    16 DLE 48 0 80 P 112 p
    17 DCI 49 1 81 Q 113 q
    18 DC2 50 2 82 R 114 r
    19 DC3 51 3 83 S 115 s
    20 DC4 52 4 84 T 116 t
    21 NAK 53 5 85 U 117 u
    22 SYN 54 6 86 V 118 v
    23 TB 55 7 87 W 119 w
    24 CAN 56 8 88 X 120 x
    25 EM 57 9 89 Y 121 y
    26 SUB 58 : 90 Z 122 z
    27 ESC 59 ; 91 [ 123 {
    28 FS 60 < 92 / 124 |
    29 GS 61 = 93 ] 125 }
    30 RS 62 > 94 ^ 126 `
    31 US 63 ? 95 _ 127 DEL

    附上案例:键盘操作元素移动同步显示输入内容

    利用ASCll码 可以获得键盘事件中 e.keyCode 对应的值 (而 e.key 直接返回值)

        <input type="text" id="text_box">
        <script>
            let textBox = document.querySelector('#text_box');
            document.addEventListener('keyup', function (e) {
                // 当用户键盘松开 s 键后,输入框获得焦点
                if (e.keyCode === 83) {
                    textBox.focus();
               // 当用户键盘松开 回车 键后,输入框失去焦点
                } else if (e.keyCode === 13) {
                    textBox.blur();
                }
            })
      </script>

    BOM 导读

    什么是BOM ?

    JS 浏览器对象模型(Browser Object Model, BOM)被广泛应用于 Web 开发之中,主要用于客户端浏览器的管理

    BOM一系列相关的对象构成,并且每个对象都提供了很多方法与属性;但是它缺乏标准。(即每个浏览器对于BOM都有不同的标准)

    BOM 的范围

    %title插图%num

    BOMDOM 的范围还要大它包含 DOM

    BOM操作整个浏览器 的 对象。它又名为 window 对象,是浏览器的顶级对象

    1.它是 js 访问浏览器窗口的一个接口,很多封装方法都来自BOM,例如 alert(); 在调用时可以省略
    2.它是一个全局对象。定义在全局作用域中的变量、函数都会变成 window对象 的属性和方法

            // window 可以简写
            alert('hello BOM');
            window.alert('hello BOM');

    页面加载事件

    window.onload 页面加载完成事件

    window.onload 事件会在整个网页加载完毕后 执行绑定 onload事件 下的内容

    // 该回调函数会存在 等待过长 的问题。网页资源 (如图片) 未加载完成时,则会一直等待
    // 它能在任何区域 书写,在外部 需要获取网站元素节点时不必考虑 上下位置

            window.addEventListener('load', function () {
                alert('页面加载完成');
            });

    DOMContentLoaded 文档加载完成事件

    DOMContentLoaded 事件会在 DOM元素加载完毕后 执行绑定 DOMContentLoaded事件 下的内容

    // 该回调函数存在兼容问题 仅 IE9 以上支持。它会在文档对象加载完成后响应
    // 它解决了onload 监听加载事件时候,某些情况下等待缓慢 (网站大图加载缓慢) 的问题

            document.addEventListener('DOMContentLoaded', function () {
                alert('DOM加载完成');
            });

    浏览器尺寸事件

    onresize 调整浏览器窗口大小事件

    noresize 事件会在浏览器窗口尺寸发生变化时响应

    //该事件适用于网页美化,隐藏多余元素 适应屏幕等效果
    //下方 div中的背景图会随着浏览器的窗口大小的固定某值 改变其本身尺寸 并动态显示当前浏览器窗口尺寸

    全屏


    window.innerWidth 可获取当前屏幕宽度

    //window.innerWidth 可获取对象获取窗口的文档显示区的宽度,如果有水平滚动条,也包括滚动条高度

            // resize 页面窗口大小发生变化事件
            window.addEventListener('resize', function () {
                // 浏览器窗口宽度
                console.log(window.innerWidth);
                // 浏览器窗口高度
                console.log(window.innerHeight);
            });

    定时器

    setTimeout() 单次下的延时执行

    setTimeout() 方法用于在指定的 毫秒 后调用函数或计算表达式

    // setTimeout 定时器  (调用函数,[延时时间:毫秒]); 它与 事件绑定一样都是 回调函数
    // setTimeout 会在 参数2 给定的毫秒后 执行一次 某个函数方法,若不设置毫秒默认为 0
    // setTimeout 可以写函数 函数名 还可以写 "函数名()"

      // 该定时器执行1秒后发送恶臭
     setTimeout(() => {
                alert('哼哼哼啊啊啊啊啊啊啊啊啊啊');
            }, 1000);

     window.clearTimeout(id) 方法用于清除还没结束的指定 Timeout定时器

    // clearTimeout(id) 需要找到指定标识符下的定时器,因此需要关闭的定时器 必须 赋值给 变量
    // 绑定的变量建议为全局变量,如若为局部变量。当尝试查找该id的 定时器时候将会显示 undefined

            let seyhi = setTimeout(() => {
                alert('Hello Bom');
            }, 5000);
            offTimeout.addEventListener('click', function () {
                window.clearTimeout(seyhi);
            });

    setInterval() 循环下的延时执行

    setInterval() 方法可按照指定的周期(以毫秒计)持续来调用函数或计算表达式

    // setInterval 定时器 (调用函数,[延时时间:毫秒]);
    // setInterval 会持续每隔这个延时时间 就会调用一次该回调函数

            // 5秒周期 控制台 打印 hello Bom
            setInterval(() => {
                console.log('hello Bom');
            }, 5000);

     window.clearIntercal(id) 方法用于清除还没结束的指定 setInterval定时器

    // clearIntercal(id) 需要找到指定标识符下的定时器,因此需要关闭的定时器 必须 赋值给 变量
    // 绑定的变量建议为全局变量,如若为局部变量。当尝试查找该id的 定时器时候将会显示 undefined

            let btn = document.querySelector('button');
            let num = 100;
            // null 是一个空对象
            let numLost = null;
            function numLostFnn() {
                // 给 定时器 绑定变量 用于 指向的 id
                numLost = setInterval(() => {
                    num--;
                }, 1000);
            }
          btn.addEventListener('click', function () { 
              // 清除指定 Interval定时器
                clearInterval(numLost);
            });

    this

    this 指向

    this 的指向在函数定义的时候是确定不了的,只有函数指行时候才能确定 this 到底指向谁,一般情况下 this 的最终指向的是那个调用它的对象

    全局作用域下的 this

            // 全局作用域下的 this 指向的为 window
            console.log(this);

    方法调用中的 this

            // 方法调用中 谁调用 this 指向谁
            let fnn = {
                seyHi: function () {
                    //this 最终指向了 fnn
                    console.log(this);
                }
            }

    构造函数中的 this

            // 构造函数中 this 指向构造函数的实例
            function Fun() {
                console.log(this);
            }
            // this 指向了实例化的目标 fun
            let fun = Fun();

    箭头函数中的 this

    var obb = {
        x: 222,
        y: {
            x: '我是调用say的上文',
            obc: function f() {
                var x = '我是父级'; 
              var obj = {
                    x: '我是兄弟',
                    // 箭头函数没有this 箭头函数的this是继承父执行上下文里面的this
                    say: () => {
                        console.log(this.x); // 实际调用的是 y 下的 x
                    }
                }
                obj.say();
            }
        }
    }
    obb.y.obc();

    同步 和 异步

    JavaScript 是单线程

    javaScript语言 的最大特点是 单线程单线程 就意味着所有的任务需要排队。前一个任务结束,才会执行后一个任务。如果前一个执行时间过长,后面的进程就会堵塞。造成页面渲染加载阻塞不连贯的感觉。

    //代码 从 上往下 执行时,将根据 位置 依次 完成 任务步骤

            早期网页版本 JavaScript 运行逻辑
            console.log(1);
            // 5秒后 执行打印 2
            setTimeout(() => {
                console.log(2);
            }, 5000);
            // 打印 3 的任务将会等待上一个打印 2 的任务完成后执行
            // 存在问题 等待上方任务执行完成的 时间过长

            console.log(3);

    为了解决这个问题,利用多核CPU的计算能力。HTML5提出 Web Worker 标准,允许 JavaScript 脚本创建多个线程。于是 JS 出现 同步异步

    同步

    任务大致按照 代码书写 从上往下 流程执行,前一个任务结束后再执行后一个任务,程序的执行顺序与任务的排列顺序是一致、同步的。

    // 类似于食堂排队打饭,前一个在前台打完饭 后 下一位 才能 在前台打饭

    异步

    多线程执行,同步任务将不等待异步执行完成后执行,将异步任务单独执行js会 先把同步任务执行完成后,再执行异步任务

    由另一个函数作为参数的函数称为 回调函数 (callback function)

    // 系统不会等到异步方法执行完成,而是直接执行后续代码。异步方法执行完成后主要通过状态通知主线程,或者通过回调处理这次异步方法执行的结果
    // 类似于 在我们将衣服丢进洗衣服时候,不是等待洗衣机洗完衣服后做下一个事情。而是在 洗衣机洗 衣服的时侯 同步做某些事情

    console.log(1);
    setTimeout(() => { console.log('异步:2'); }, 0);
    console.log(3);
    console.log(4);
    console.log(5);
    console.log(6);
    /*
    输出结果
    1
    3
    4
    5
    6
    异步:2
    */

    同步异步 的 执行模型

    %title插图%num
    js 执行机制

    JavaScript 会首先在 主线程执行栈 中执行 完成 同步任务队列 后,再去处理 异步任务队列。而异步任务由 异步进程处理 ( 异步 API ) 提供 并放置在 异步任务队列 中。这样的机制又称为 事件循环 ( event loop )

    location对象

    location对象属性

    location对象属性 返回值
    location.href 获取或者设置 整个URL
    location.host 返回主机(域名) https://smmcat.cn
    location.port 返回端口号 如果未写 返回空字符串
    location.pathname 返回路径
    location.search 返回参数
    location.hash 返回片段 #后面的内容 常见于链接 锚点

    >>更多关于location内容

    location.href 实现页面自动跳转

    // 搭配 srtlnterval定时器 可实现页面自动跳转。效果类似执行 <a>标签 默认反馈 体验一下

            let skip_time = document.querySelector('#skip_time');
            let time = 10;
            setInterval(() => {
                if (time == 0) {
                   //转到 无名喵站 指定锚点 位置
                    location.href = 'https://smmcat.cn/?page_id=930#sm_p27';
                } else {
                    skip_time.innerHTML = time + 's';
                    time--;
                }
            }, 1000);

    location.search 获取页面传值

    选择项目,并实现传参:

            // 从另一个网站传过来 get参数 http://...html?_name=233
            // substr() 实现抽取从 参数1下标 开始 到 参数2指定数目的字符,如参数2无则默认抽取到末尾

            let params=location.search.substr(1);
            // split() 字符转数组 以 = 分割
            let arr=params.split('=');
            let p=document.querySelector('#_name');
            p.innerHTML=arr[1];

    location对象方法

    location对象方法 返回值
    location.assign() 跟 href 一样,可以跳转页面(也称为重定向页面)
    location.replace() 替换当前页面,因为不记录历史,所以不能后退页面
    location.reload() 重新加载页面,相当于刷新按钮或者f5 如果参数为 true 强制刷新 ctrl+f5

    location.assign() 重定向

    // 跳转到某网站,该方法记录浏览历史,因此支持后退

            btn.addEventListener('click', function () {
                location.assign('https://smmcat.cn');
            });

    location.replace() 替换地址

    // 替换当前页面,因为不记录历史,所以不能后退页面

            btn.addEventListener('click', function () {
                location.replace('https://smmcat.cn');
            });

    location.reload() 重载页面

    // 类似于刷新页面,如果不需要刷新页面时使用缓存,让服务器重新读取,可在参数里面加 true

            p.addEventListener('click', function () {
                location.reload(true);
            });

    navigator对象

    什么是 navigator对象?

    navigator对象 包含有关浏览器的信息,它有很多属性,我们最长用的是 userAgent,该属性可以返回由客户机发送 服务器 的 user-agent 头部的值

    navigator对象属性 作用
    navigator.userAgent userAgent 属性是一个只读的字符串,声明了浏览器用于 HTTP 请求的用户代理头的值

    navigator.userAgent 判断用户登录设备 实现跳转不同页面

    //很多网站都会自动跳转客户端对应且适配的页面 会判断 userAgent 值进行操作 体验一下

            //检测用户 user-agent头部的值 索引关键词 判断登录设备 if((navigator.userAgent.match(/(phone|pad|iphone|ipod|ios|ipad|Android|Mobile|BlackBerry|IEMobile|MQQbrowwser|JUC|Fennec|WOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone)/i))) {
                // 转到手机端 页面链接
                window.location.href = "";
            } else {
                // 转到电脑端 页面链接
                window.location.href = "";
            }

    history对象

    history对象 方法

    history对象方法 作用
    back() 可以后退功能
    forward() 前进功能
    go() 前进后退功能 参数为1则前进1个页面,如果为-1 为后退1个页面

    History 对象包含用户(在浏览器窗口中)访问过的 URL

    // history 对象是 window 对象的一部分,可通过 window.history 属性对其进行访问
    // history 对象包含浏览器历史,为了保护用户的隐私,JavaScript 访问此对象存在限制
    // history 对象一般在实际开发中比较少用,但是会在一些OA办公系统中见到 用于云系统内部的跳转操作

            let come = document.querySelector('#come');
            let back = document.querySelector('#back');
            // 网页前进 相当于 点击了 浏览器前进按钮
            come.addEventListener('click', function () {
                history.forward();
            });
            // 网页后退 相当于 点击了 浏览器后退按钮
            back.addEventListener('click', function () {
                history.back();
            });

    offset 偏移量

    %title插图%num

    offset 系列属性

    offset系列属性 作用
    element.offsetParent 返回作为该元素带有定位的父级元素 如果父级没有定位则返回body
    element.offsetTop 返回元素相对带有定位父元素上方的偏移
    element.offsetLeft 返回元素相对带有定位父元素左边框的偏移
    element.offsetWidth 返回自身包括padding、边框、内容区的宽度,返回值不带单位
    element.offsetHeight 返回自身包括padding、边框、内容区的高度,返回值不带单位

    offset (偏移量) ,使用 offset 相关属性可以动态获取该元素的位置 (偏移)、自身大小等

    // offsetTop 与 offsetLeft 会计算元素 左侧 和 顶部 与有定位的父级之间的距离
    // offsetWidth 与 offsetHeight 会计算元素自身 盒子区域 大小,但不包括 overflow 隐藏的区域 与  margin

            let div=box.querySelector('.box');
            // 返回元素盒子顶端 与 父级文档 或 body顶端 相距的 高度
            console.log(div.offsetTop);
            // 返回元素盒子顶端 与 父级文档 或 body左侧 相距的 宽度
            console.log(div.offsetLeft);
            // 返回 元素盒子模型 自身高度
            console.log(div.offsetHeight);

    offsetParent 与 parentNode 获取父级元素的区别

    // offsetParent 仅获取带有定位的父级,因此获取的父级不一定是最近的父级,也可能是 上级 直到 body 其中一个父级元素

            // 返回带有定位的父级元素 (以便用于操作父级元素的偏移量)
            console.log(div.offsetParent);
            // 返回最近一级的父级元素 (常用于元素选定:如删除父级元素)
            console.log(div.parentNode);

    offset 与 style 区别

    // offset 与 style 经常搭配使用。用于测量元素与操作元素 附上案例:获取鼠标单击位置在盒子的坐标模态框案例

    offset 是只读属性,只能获取不能赋值;获取的值是根据 padding+border+width 的大小且没有单位 (px) 的。且 offset 可以得到任意样式表中的样式值。它更适用于 获取元素大小位置的操作

    style 是可读写属性,可以获取也可以赋值;获得值仅为 width 且是带有单位的字符串。且 style 只能获得行内样式表中的样式值。 它更适用于 修改元素大小位置操作

        <div class="box" style="width: 200px;padding: 20px;">
        <script>
            let div = box.querySelector('.box');
            console.log(div.offsetWidth); //结果为 220
            console.log(div.style.width); //必须是行内式写的 结果为 200px
        </script>

    offset 实现 京东放大镜 效果

    // 鼠标在区域移动 时 显示大图框 与 mark框, 绑定光标在区域的位置并 动态绑定 mark在框内位置,最后计算mark框安全区域,防止溢出。
    // overflow隐藏 大图本体溢出区域 mark框在小格子走动,大图 随之移动至 固定比例 的位置

    %title插图%num
    %title插图%num

    client 元素可视区

    %title插图%num

    client 翻译过来就是客户端,我们使用 client 系列相关属性来获取元素可视区的相关信息,通过 client 系列的相关属性可以动态得到该元素的边框大小、元素大小等

    client 系列属性

    client系列属性 作用
    element.clientTop 返回元素上边框的大小
    element.clientLeft 返回元素左边框的大小
    element.clientWidth 返回自身包括padding、内容区的宽度,不含边框,返回数值不带单位
    element.clientHeight 返回自身包括padding、内容区的高度,不含边框,返回数值不带单位

    client 与 offset 的区别为,client 不包含边框

    // chlient 只返回内容区域,若想获取元素边框,可用 clientTop 或 clientLeft

    结果


        <div style="width: 140px; height: 140px;background-color: brown;border: 10px solid #ccc;"></div>
        <script>
            let SMclient = document.querySelector('div');
            SMclient.innerHTML = SMclient.clientHeight; //140
            SMclient.innerHTML = SMclient.offsetHeight; //140 + 20 = 160
        </script>

    立即执行函数

    (function(){})() 立即执行函数

    声明一个函数,并马上调用这个匿名函数就叫做立即执行函数;即立即执行函数是定义函数以后会立即执行的函数写法

    常规函数定义并调用

    function fnn() {
        console.log('hello word');
    }
    fnn();

    立即执行函数

    // 第一种立执行函数写法
    (function () {
        console.log('hello word');}
    )();
    // 第二种立执行函数写法
    (function () {
        console.log('hello word');
    }());

    // 上边的两种写法,就是立即执行函数的两种写法,都是以圆括号开头,引擎会意味后面跟的是表达式,而不是一个函数定义语句,所以就避免了错误,这就叫做"立即调用的函数表达式"

    立即执行函数的运行原理

    %title插图%num

    // 立即执行函数一般也写成匿名函数,匿名函数写法为function(){/…/},所谓匿名函数,就是使用function关键字声明一个函数,但未给函数命名,倘若需要传值,直接将参数写到括号内即可。

    // 将它赋予一个变量则创建函数表达式,赋予一个事件则成为事件处理程序等。但是需要注意的是匿名函数不能单独使用,否则会js语法报错,至少要用()包裹起来。

    立即执行函数的传参

    // 把 实参 字符串 hello word 赋值给了 形参 str
    (function (str1,str2) {
        console.log(str1 + str2);
    })("hello"," word")

    立即执行函数的用途

    创建了一个独立的作用域。避免变量命名冲突的问题

    // 立即执行函数最大的作用就是 独立创建了一个作用域,里面所有的变量都是局部变量,不会有命名冲突的情况

    let _name = '244';
    (function () {
        let _name = '233';
        console.log(_name); // 233 并不会替换上方全局变量 _name 的值
    })();
    console.log(_name); // 244

    scroll 滚动

    %title插图%num

    scroll 翻译过来就是滚动,该系列相关属性可以动态 (只读) 获得该元素大小、滚动距离等

    scroll 系列属性

    client系列属性 作用
    element.scrollTop 返回被卷去的上侧距离
    element.scrollLeft 返回被卷去的左侧距离
    element.scrollWidth 返回自身实际宽度 (不包含边框,但包括溢出元素)
    element.scrollHeight 返回自身实际高度 (不包含边框,但包括溢出元素)
    window.pageYOffset 获得页面被滚动隐藏的高度

    scrollWidth、scrollHeight 返回元素实际大小 (包括内容 padding 和 溢出区域)

    这段内容将会超出盒子实际的大小,我们看看scroll实际大小是多少?

    可以看到,scrollHeight 返回的是整个盒子内容的实际高度,子元素溢出盒子的大小也会算 scrollHeight 中;宽度同理

    scroll 滚动事件 与 element.scrollTop 元素上方被隐藏元素高度

    // scroll 是元素的滚动条发生滚动的事件,滚动下方猫猫图,右侧scrollTop值会发生改变
    // scrollTop的值为该区域顶端被隐藏的高度,依靠scroll滚动事件会动态传值给右侧指示盒

    0

    %title插图%num

    可以看到,scrollTop 会将盒子中滚动条非显示区域的顶部内容的高度作为它的值;scrollLeft 同理

    动画原理

    基础移动动画原理

    利用定时器 setInterval 可以让一个定位的盒子 逐次向方位宽度增加的动画效果

    // 单击该进度条 会从0% 逐步递增到 100% ,里面的绿色盒子长度逐步递增到父盒子长度


    动画封装方式

    利用 元素对象 添加属性方法 的方式 添加 和 封装 动画效果

    // 每次定义变量都会占用内存空间,为了节约空间,可直接给标签对象添加属性方法

            // 定义封装动画方法 传入 标签对象 限制的距离
            function animate(obj, target) {
                //预先清除上一个定时器
                clearInterval(obj.timer);
                // 创建 标签对象属性 timer 并 赋予连续的动画方法
                obj.timer = setInterval(function () {
                    // 如 标签对象 与父级左侧之间的距离大于 taget 给定的值
                    if (obj.offsetLeft >= target) {
                        // 清除 该定时器
                        clearInterval(this);
                    } else {
                        // 若否 持续执行每次自身与父级左侧的距离 加 1px
                        obj.style.left = obj.offsetLeft + 1 + 'px';
                    }
                }, 30);
            }

    技巧 - 缓动动画公式

    让元素移动逐渐缓慢直到停止的完成一个动画周期

    ( 目标值 - 现在的位置 ) / 总次数

    技巧 - 封装多用途定位动画

    // 定义一个函数方法,将预装的 setInterval实现的渐慢移动动画 以 对象添加属性方法的方式 赋值并执行
    // 由于计算机不容易精确的存储小数内容的值,所以一般运算时都尽量忽略小数部分或者保留小数点后几位数
    // 上方代码稍做修改,即可实现给定位置将会移动到该区域 (元素需要定位)

        // temp的值为 分成50步骤完成的 目标位置的值
        let temp = (target - obj.offsetLeft) / 50;
        //判断返回的数值是否为正负 执行不同的取整方法
        temp = temp > 0 ? Math.ceil(temp) : Math.floor(temp);

    技巧 - 动画函数添加回调函数

    // JavaScript中函数方法是可以作为参数传参的,因此我们可以在函数中嵌套自定义的处理方法
    //该写法实现了 调用该动画函数执行完毕后 会执行某项特定的 自定义操作的回调函数

            // 参数 元素对象 回调函数
            function moveElement(...,callback) {
                clearInterval(obj.timer); 
              obj.timer = setInterval(() => {
                   ...
                    if (...) {
                        // 当清除定时器后并执行某项方法
                        clearInterval(obj.timer);
                        // 如果回调函数存在,则执行回调函数的内容
                        if(callback){
                        callback();
                     }
                    } else {
                       ...
                    }
                }, 20);
            };
            moveElement(obj,function(){
                //描述回调函数
                ...       
    })

    // 下方为使用了 回调函数 的案例,当动画执行完成后,会执行改变元素颜色操作