Web API

Web API

一、名词解释:

webAPI:
  • 使用js来操作html和浏览器

DOM : document object model 文档对象模型.

​ ===> 把一个页面当做一个对象来看待. 对象有属性和方法.

​ 是用来呈现以及与任意HTML或XML文档交互的API;

​ 通过DOM提供给我们的属性和方法, 操作网页内容.

BOM: browser object model 浏览器对象模型

​ ====> 把浏览器当做一个对象来看待. 浏览器的顶级对象就是window

​ 通过浏览器提供给我们的方法, 操作浏览器的功能.

对象:
  • 描述事物的特征和行为 具有属性和方法
文档:
  • 一个页面就是一个文档. document
元素:
  • 页面上所有的标签都叫元素. element
节点:
  • 页面上所有的内容 都叫节点(元素节点 文本节点 属性节点 注释节点)
DOM对象(DOM元素):
  • 把页面上的内容(元素/节点)当成对象来看待
DOM树:
  • 描述了元素节点之间的一种层级关系 父子关系或者兄弟关系
document对象:
  • 页面上的顶级对象
元素和节点有什么区别:

DOM节点:

  • DOM 文档是由节点层次结构组成。每个节点可以有父级或子级节点
<!DOCTYPE html>
<html>
  <head>
    <title>My Page</title>
  </head>
  <body>
    <!-- Page Body -->
    <h2>My Page</h2>
    <p id="content">Thank you for visiting my web page!</p>
  </body>
</html>
image-20220829232620748
		const paragraph = document.querySelector('p');
        console.log(paragraph.nodeType); // 1 ==> Node.ELEMENT_NODE
		paragraph instanceof Node;        // => true
		paragraph instanceof HTMLElement;   // => true
       /* paragraph 既是节点 也是元素 */ 

        const firstChild = paragraph.childNodes[0];
        console.log(firstChild.nodeType); // 3 ==> Node.TEXT_NODE

        console.log(document.nodeType); // 9 ==> Node.DOCUMENT_NODE

DOM元素:

  • 元素是特定类型的节点,是使用 HTML 文档中的标记(标签)编写的节点
了解一些常见的节点类型:
1. DocumentType类型 —— 文档类型声明节点
  • 文档类型声明节点即文档最顶部的类型声明,比如,`。

  • 文档类型声明节点的nodeType ==10

  • 文档类型声明节点的nodeName等于文档的类型名。

  • 文档类型声明节点没有子节点。

2. Document类型 —— 文档节点
  • 在浏览器中,document对象是HTMLDocument类型的一个实例,而HTMLDocument继承自Document类型。

  • docuemnt对象作为文档的顶层节点,我们称其为文档节点

  • 文档节点的nodeType等于9

  • 文档节点的nodeName等于'#document'

3. Element类型 —— 元素节点
  • 元素节点的nodeType等于1

  • 元素节点的nodeName等于元素的标签名

  • 所有HTML元素都由HTMLElement或其子类型表示,HTMLElement类型继承自Element类型。

  • HTMLElement类型设定了idclassNametitle等基本属性,所有HTML元素都支持这些属性

4. Text类型 —— 文本节点
  • 文本节点的nodeType等于3.

  • 文本节点的nodeName等于'#text'

  • 文本节点的nodeValue即为包含的文本内容

  • 文本节点的父节点是元素节点,没有子节点

  • 文本节点拥有一个length属性,表示该文本中的字符数

  • 空格也会生成文本节点

  • 文本节点的创建:document.createTextNode('文本内容')

  • 默认情况下,一个元素节点下最多只能有一个文本节点。

5. Attr类型 —— 属性节点
  • 一般不将其视作DOM树的一部分

  • 从HTML的角度来看,属性即元素标签内的特性;从JS的角度看,属性就是元素节点对象实现和提供的相关节点

  • 属性节点的nodeType等于2.

  • 属性节点的nodeName等于属性名

  • 属性节点在HTML中没有子节点

  • 在实际开发中,对于属性的操作我们一般都使用getAttribute()setAttribute()removeAttribute()这几个更加好用的方法。

二、获取DOM对象

1. 获取元素的方式
document.querySelector('选择器')
 //  作用:返回指定选择器的第一个DOM对象(元素)

document.querySelectorAll('选择器')
 // 作用:返回匹配的所有元素的集合
 // 返回值:是一个伪数组 一堆集合
 // 伪数组:有length 有索引 没有数组的pop,shift等方法

document.getElementById('id名')
document.getElementsByClassName('类名')
document.getElementsByTagName('div')

/* 特殊元素的获取 */
body ==> document.body
html ==> document.documentElement

​ console.dir();打印一个对象的所有属性和方法

2. 属性选择器
 <input type="text" value="123" data-id="0" data-name="andy">
<input type="password">
		const input1 = document.querySelector('input[value]')
            // console.log(input)
        console.log(input.dataset) // 自定义属性集合
        console.log(input.dataset.name) // 自定义属性集合
        console.log(input.dataset.id) // 自定义属性集合
            // 获取元素
            // document.querySelector('选择器')
            // 1. [] 方括号立马写上属性名
        const input2 = document.querySelector('input[type="password"]')

        // 2. 方括号里键值对 引号可以省略
        const input3 = document.querySelector('input[type=password]')

        // 3. 可以直接写属性也能获取到
        const input4 = document.querySelector('[type=password]')

        const input5 = document.querySelector('[value="123"]')
        const input6 = document.querySelector('[data-id]')
        console.log(input)
3. 操作元素内容

innerHTML 识别html标签

innerText 不识别html标签

4. 修改标签样式属性
  1. style (权重大 1000)
  2. className

    className适合多个样式都需要修改的情况

    也可以清空某个元素的所有类名 div.className =’ ’

  3. classList
    • 添加类名:box.classList.add(‘类名’)
    • 删除类名:box.classList.remove(‘类名’)
    • 切换类名:box.classList.toggle(‘active’)

    三者的使用选择:

    • style 适合修改单个或少部分样式的时候使用
    • className 缺陷会覆盖原来的类名
    • classList 不会覆盖原来的类名 是追加或者删除当前的这个类名

三、自定义属性

  1. H5 新增, 以 data - 来定义自定义属性
  2. dataset获取自定义属性:
    • 它获取到的是一个对象, 存放了所有以**data开头**定义的自定义属性
  • element.dataset.属性名

  • element.dataset[‘属性名’] (注意:单引号)

  1. dataset内, 属性名从短横线变为了驼峰
	<div data-id="111" data-test-id="2222"></div>
    <a href="http://www.baidu.com" target="_blank" person="我也是自定义"></a>
    <div data-id="0" data-test-id="222"></div>
    <ul>
        <li>123</li>
        <li>123</li>
        <li>123</li>
        <li>123</li>
        <li>123</li>
    </ul>
		// 自定义属性 ,我们自己定义的一些属性。
        const div = document.querySelector('div')  // 获取第一个div
        const a = document.querySelector('a')
        console.log(typeof div.dataset) // 'object' 

            // 对象 获取属性值的两种方式:
            // 1. 对象.属性名
            // 2. 对象['属性名']
        console.log(div.dataset.id)
        console.log(div.dataset['id'])  // 注意:单引号
		// dataset内, 属性名从短横线变为了驼峰
        console.log(div.dataset.testId)
        console.log(div.dataset['testId']) 

        // 1. 获取
        // 获取自定义属性 元素.getAttribute('属性名')
        console.log(a.getAttribute('person'))
            // 它还可以获取元素本身自带的属性
        console.log(a.getAttribute('href'))

        // 2. 设置 \ 修改
        // 设置元素自定义属性 元素.setAttribute('属性名', 值)
        a.setAttribute('test-demo', '哈哈哈哈')// setAttribute() 还可以设置(修改)本身自带的属性值
        a.setAttribute('href', 'http://jd.com')
        console.log(a.getAttribute('href'))
		// setAttribute() 用js自动设置自定义属性 更推荐以'data-'开头自定义属性

        // 3. 移除属性
        // el.removeAttribute('属性名')
        a.removeAttribute('test-demo')

        // 需求:给每一个li标签 设置自定义属性data-id 索引号从0开始
        const lis = document.querySelectorAll('li')
        lis.forEach(function(item, i) {
            item.setAttribute('data-id', i)
        })

        // item.getAttribute(属性名) ==> 可以获取元素的属性
        // item.setAttribute(属性名,值) ==> 可以自定义属性  还可以修改元素本身的属性
        // item.removeAttribute(属性名) ==> 移除元素的某个属性

四、遍历对象获取属性

const obj = {
            name: 'pink',
            age: 20,
            hobby: '唱歌',
            key: '234'
        }

        for (let key in obj) {
            console.log(key)  //name age hobby key
            console.log(obj[key])  //'pink'  20  '唱歌' '234'
            console.log(obj['name']) // 'pink'
            // 1. 这里的key是一个变量, 每次循环的时候,依次表示每一个属性名
            // 第一次循环 key 'name'
            // 第二次    key  'age'
            // 第三次     key  'hobby
        }

        // 如果我们要直接取属性的值, 这里, 需要加引号
        console.log(obj['age'])
        // 如果不加引号, 表示变量, 找不到age, 
        console.log(obj[age]) // Error 报错

        console.log(obj[key]) // Error 报错
        console.log(obj['key'])  //234
        console.log(obj.key)   //234

        // ===> 最后记住一句话:  obj[key]
        // 如果不加引号, 表示变量 , 
        // 如果加了引号, 表示对象本身存在的某个属性名

五、计时器setInterval

1. setInterval使用
		// 第一种:直接把函数写在setInterval()里面
		// 语法: window.setInterval(fn, wait)
		// window提供的方法 window可以省略
        window.setInterval(function() {
            console.log('定时器在走');
        }, 1000)

        // 第二种:具名函数 
        function fn() {
            console.log('午饭吃什么');
        }
        const foo = function() {
            console.log('好好努力');
        }
        setInterval(foo, 1000)

思考:

 		var a = 3; //在顶层函数中声明变量a
        function f() {
            const a = 2; //在函数体内声明局部变量a
            return new Function("return a*a;"); //无法捕获局部作用域
        }
        console.log(f()());  // 9
2. 定义函数有几种方式
      // 1. 声明式
		function foo(){
        console.log(1)
      }
      btn.addEventListener('click', foo)

      // 2. 表达式
      const bar = function(){
        console.log(2)
      }
      btn.addEventListener('click', bar)
3. 清除计时器
		let timer1 = setInterval(function() {
            console.log('22222');
        }, 1000)
        console.log(timer1); 
		// 定时器有一个返回值 是一个数字 是当前定时器的唯一标识
        // 这个number标记  从1开始
        clearInterval(timer1)  //清除计时器

六、延时器 setTimeout

        setTimeout(function() {
            console.log('大家吃早饭了嘛? ')
        }, 1000)

        // 1.2 写函数名
        function cb() {
            console.log('饿了吗')
        }
        const foo = function() {
            console.log('真的不饿吗')
        }

        // 注意:函数名后面一定不要写小括号, 写小括号表示调用
        let timer1 = setTimeout(cb, 2000)
        let timer2 = setTimeout(foo, 5000)
        
        window.clearTimeout(timerId)  // 清除延时器
        // window可以省略

setTimeout 延时时间到了,只调用一次

setInterval 每隔这个延时时间,都会回调一次,会调用很多次,直到清除定时器

七、事件监听

事件三要素:

  1. 事件源:谁 谁触发了事件

  2. 事件类型:什么事件(行为)

  3. 事件处理程序:我们要干嘛(事件)

1. 随机点名案例分析(多种方法解析)
    <h2>随机点名</h2>
    <div class="box">
        <span>名字是:</span>
        <div class="qs">这里显示姓名</div>
    </div>
    <div class="btns">
        <button class="start">开始</button>
        <button class="end">结束</button>
    </div>
<!-- 多次重复点击会开启多个计时器 速度会随着点击的次数增加而加快 且后台会冗余大量的计时器 -->
// 解决方法一:
const arr = ['马超', '黄忠', '赵云', '关羽', '张飞']
        const start = document.querySelector('.start')
        const end = document.querySelector('.end')
        const qs = document.querySelector('.qs')

        let i
        let timerId
        start.addEventListener('click', function() {
            clearInterval(timerId)  
            // 在每次点击事件之前 先进行清除计时器 这样确保每次点击开始之后 只有一个计时器在进行
            // 缺点:后台会冗余大量已经清除的计时器
            timerId = setInterval(function() {
                i = Math.floor(Math.random() * arr.length)
                qs.innerHTML = arr[i]
            }, 50)
            if (arr.length === 1) {
                start.disabled = end.disabled = true
            }
        })
        end.addEventListener('click', function() {
            clearInterval(timerId)
            arr.splice(i, 1)
        })
// 解决方法二:
const arr = ['马超', '黄忠', '赵云', '关羽', '张飞']
        const start = document.querySelector('.start')
        const end = document.querySelector('.end')
        const qs = document.querySelector('.qs')

        let i
        let timerId
        let flag = true
        // 声明flag 运用开关思想 来控制后台启动计时器的数量
        start.addEventListener('click', function() {
            if (flag === false) return
            flag = false
            timerId = setInterval(function() {
                i = Math.floor(Math.random() * arr.length)
                qs.innerHTML = arr[i]
            }, 50)
            if (arr.length === 1) {
                start.disabled = end.disabled = true
            }

        })
        end.addEventListener('click', function() {
            clearInterval(timerId)
     // 对flag进行判断 是为了防止多次点击“结束” 导致数组里面的元素全部删除清空 出现undefined
            if (flag) { 
                arr.splice(i, 1)
            }
            flag = true

        })
// 解决方法三:
const arr = ['马超', '黄忠', '赵云', '关羽', '张飞']
        const start = document.querySelector('.start')
        const end = document.querySelector('.end')
        const qs = document.querySelector('.qs')

        let i
        let timerId = 0
        start.addEventListener('click', function() {
            if (timerId) return
            // 就地取材 直接利用现有的timerId变量 运用开关思想 进行判断
            timerId++
            timerId = setInterval(function() {
                i = Math.floor(Math.random() * arr.length)
                qs.innerHTML = arr[i]
            }, 50)
            if (arr.length === 1) {
                start.disabled = end.disabled = true
            }
        })
        end.addEventListener('click', function() {
            clearInterval(timerId)
            if (timerId) {
            // 为了防止多次点击“结束” 导致数组里面的元素全部删除清空 出现undefined
                arr.splice(i, 1)
            }
            timerId = 0
        })
2. 轮播图
 <div class="slider">
        <div class="slider-wrapper">
            <img src="./images/slider01.jpg" alt="" />
        </div>
        <div class="slider-footer">
            <p>对人类来说会不会太超前了?</p>
            <ul class="slider-indicator">
                <li class="active"></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
            </ul>
            <div class="toggle">
                <button class="prev">&lt;</button>
                <button class="next">&gt;</button>
            </div>
        </div>
    </div>
 // 1. 初始数据
        const arr = [{
            url: './images/slider01.jpg',
            title: '对人类来说会不会太超前了?',
            color: 'rgb(100, 67, 68)'
        }, {
            url: './images/slider02.jpg',
            title: '开启剑与雪的黑暗传说!',
            color: 'rgb(43, 35, 26)'
        }, {
            url: './images/slider03.jpg',
            title: '真正的jo厨出现了!',
            color: 'rgb(36, 31, 33)'
        }, {
            url: './images/slider04.jpg',
            title: '李玉刚:让世界通过B站看到东方大国文化',
            color: 'rgb(139, 98, 66)'
        }, {
            url: './images/slider05.jpg',
            title: '快来分享你的寒假日常吧~',
            color: 'rgb(67, 90, 92)'
        }, {
            url: './images/slider06.jpg',
            title: '哔哩哔哩小年YEAH',
            color: 'rgb(166, 131, 143)'
        }, {
            url: './images/slider07.jpg',
            title: '一站式解决你的电脑配置问题!!!',
            color: 'rgb(53, 29, 25)'
        }, {
            url: './images/slider08.jpg',
            title: '谁不想和小猫咪贴贴呢!',
            color: 'rgb(99, 72, 114)'
        }, ]
        const img = document.querySelector('.slider-wrapper img')
        const p = document.querySelector('.slider-footer p')
        const lis = document.querySelectorAll('.slider-indicator li')
        const footer = document.querySelector('.slider-footer')
        const prev = document.querySelector('.prev')
        const next = document.querySelector('.next')
        let i = 0
        next.addEventListener('click', function() {
            i++
            if (i >= 8) {
                i = 0
            }
            render()
        })
        prev.addEventListener('click', function() {
            i--
            if (i <= -1) {
                i = arr.length - 1
            }
            render()
        })

        function render() {
           img.src = arr[i].url
           p.innerHTML = arr[i].title
           footer.style.backgroundColor = arr[i].color
           document.querySelector('.slider-indicator .active').classList.remove('active')
           lis[i].classList.add('active')
        }

        /* ==================  计时器  ================== */
        const slider = document.querySelector('.slider')
        let timer = setInterval(function() {
            next.click()
        }, 1000)
        slider.addEventListener('mouseenter', function() {
            clearInterval(timer)
        })
        slider.addEventListener('mouseleave', function() {
            timer = setInterval(function() {
                next.click()
            }, 1000)
        })
3. 全选按钮案例
 		const checkAll = document.querySelector('#checkAll')
        const cks = document.querySelectorAll('.ck')
        // 最外层是循环
        cks.forEach(function(item) {
            // 点击全选按钮
            checkAll.addEventListener('click', function() {
                item.checked = checkAll.checked
            })
             // 点击单个按钮
            item.addEventListener('click', function() {
                const arr = document.querySelectorAll('.ck:checked')
                if (arr.length === cks.length) {
                    checkAll.checked = true
                } else {
                    checkAll.checked = false
                }
		})
3. 键盘事件(input\change\blur)
  • input事件: 在输入框输入的时候会实时响应并触发;
  • change事件:在输入框失去焦点,并且输入框的值发生变化的时候才会触发
  • blur事件:blur事件是每次失去焦点时触发,不管输入框数据有没有变化;

八、DOM事件对象

事件对象: 当事件发生的时候, 和这个事件相关的所有信息, 都存在这个对象中.

在 DOM 中发生事件时,所有相关信息都会被收集并存储在一个名为 event 的对象中。这个对象包 含了一些基本信息,比如导致事件的元素、发生的事件类型,以及可能与特定事件相关的任何其他数据。 例如,鼠标操作导致的事件会生成鼠标位置信息,而键盘操作导致的事件会生成与被按下的键有关的信 息。

这个对象就叫做事件对象. event, 简写ev、evt ===> e

event 对象只在事件处理程序执行期间存在,一旦执行完毕,就会被销毁

1. 事件对象常见的公共属性与方法
属性/方法读/写说 明
currentTarget 元素只读当前事件处理程序所在的元素
preventDefault() 函数只读用于取消事件的默认行为
stopImmediatePropagation() 函数只读用于取消所有后续事件捕获或事件冒泡,
并阻止调用任何后续事件处理程序(DOM3 Events新增)
stopPropagation() 函数只读用于取消所有后续事件捕获或事件冒泡
target 元素只读事件目标
type 字符串只读被触发的事件类型
  • e.target ==> 触发事件的元素 点击的是谁 他就指向谁

    this ==> 绑定事件的元素

    e.currentTarget ==> 绑定事件的元素 等于this

  • type 属性多用于在一个处理程序处理多个事件

		const btn = document.querySelector('button')
        let handler = function(event) {
            switch (event.type) {
                case "click":
                    alert("Clicked");
                    break;
                case "mouseover":
                    event.target.style.backgroundColor = "red";
                    break;
                case "mouseout":
                    event.target.style.backgroundColor = "";
                    break;
            }
        };
        btn.onclick = handler;
        btn.onmouseover = handler;
        btn.onmouseout = handler;
// 在这个例子中,函数 handler 被用于处理 3 种不同的事件:click、mouseover 和 mouseout
// 当按钮被点击时,会在控制台打印一条消息
// 这个函数使用 event.type 属性确定了事件类型,从而可以做出不同的响应。
  • preventDefault()与stopPropagation()的区别:

    • preventDefault()方法用于取消默认行为的事件

      比如,链接的默认行为就是在被单击时导 航到 href 属性指定的 URL,如果想阻止这个导航行为,可以在 onclick 事件处理程序中取消;以及submit默认提交行为

    • stopPropagation()方法用于立即阻止事件流在 DOM 结构中传播,取消后续的事件捕获或冒泡

      例如,按钮的事件处理程序中调用 stopPropagation(),可以阻止 document.body 上注册的事件处理程序执行

      阻止的是事件的传播 不会阻止函数内代码的执行

九、函数内部特殊对象(arguments、this)

1. arguments动态参数
  • arguments 是函数内部内置的伪数组变量,它包含了函数调用时传入的所有实参

    1. 动态参数,只存在于函数里 是伪数组
    2. arguments的作用是动态获取函数传递过来的所有实参
    3. 可以通过for循环一次性得到传递过来的实参
    function box() {
        let sum = 0;
        if (arguments.length == 0) return sum;        //如果没有参数,退出
        for(var i = 0;i < arguments.length; i++) {    //如果有,就累加
            sum = sum + arguments[i];
        }
        return sum;                            //返回累加结果
    }
    alert(box(5,9,12));
    
2. this
  • this就是一个关键字, 是一个变量. 它的值存的是一个对象.

this在标准函数和箭头函数中有不同的行为。

  • 在标准函数中,this 引用的是把函数当成方法调用的上下文对象
  • 在箭头函数中,this引用的是定义箭头函数的上下文
 // 全局环境中 this指向window (指向 ===> 理解为 等于)
 console.log(this);  // window

函数内部 this这个对象的值取决于函数被调用的方式

		// 函数内部 this这个对象的值取决于函数被调用的方式
		// ===> 粗略的规则:谁调用 this指向谁
        // 1. 普通函数的调用
        function fn() {
            console.log(this);
        }
        fn() // ===> 相当于window.fn()
        window.fn()

        // 2. 函数作为对象的方法调用
        const obj = {
            name: 'zjl',
            fn: function() {
                console.log(this);
            }
        }
        obj.fn()  // obj{}

		// 2.3 事件绑定中 this指向注册(绑定)事件元素
        const btn = document.querySelector('button')
        btn.addEventListener('click', function() {
            console.log(this);  // <button>
            this.style.color = 'orange'
            console.log(btn === this); // true
        })

         btn.fn() ==>可以理解为 btn调用了这个函数

十、回调函数

  1. 本质上: 就是函数, 只是作为函数的参数来进行使用.

    • 作为函数的参数传入

    • 一开始不执行, 当满足某些触发条件的时候, 才执行.回头再调用

  2. 使用场景:事件绑定 / 事件注册 / 事件监听

        const btn = document.querySelector('button')
        const callback = function() {
            console.log('我是回调函数');
        }
        btn.addEventListener('click', callback)
        // 定时器
        const cb = function() {
            console.log('我也是回调函数');
        }
        setInterval(cb, 1000)
// 为什么计时器会重新启动?

十一、事件

1. 事件流:

事件在执行过程中的流动路径(元素在页面中接收事件的顺序)

DOM事件流 三个阶段:

​ 1. 捕获阶段 从外到内

​ 2. 处于目标阶段

   3. 事件冒泡阶段 从内到外
2. 事件捕获:

是最不具体的节点应该最先收到事件,而最具体的节点应该最后收到事件

document - > html - > body - > father - > son(从外到内)

addEventListener(type, listener, true) 第三参数为 true

3. 事件冒泡:

事件从最具体的元素(文档树中最深的节点)开始触发,然后向上传播至没有那么具体的元素(文档)

son - > father - > body - > html - > document(从内到外)

addEventListener(type, listener, false)

4. 事件解绑
		// 第一种:传统方式解绑
		const btn = document.querySelector('button')
        btn.onclick = function() {
            console.log('传统方式解绑');
            btn.onclick = null
        }
		// 第二种:事件监听方式的解绑
        const fn = function() {
            console.log('事件监听方式的解绑');
            btn.removeEventListener('click', fn)
        }
        btn.addEventListener('click', fn)
        // 我们解绑的时候, 需要传入一个函数名字, 表示解绑谁
        btn.removeEventListener('click', 没有函数名)

		// 建议: 不管是表达式,还是声明式, 都写在事件注册的前面.
        //  先声明, 在使用. 函数的定义, 写在调用的前面
      // 事件监听, 如果直接写匿名函数, 无法解绑
        btn.addEventListener('click', function() {
            console.log('你动不了我')
        })
5. 事件委托

利用事件冒泡 将事件监听绑定在父元素上 通过父元素来监听子元素的事件

  • 当我们使用事件委托的时候,使用**e.target.**tagName来判断我们点击的是否是想要的标签
  • 事件委托的好处(作用):减少事件注册的次数 提高程序性能
6. 页面加载事件
  • window ==> load 页面上所有的资源加载完执行 包括css、图片
  • document ==> DOMContentLoaded 只要DOM元素加载完 就执行回调
1. window ==> load
	// 等待页面所有资源都加载完毕后, 才执行回调函数里面的代码。(DOM元素加载完,CSS, 图片等都加载完)
    window.addEventListener('load', function(){
     	// js代码内容
    })
2. DOMContentLoaded
	// 当DOM元素加载完成时, 就会执行回调函数   不包含图片, 样式等。
	document.addEventListener('DOMContentLoaded', function(){
   		// js代码内容
	})
7. 滚动事件
// 被卷去的头部
document.documentElement.scrollTop === window.pageYOffset
// scrollTop 可读写  
被检测的元素.offsetTop
 // offsetTop 仅可读 被检测元素距离页面顶部的位置
8. 立即执行函数

Immediately-Invoked Function Expression (IIFE) 立即执行函数(自执行函数)

作用:

立即执行函数会形成一个单独的作用域,我们可以封装一些临时变量或者局部变量,避免污染全局变量

		// 1. 普通函数, 先声明, 后调用
        function fn() {
            console.log('我是普通函数')
        }
        fn() // 函数名加() 调用

        // 2. 立即执行函数 : 不需要调用,立马执行的函数 
		//  以() / [] 开头, 再前面需要加分号!
        ;(function() { /* code */ })()
        ;(function() { /* code */ }())
        // 3. 多个立即执行函数之间, 要用分号隔开
  例题:   
		;(function() {
            // 如果没写关键字, 会变为全局变量 成为window的属性
            num = 20
            console.log(num)
        })()
        console.log(num)  // 20

九、处理字符串的属性与方法

1. 去除字符串空格trim()
  • trim() 去除字符串左右两边的空格
  • 语法: str.trim()
  • 返回一个新的字符串,不会改变原来的字符串
const str = '          im a teacher  '
        console.log(str.trim())  // 'im a teacher'
2.数组转换为字符串
toString()

作用: 返回字符串。

join()
  • arr.join(分割符)
  • 作用: 把数组的所有元素连接成一个字符串, 并返回这个字符串。
  • 参数:可以传一个分割符, 也可以省略
	   // 1. 如果参数省略, 默认使用逗号分割
      const arr = ['red', 'pink', 'orange']
      console.log(arr.join()) 
      // 2. 传空字符串   直接将数组元素无间隙的连在一起
      const res = arr.join('')   
      // 3. 用分割符来拼接  (分割符可以自己定义)
      const res2 = arr.join('*')
3. 字符转换为数组split()
        let str2 = 'red, blue, purple';
        console.log(str2.split(','));  // [red, blue, purple]
4. 返回指定位置的字符charAt()
var str = "HELLO WORLD";
var n = str.charAt(2) // L

// 遍历字符串里面所有字符
	for (let i = 0; i < str1.length; i++) {
    	console.log(str1.charAt(i));
    }
		// 查找字符串'addjfirfcjasxaodofcjoao'中所有o出现的位置以及次数
        // 因为indexOf 只能查找到第一个 所以后面的查找 一定是当前索引号+1 从而继续查找
        let str = 'addjfirfcjasxaodofcjoao';
        let index = str.indexOf('o');
        let num = 0;
        while (index !== -1) {
            console.log(index);
            num++;
            index = str.indexOf('o', index + 1);
            // 因为indexOf 只能查找到第一个 所以后面查找 一定是当前索引号+1 从而继续查找
        }
        console.log('o出现的次数是:' + num);
   // 判断字符串 出现次数最多的字符 并统计其次数
        // obj.a=1
        // obj.b=1
        // obj.c=1
        let obj = {};
        for (let i = 0; i < str.length; i++) {
            let chars = str.charAt(i);
            if (obj[chars]) { //o[chars]得到的是属性值 
                obj[chars]++;
            } else {
                obj[chars] = 1;
            }
        }
        console.log(o);
5. 返回字符串首次出现位置indexOf()
  • indexOf() 方法可返回某个指定的字符串值在字符串中首次出现的位置
  • 如果没有找到匹配的字符串则返回 -1
  • indexOf 从前往后寻找字符串位置
const str = "hello world"
document.write(str.indexOf("lo") + "<br>"); // 3
6. 切片
substring()
  • 提取字符串中介于两个指定下标之间的字符
  • 返回字符串:[开始处的字符,结束处的字符)
const str = "hello world"
document.write(str.substring(3)+"<br>"); // lo world
document.write(str.substring(3,7)); // lo w
slice(start,end)
  • 可提取字符串的某个部分,并以新的字符串返回被提取的部分
  • 返回字符串:[start,end)
  • start 参数字符串中第一个字符位置为 0, 第二个字符位置为 1, 以此类推
  • end 参数如果为负数,-1 指字符串的最后一个字符的位置,-2 指倒数第二个字符,以此类推
substr()
        let str1 = '改革春风吹满地';
        console.log(str1.substr(2, 3));  // 春风吹
7. 替换字符replace()
        let str = 'addjfirfcjasxaodofcjoao';
        // 把字符里面所有的‘f’替换为‘*’
        while (str.indexOf('f') !== -1) {
            str = str.replace('f', '*')
        }
        console.log(str);
8. 将 Unicode 编码转为一个字符fromCharCode()
fromCharCode()
  • 将 Unicode 编码转为一个字符
const n = String.fromCharCode(65);  // A
9. 字符串样式
        let str = "hello world"
        // length big small fontcolor fontsize bold italics strike删除线 sub下 sup上
        // toUpperCase大写 link charAt concat连接字符串 indexOf lastindexOf slice
        document.write(str.length + "<br>");
        document.write(str.big().big().italics() + "2".sub() + "<br>");
        document.write(str.fontcolor('pink') + "<br>");
        document.write(str.link("http://www.baidu.com") + "<br>");

十、Date 对象

1. 实例化
  • **实例化:**通过构造函数生成实例对象的过程
  • **实例:**实例的例子 具体的某一个对象
		// 构造函数
        function Star(name, age) {
            this.name = name
            this.age = age
        }
        const ldh = new Star('刘德华', 20)
        console.log(ldh);

通过Star这个构造函数 创建出了刘德华这个具体的明星 这个过程叫做实例化

2. 常见的方法
let date = new Date()
date.getFullYear()  // 年
date.getMonth() // 月(0~11)
date.getDate()  // 日(1~31)
date.getDay()  // 星期(0~6)

date.getHours() //时
date.getMinutes()  //分
date.getSeconds()  //秒
date.getTime() 、date.now() // 时间戳 后者性能更好


date.toString());
> "Fri Sep 09 2022 01:04:24 GMT+0800 (中国标准时间)"
date.toDateString());
> "Fri Sep 09 2022"
date.toLocaleDateString(undefined, options);
> "2022年9月9日星期五"
date.toLocaleDateString();
> "2022/9/9"
date.toLocaleTimeString('en-US');
> "8:47:13 AM"
date.toLocaleTimeString();
> "08:47:13"
3. 倒计时
 	<div class="countdown">
        <!-- <p class="next">今天是2222年2月22日</p> -->
        <p class="title">倒计时</p>
        <p class="clock">
            <span id="day">00</span>
            <i>:</i>
            <span id="hour">00</span>
            <i>:</i>
            <span id="minutes">25</span>
            <i>:</i>
            <span id="scond">20</span>
        </p>
        <!-- <p class="tips">18:30:00下课</p> -->
    </div>
 	const getCountTime = function() {
            // 得到当前的时间戳
            const now = +new Date()
            const future = +new Date('2022-9-8 09:00:00')
            const time = (future - now) / 1000
                // 除以1000是为了得到秒数

            let d = parseInt(time / 60 / 60 / 24)
            let h = parseInt(time / 60 / 60 % 24)
            let m = parseInt(time / 60 % 60)
            let s = parseInt(time % 60)

            // 补 0
            d = d < 10 ? '0' + d : d
            h = h < 10 ? '0' + h : h
            m = m < 10 ? '0' + m : m
            s = s < 10 ? '0' + s : s

            // 将天、时、分、秒放入盒子
            const arr = [d, h, m, s]
            const spans = document.querySelectorAll('span')
            arr.forEach(function(item, index) {
                spans[index].innerHTML = item
            })

        }
        getCountTime()
        setInterval(getCountTime, 1000)

十一、节点操作

1. 父节点

文档: document 一个页面就是一个文档 window ==> document ==> html

元素: element 页面上所有的标签都叫元素

节点: node 页面上所有的内容都叫节点 : 元素节点 属性节点 文本节点 注释节点

父节点: node.parentNode 返回最近一级的父元素(节点) 如果找不到就返回null

2. 子节点
 	<ul>
        <li>1</li>
        <li>2</li>
        <li>3</li>
        <li>4</li>
        <li>5</li>
    </ul>
		// 1. 子节点 (元素/文本/属性/注释节点)
        // 语法: node.childNodes  node表示父元素
        const ul = document.querySelector('ul')
        console.log(ul.childNodes)
        // 返回值, 是一个伪数组: 有length, 有索引, 但是没有数组的pop()/push()等方法

        // 2. 子元素节点
        // 语法:node.children
        // 获取的是夫元素下的子元素节点(亲儿子)
        // 返回值:也是一个伪数组

        // 获取第一个子元素节点
        console.log(ul.children[0]);
        // 获取最后一个子元素节点
        console.log(ul.children[ul.children.length - 1]);
3.兄弟节点

node.parentNode 父节点
node.children 子元素节点(伪数组)
node.previousElementSibling 前一个兄弟元素节点
node.nextElementSibling 后一个兄弟元素节点

4. 增加节点

先创建(元素)节点/标签,再追加给父元素( 先创建 再追加)

  • 父元素.appendChild(要添加的元素)
  • 父元素.insertBefore(插入的元素,放在哪个元素前面)
  • insertBefore 与 appendChild不能同时对一个克隆对象进行操作
const ul = document.querySelector('ul')      
const li = document.createElement('li')
	li.innerHTML = '哈哈哈哈哈'   
	ul.appendChild(li)
	// appendChild 是在父元素的最后追加
        
const li2 = document.createElement('li')      
 	li2.innerHTML = '嘿嘿嘿嘿'
    ul.insertBefore(li2, ul.children[0])             
    // insertBefore 是在指定元素的前面追加         
5. 克隆节点
const copy_li1 = li1.cloneNode(true)  // 参数为true 为深拷贝
面试题:深拷贝与浅拷贝
共同点:复制
1. 浅拷贝:只复制引用,而未复制真正的值。
var arr1 = ['a','b','c','d'];
var arr2 = arr1;

var obj1 = {a:1,b:2}
var obj2 = Object.assign(obj1);

2. 深拷贝:是复制真正的值 (不同引用)
var obj3 = {
	a:1,
	b:2
}
var obj4 = JSON.parse(JSON.stringify( obj3 ));
6. 删除节点
  • node(父元素).removeChild(子元素)
  • 只能删除父节点下面最近一层的子节点 不能跨级删除

十二、BOM

  • BOM 浏览器对象模型, 把浏览器(顶级对象 window)当做一个对象
console.log(document === window.document) // true
  • DOM 文档对象模型, 把页面文档当做一个对象
  • 在全局作用域中, 用var声明的变量, 会成为window的属性;用const let 声明的变量,则不会成为window的属性
  • 全局作用域中用function声明的函数,会成为window对象的方法;用const声明的函数不会成为window对象的方法
1. location对象

属性:

​ location.href 记录了URL的完整地址. 可读写 , 所以还可以设置==>可以跳转

e.preventDefault() 阻止默认提交 阻止表单的action跳转 但是不会阻止代码的执行
form.action='http://baidu.com'

​ location.search 获取"?xxxxx"

​ location.hash 获取的是"#xxxx"

方法

​ location.reload() 方法 重新加载, 页面刷新

​ location.reload(true) 表示强制刷新。 清空缓存

2. navigator对象

检测 userAgent(浏览器信息)

userAgent记录了浏览器配置信息, 可以检测是Android 还是 IOS, 是移动端,还是PC

		;(function() {
            const userAgent = navigator.userAgent
                // 验证是否为Android或iPhone
            const android = userAgent.match(/(Android);?[\s\/]+([\d.]+)?/)
            const iphone = userAgent.match(/(iPhone\sOS)\s([\d_]+)/)
                // 如果是Android或iPhone,则跳转至移动站点
            if (android || iphone) {
                location.href = 'http://m.itcast.cn'
            }
        })();
3. history对象

返回上一页面

history.back(-1):直接返回当前页的上一页,数据全部消息,是个新页面
history.go(-1):也是返回当前页的上一页,不过表单里的数据全部还在 
history.back(-1) 
history.back();       //返回 

前进一页面

history.back(1) 前进 
history.go(1);         //前进  
history.forward();  //前进  
4. localStorage 本地存储
	面试题:
		localStorage 和 sessionStorage 有什么区别? 
		1. 生命周期  2. 数据共享 3.localStorage 和 sessionStorage的存储大小, 都是5M
  • 生命周期: 生命周期永久生效(数据一直存在), 除非手动删除, 否则关闭页面也会存在

    • 生命周期: 一个对象的创建到清除的过程, 数据存在的周期
  • 数据共享: 可以多窗口(页面)共享 , 同一个浏览器,同一个域名(地址)下

  • 数据以键值对的形式存储使用 key value, 存的是字符串的形式

    1. 存数据 localStorage.setItem(key, value)
     localStorage.setItem('user_name', '刘德华')
    // 如果key存在, 就是覆盖修改, 不存在, 就是新增一条数据
    
    1. 取数据 localStorage.getItem(key), 返回值就是我们存的value
    const res = localStorage.getItem('user_name')
    
    1. 删数据 localStorage.removeItem(key)
    localStorage.removeItem('user_name')
    
    1. 清空数据 localStorage.clear()
5. 本地存储复杂数据类型

复杂数据类型 在存入 localStorage / sessionStorage之前, 必须先转为字符串

JSON.stringify() : 将对象转换为JSON格式的字符串

localStorage.setItem('test_obj', JSON.stringify(obj))

JSON.parse() : 将JSON格式的字符串, 转换为对象形式。

const result = JSON.parse(localStorage.getItem('test_obj'))
6. sessionStorage 会话存储
  • 生命周期: 关闭浏览器窗口, 数据清除

  • 数据共享: 在同一个窗口(页面)下数据可以共享 (前提:同一个域名下)

  • 数据以键值对的形式存储使用 key value, 存的是字符串的形式

    1. 存数据 sessionStorage.setItem(key, value)
     sessionStorage.setItem('user_name', '刘德华')
    // 如果key存在, 就是覆盖修改, 不存在, 就是新增一条数据
    
    1. 取数据 sessionStorage.getItem(key), 返回值就是我们存的value
    const res = sessionStorage.getItem('user_name')
    
    1. 删数据 sessionStorage.removeItem(key)
    sessionStorage.removeItem('user_name')
    
    1. 清空数据 sessionStorage.clear()

十三、事件循环

1. JS是**单线程**的语言:

也就是同一时间只能做一件事件(同步), 所有的工作的顺序执行

  • 代码是从上到下,依次执行的, 逻辑是一步一步完成

why JS是单线程?

  • JS设计之初, 就是为了做网页交互, 那么就会操作DOM元素
2. 线程和进程

进程是资源分配的最小单位, 线程是CPU调度的最小单位

进程(process) : 一个进程就是一个正在运行的程序(打开任务管理器)
线程(thread) : 一个进程内执行着的每一个任务 (录屏程序: 录声音,录画面)

  • 线程是允许应用程序并发执行多个任务的一种机制
  • 进程 ==> 火车 , 线程 ==> 车厢

两者联系:

  1. 线程必须依附于进程存在 (单独的车厢无法运行)
  2. 一个进程可以包含多个线程 (一个火车可以有多个车厢)
3. 同步和异步

同步: 同一时间只能执行一个任务, 上一个任务执行完, 才能执行下一个任务
异步: 可以同时执行多个任务,提高了程序的执行效率

同步任务: 同步任务都在主线程上执行, 形成一个执行栈. 同步任务是依次执行的.
**异步任务:**JS的异步任务一般是通过回调函数来实现的, 在做某个任务的同时还可以处理其他任务

		 异步任务-常见的三种类型:
         1. 事件: click, resize 监听 回调函数
         2. 定时器: setTimeout / setInterval  回调
         3. 资源加载: load DOMContentLoaded 回调
        window.addEventListener('load', function(){})
       我们把执行的任务又分为 : 宏任务 macroTask,  微任务  microTask  

        宏任务: 
         1. 整个script代码块
         2. setTimeout 
         3. setInterval
         4. setImmediate

        微任务: 
        1. promise的回调 ==> promise.then()  promise.catch() 
        2. async await 
        3. mutationObserver  (vue源码)
        4. process.nextTick  (node)

        每执行完一个宏任务, 就会清空当前的所有微任务队列.
        JS执行机制, 事件循环EventLoop 
4. JS执行机制
js执行机制流程图
  1. 首先判断JS任务是同步任务, 还是异步任务. 同步任务会在主线程的执行栈中依次执行.

  2. 异步任务会提交给异步进程处理(setTimeout/ click事件等,此时异步进程也在执行相关的逻辑判断).

满足触发条件后, 异步进程会将异步任务(回调函数)放到任务队列(临时进行存放的一个空间)里面去

  1. 当主线程执行完所有的同步任务后, 会去任务队列中查看是否有可以执行的异步任务.

​ 如果有, 就拿到主线程中执行(立即性). 执行完之后再去任务队列里面查找, 依次循环.

十四、正则表达式

1. 定义与作用

正则表达式是什么?

  • 是用于匹配字符串中字符组合的模式

正则表达式有什么作用?

  • 表单验证(匹配)
  • 过滤敏感词(替换)
  • 字符串中提取我们想要的部分(提取)
2. 判断字符串是否符合规则:test()

用来查看正则表达式与指定的字符串是否匹配

reg.test(str) // 返回一个布尔值
3. 检索符合规则的字符串:exec()
  • 在一个指定字符串中执行一个搜索匹配
  • 如果匹配成功,exec() 方法返回一个数组,否则返回null
4. 元字符
  • 是一些具有特殊含义的字符
  • 可以极大提高了灵活性和 强大的匹配功能
1. 边界符
  • 提示字符所处的位置
边界符说明
^匹配行首的文本(以谁开始)
$匹配行尾的文本(以谁结束)

如果 ^ 和 $ 在一起,表示必须是精确匹配

2. 量词

设定某个模式出现的次数

量词说明
*>=0
+>=1
?1或者0
{n}=n
{n,}>=n
{n,m}>=n && <=m
3. 字符类

[ ] 匹配字符集合

  • 后面的字符串只要包含 abc 中任意一个字符,都返回 true

    /[abc]/.test('baby')  // true
    /[abc]/.test('cry')  // true
    /[abc]/.test('die')  // flase
    

    [ ]加上 - 连字符:表示一个范围

    /[abc]/.test('abc') // true
    /^[abc]$/.test('a') // true
    /^[abc]$/.test('abc') // false
    

    [ ] 里面加上 ^ 取反符号:匹配除了小写字母以外的字符

    ==> [^...] 里面写^表示取反, 不能是里面的任意一个字符. 
    ==> /^xxx/ 如果写到正则的最前面, 表示边界符, 以什么开头
    

    . 匹配除换行符之外的任何单个字符

    /n./.test('an') // false
    /n./.test('na') // true
    /.n/.test('an') // true
    /.n/.test('ab+n') // true
    
    • 预定义:某些常见模式的简写方式

      预定类说明
      \d==> [0-9]
      \D==> [ ^ 0-9]
      \w[A-Za-z0-9_]
      \W[^A-Za-z0-9_]
      \s匹配空格
      \S匹配非空格的字符
5. 修饰符
  • i,正则匹配时字母不区分大小写
  • g,匹配所有满足正则表达式的结果
  • replace 替换
str.replace(/正则表达式/,'替换的文本')
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值