WebAPI学习笔记

JavaScript的组成

  1. ECMAScript

ECMAScript定义了JavaScript的语法规范,是JavaScript的核心,描述了它的基本语法和数据类型。

ECMAScript是一套标准,与具体实现无关。

  • 各版本主要实现
  1. ES6(ES2015)
/*
 * let, const, class, modules, arrow functions, template string, destructuring, default, rest argument, binary data, promise等
 */
  1. ES7(ES2016)
/*
 * 完善ES6规范,求幂运算符*,array.prototype.includes等
 */
  1. ES8(ES2017)
/*
 * 原子,并发,Object.values/Object.entries,字符串填充,await/asyn等
 */
  1. WebAPI
  • 作用

WebAPI是浏览器提供的一套用于操作网页的API,可以让用户非常轻易地操作页面的元素以及浏览器的一些功能

  • 内容

主要由BOMDOM两部分组成

  • BOM

用于操作浏览器的一套API,可以借此使用浏览器窗口相关功能,如弹出框、控制浏览器跳转、获取分辨率等等

  • DOM

用于操作页面元素的一套API,将HTML当做一个文档树,使用DOM提供的API就可以对树上的节点进行操作

DOM

几个概念
  • 文档

document,指整个页面

  • 节点

node,页面中的任何内容,如文字、属性、标签、注释等

  • 元素

element,指标签节点

属性和方法
  • 页面标签和DOM对象
  • 固有属性

对于页面标签的固有属性,它们和DOM对象的属性是一一对应的,因此可以通过修改DOM对象的属性来间接实现对页面元素固有属性的修改

  • 自定义属性

指用户在页面标签中自定义的属性,这些属性都是非固有属性,通常用于存储数据


自定义属性无法使用document对象去获取,且获取的DOM对象,无法直接使用box.自定义属性名方式来获取自定义属性,需要使用以下api来操作自定义属性

  • box.getAttribute("属性名")

可以获取固有/自定义属性,不存在则返回null

  • box.setAttribute("属性名", "属性值")

设置属性值,可以是固有/自定义属性

  • box.removeAttribute("属性名")

移除属性,可以是固有/自定义属性

  • 获取元素的方法
  1. getElementById()
  • 说明

通过id获取标签节点,即获元素对象


<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Titletitle>
head>
<body>
<img id="demo" src="./static/img/test.png" alt="图片" title="图片"/>
<script>
    let img = document.getElementById("demo");
    setTimeout(() => {
        img.title = "美女";
    }, 3000);
script>
body>
html>
  • 注意
  1. 如果id不存在,则返回null,此时要注意不能再使用属性或方法,因为null.onclick等将会报错
  2. 部分浏览器对于含有id属性的元素,可以直接进行使用而不用先对该元素进行获取,但是不规范,所以不推荐
  1. getElementsByTagName()
  • 说明

指通过标签名来获取元素的DOM对象,由于相同的标签往往不止一个,所以获取到的返回值将是一个伪数组

  • 注意

如果标签不存在,一样会返回一个长度为0的伪数组

  1. getElementsByClassName()
  • 说明

getElementsByTagName()的区别在于是通过类名来获取元素对象

  • 注意

存在兼容性问题,IE678不支持该方法,一般不会用

  1. getElementsByName()
  • 说明

通过name属性来获取元素,返回值一样也是个伪数组

  • 注意

name属性可知,此方法仅限于获取表单元素

  1. 通过CSS选择器来获取元素
  • 说明
document.querySelector("selector"); //只会获取到一个元素,即使用的是如标签选择器等可以获取多个元素的选择器,最终也只会获取第一个元素
document.querySelectorAll("selector"); //可以获取多个元素,且无论获取到多少个,都将返回一个伪数组
// 当然,也可以是任意DOM对象:box.querySelectorAll
  • 注意

H5提供的新方法,IE678不支持

  • 其他方法
  • document.getSelection()

获取选中的元素

  • 常用属性
  • 文本操作属性
  • innerText
  • 说明

由IE浏览器设计出来的属性,获取到的是标签中的纯文本内容

  • 兼容性问题

低版本的火狐浏览器不支持该属性,且火狐浏览器自身也设计了一个textContent属性,该属性对于IE678同样不支持,当然,对于现代浏览器,这两种属性都能支持

  • 兼容性处理
function getText(element) {
    if(typeof element.innerText == "string") return element.innerText;
    else return element.textContext;
}
  • innerHTML
  • 说明

获取的是标签中的所有内容,即还包含了其中的子标签

  • innerText的共同点

box.innerText/innerHTML = "纯文字"结果都将会把box元素中的所有内容(包括其中的子标签),一律替换为 “纯文字”

  • innerText的不同点

box.innerText/innerHTML = "

文字

"innerText会将p标签当做文字处理,而innerHTML会把其解析成一个子标签,所以处于安全考虑,建议优先使用innerText

  • style属性
  • 说明

style是页面标签中的一个固有属性,而对于DOM,所有的DOM对象也对应有一个style对象,对象中的属性就对应页面标签的行内样式的所有可用属性

box.style.backgroundColor = "pink"; //注意要使用驼峰式写法
  • 注意

style对象操作的是行内样式,即一方面它无法获取非行内样式,另一方面它设置的是行内样式所以优先级较高

  • document的几个特殊属性
  • document.body:获取body元素
  • document.head:获取head元素
  • document.title:直接获取/修改title的内容
  • document.documentElement:获取html根标签元素
DOM文档树
  • 节点

标签中的属性属于标签自身的属性节点,标签中的文本属于标签的文本子节点,即页面中的任何内容都是节点,包括文本内容、标签、注释、属性等

  • 节点的查找
<ul>
    
    <li>第1个li元素li>
    <li id="two">第2个li元素li>
    <li>第3个li元素li>
ul>
  • 子节点相关API
  • ul.chlidNodes

获取所有(直接)子节点,共9个,即ul有9个子节点:换行、注释、换行、li标签、换行、li标签、换行、li标签、换行

  • ul.children

只获取(直接)子节点中的标签节点,共3个,即三个li标签子节点,和querySelectorAll的区别如下:

let lis_children = ul.children;
let lis_queryAll = ul.querySelectorAll("ul > li");
btn.onclick = function(){
    let li = document.createElement("li");
    ul.appendChild(li); //children是动态集合,即会同步后续添加的li,而querySelectorAll则是静态集合,即永远是原来的那些li
}
  • ul.firstChild
  • ul.lastChild

获取第一个/最后一个(直接)子节点,结果均为换行文本子节点

  • ul.firstElementChild
  • ul.lastElementChild

获取第一个/最后一个(直接)子节点中的标签节点,结果均为li标签子节点

  • 兄弟节点相关API
  • two.previousSibling
  • two.nextSibling

获取上一个兄弟节点:第2个li和第1个li之间的换行文本节点;获取下一个兄弟节点:第2个和第3个li之间的换行文本节点

  • two.previousElementSibling
  • two.nextElementSibling

获取上一个兄弟标签节点:li标签节点(

  • 第1个li
  • );获取下一个兄弟标签节点:li标签节点(
  • 第3个li
    • 父节点相关API
    • two.parentNode

    获取父节点,即ul节点

    • 节点的三个重要属性
    • nodeName:节点名称
    • nodeType:节点类型

    返回值是个数字,其中1表示标签节点

    • nodeValue:节点的值
    • 节点的方法
    • parent.appendChild(node)

    添加一个子节点为最后子节点,如果该子节点本身就是页面中的一个元素,则相当于是一个移动操作

    • parent.insertBefore(child, refChild)

    添加一个子节点child到指定子节点refChild之前,如果refChild为undefined,则等同于appendChild操作

    • node.cloneNode(deep)

    deep为布尔类型,表示是否需要进行深拷贝(不仅复制标签自身,还包括其中的子节点),默认false

    • parent.removeNode(child)

    移除指定子节点

    • 创建节点的几个方式
    1. document.write()

    可以解析标签(相当于实现了节点的创建),需要注意的是,如果页面已经加载完毕,再去执行此方法时(如由事件触发时),其写入的内容会将原来页面中body的内容覆盖,原因是页面从上往下加载时,会开启一个文档流,当加载完成时该文档流随之关闭,而执行该方法需要使用文档流,如果已关闭则会自己重新开启一个,以至将原来文档流内容覆盖了

    1. innerHTML

    一样可以解析标签,详情见文本属性

    1. document.createElement("tagName")

    和克隆一样,会在内存中创建一个标签节点,不会影响原有内容,推荐使用

        let h1 = document.createElement("h1");
        h1.innerText = "h1";
        box.appendChild(h1);
    
    AJAX
    • 简介

    Asynchronous Javascript And Xml,本质是基于HTTP协议,通过JS的XMLHttpRequest对象实现的异步请求。


    AJAX和 a标签 或 form表单提交 或 直接输入网址 一样,都是一种用于请求后台的方式,区别在于,其他的请求方式都会刷新当前页面,而AJAX可以在不刷新页面的情况下请求服务器,从而实现页面的局部数据更新

    • XMLHttpRequest

    一个浏览器的内置对象,用于与服务器进行通信(交换数据)

    xhr.getResponseHeader(key); //获取指定的响应头中的值
    xhr.getAllResponseHeaders(); //获取响应头中所有信息
    
    • get 和 post 请求
    //创建XMLHttpRequest对象
    let xhr = new XMLHttpRequest();
    
    //设置请求行
    xhr.open('get', 'get接口地址'); //get请求
    xhr.open('post', 'post接口地址'); //post请求
    
    //设置请求头
    xhr.setRequestHeader('context-type', 'text/html'); //post方法必须设置请求头
    
    //发送请求:参数为请求体
    xhr.send(null); //get无请求体
    xhr.send("name=zs&age=12"); //post可以设置请求体(查询字符串)
    
    //监听请求状态
    /**
     * xhr.readyState
     * 0:请求未初始化,即还没有调用open()方法
     * 1:请求已建立,但还没有发送,即还没有调用send()方法
     * 2:请求已发送,正在处理中
     * 3:请求正在处理中,通常响应中已有部分数据可用了,但是服务器还没有完成
     * 4:响应已经完成
     */
    xhr.onreadystatechange = function () {
        if (xhr.readyState === 4 && xhr.status === 200) {
            console.log(xhr.responseText);
        }
    }
    
    • XMLHttpRequest 2.0
    • 支持超时时间
    //设置在xhr.open()方法的后面
    xhr.timeout = 1000; //单位毫秒
    xhr.ontimeout = function(){}; //当超时时触发
    
    • FormData

    FormData是2.0新增的一个对象,用于管理表单数据,且表单中如果有input:file时,还将支持文件上传

    //指定要管理的表单
    let fd = new FormData(document.querySelector("form"));
    
    //可以添加非表单中的额外的数据
    fd.append('num', 1000000);
    
    let xhr = new XMLHttpRequest();
    //使用FormData,必须用post请求
    xhr.open("post", "...");
    
    //使用FormData,post请求可以不设置请求头(1.0必须设)
    
    //直接发送fd实例即可
    xhr.send(fd);
    xhr.onreadystatechange = function(){ //... };
    

    对于文件的上传,还可以监听文件上传进度

    //需在 xhr.send 方法前编写监听代码
    xhr.upload.onprogress = function(e) {
        //e.total:文件总大小
        //e.loaded:已上传文件大小
        (e.loaded / e.total) * 100 + "%"; //设置成width值即可。
    }
    
    • 前后端传递数据的通用格式
    • XML
    • 简介

    EXtensible Markup Language,即可扩展标记语言,和HTML的区别在于,HTML主要用于展示数据,且HTML的标签都是已经预定义的,而XML则主要用于存储和传输数据,其标签是可扩展、可自定义的

    • 语法规范
    1. 第一行必须是版本信息
    2. 必须有且仅有一个根元素
    3. 标签中不可有空格,且不可以以数据 或 . 开头,并区分大小写
    4. 不可以交叉嵌套,且都是双标签,如果是单标签则必须闭合
    5. 属性为双引号(浏览器会自动修正为双引号)
    6. 注释同HTML
    • 示例
    后端需设置 Content-type 为 text/xml
    
    
    <root>
        <person id="1">
            <name>zhangsanname>
            <sex>malesex>
            <age>19age>
            <hobby>footballhobby>
            <book>
                <type>comedytype>
                <name><<love>>name>
            book>
        person>
        <person id="2">
            <name>lisiname>
            <sex>femalesex>
            <age>21age>
        person>
    root>
    
    • JSON

    Javascript Object Notation,即js对象标记

    /**
    * 将json字符串转为json数据
    * JSON.parse(text, [, reviver])
    * text:必填,一个有效的json字符串
    * reviver:选填,可以理解为是个map算子,对象的每个成员都会调用此函数
    */
    let jsonStr = '{"name":"zhangsan","sex":"male","address":"henan"}';
    let jsonData = JSON.parse(jsonStr, ((key, value) => {
      if (key === "sex" && value === 'male') return "man";
       else if (key === "sex" && value === "female") return "woman";
       else return value;
    }));
    console.log(jsonData); //{ name: 'zhangsan', sex: 'man', address: 'henan' }
    
    /**
    * 将json数据转为json字符串
    * JSON.stringify(value[, replacer[, space]])
    * value:必填,代表一个json数据的对象或数组
    * replacer:选填,可以是个函数或数组
    *          如果是函数,效果类似上面的reviver函数;
    *          如果是个数组,存放key值,表示只保留这些key对应的key-value数据。
    * space:选填,可以是空格,换行符,制表符等,表示文本在每个级别中进行缩进的形式,如果是数字则表示缩进的空格数
    */
    let jsonString1 = JSON.stringify(jsonData, (key, value) => {
       if (key === "sex" && value === 'man') return "male";
       else if (key === "sex" && value === "woman") return "female";
       else return value;
    }, '\t');
    console.log(jsonString1);
    // 输出如下:
    // {
    //     "name": "zhangsan",
    //     "sex": "male",
    //     "address": "henan"
    // }
    
    let jsonString2 = JSON.stringify(jsonData, ['sex', 'name'], '  ');
    console.log(jsonString2);
    // 输出如下:
    // {
    //   "sex": "man",
    //   "name": "zhangsan"
    // }
    
    • ajax的同步形式
    //由open方法的第三个参数决定,默认true,表示异步,如果修改为false,则表示同步
    xhr.open("get", "./index.php", false);
    
    • 命名空间与ajax的封装
    • 命名空间

    项目组分配给个人的一个"变量名",该变量全局唯一,用于解决命名冲突、命名全局污染问题

    • AJAX的封装
    let xxx = {
        ajax(obj) {
            let url = obj.url || location.href;
            let type = obj.type || 'get';
            let args = this.argHandler(obj.args);
            let callback = obj.callback;
            let xhr = new XMLHttpRequest();
            if (type === 'get') {
                url = url + "?" + args;
                args = null;
            }
            xhr.open(type, url);
            if (type === 'post') {
                xhr.setRequestHeader('content-type', 'application/x-www-form-urlencoded');
            }
            xhr.send(args);
            xhr.onreadystatechange = function () {
                if (xhr.readyState === 4 && xhr.status === 200) {
                    callback && callback();
                }
           }
        },
        argHandler(args) {
            let res = [];
            if (args) {
                for (let key in args) {
                    if (args.hasOwnProperty(key)) {
                        res.push(key + '=' + args[key]);
                    }
                }
                res = res.join('&');
            }
            return res.length ? res : "";
        }
    };
    
    • ajax和绑定事件的失效问题

    如果绑定事件的元素是通过AJAX动态生成的,很大可能存在执行到主线程中该元素事件时,该元素仍未生成问题,最终的现象就是该元素所绑定的事件不生效


    该问题无法通过入口函数的方式解决,因为入口函数不会感知AJAX,可通过事件委托方式解决

    BOM

    • 简介

    指浏览器对象模型, 提供了一套用于操作浏览器相关功能的API

    • 主要内容
    1. frames
    2. history

    用于操作浏览器历史记录的对象,常用以下属性和方法

    • history.back

    后退,回到之前页

    • history.forward

    前进,进入后一页

    • history.go(数字)

    前进/后退指定页数,数字为正表示前进,为负则是后退

    1. location

    相当于浏览器地址栏对应的对象,常用一下属性和方法

    • location.href

    获取到当前页面地址栏中的完整链接地址

    • location.href = "http:/..."

    跳转到指定页面

    • location.href = ""

    空串表示刷新当前页面

    • location.reload()

    表示刷新页面

    • location.hash

    获取url的锚点,即#及之后的内容

    • location.host

    获取 ip + port

    • location.hostname

    获取 ip

    • location.port

    获取 port

    • location.pathname

    获取 port 之后的内容: /文件路径.html

    • location.search

    获取 ? 开始 + 参数

    • location.protocal

    获取协议部分,如 http

    • location.origin

    获取 协议 + ip + port

    1. navigator

    用于获取客户福安相关信息的对象

    • navigator.userAgent

    获取用于代理信息,包括浏览器版本、操作系统、浏览器内核等内容,不过可能会罗列出所有可能的浏览器,所以信息不会很准确,而且用于可以修改浏览器的这些信息

    1. screen

    用于获取屏幕相关信息的对象,常用以下属性和方法

    • screen.width

    获取电脑屏幕的宽度,是一个固定值

    • screen.height

    获取电脑屏幕的高度,是一个固定值

    • screen.availWidth

    获取浏览器可以占用的总宽度

    • screen.availHeight

    获取浏览器可以占用的总高度

    window对象

    • 简介

    是js中的一个全局对象,一个顶级对象,BOM和DOM中的属性和方法都输与window,比如常用的document,alert(),console.log()等,只不过对于window对象中属性和方法的使用可以省略window的书写

    • window.onload

    入口函数,在页面以及外部资源,如图片、css、js等加载完成之后才会执行,并且一个页面只有一个入口函数会生效,即使写了多个,后面的会将前面的覆盖

    • 常用方法
    • open()

    用于打开一个窗口

    window.open(url, [name], [features])
    /*
     * url:打开的窗口的地址
     * name:可选,新窗口名称,一方面可以通过window.name获取该名称,另一方面他还有个作用,就是对于点击打开窗口,浏览器会先通过name判断是否已经打开过该窗口,如果打开过则会在已打开的该窗口中执行刷新操作,而非重复地打开
     * features:可选,用于指定新窗口的特性,如指定窗口的大小等
     * 返回值:返回该创建的窗口对象,后续可通过此对象对该窗口进行关闭
     */
    
    let w = window.open("http://www.baidu.com", "百度", "width=300, height=300, top=100, left=100");
    w.close(); //关闭此窗口
    
    • close()

    window.close()表示关闭当前窗口

    • getComputedStyle()

    获取在元素计算后的样式,即元素上真正起着效果的样式

    window.getComputedStyle(元素, 伪类);
    /*
     * 元素:要获取样式的目标元素
     * 伪类:表示获取元素伪类的样式,一般不需要,填写null即可
     * 返回值:返回的是一个对象,其中包含了该元素所有的计算样式
     * 兼容性:IE678不兼容,使用的是element.currentStyle[attr]
     */
    
    • 延时器
    let timer = setTimeout(function() { //... }, delay);
    /*
     * delay:延时的时间,单位毫秒,该时间并不准确,只能说至少需要这些时间,因为事件队列中可能还有其他回调函数要处理,或者是还有很多同步代码要执行
     */
    clearTimeout(timer); //清除指定的延时器
    
    • 定时器
    let interval = setInterval(function(){ //... }, interval);
    /*
     * interval:定时器的时间间隔,单位毫秒
     */
    clearInterval(interval); //清除指定的定时器
    //定时器中的this指向问题
    setInterval(function(){
        console.log(this); //定时器中的this指向的是window
    }, 1000);
    

    事件

    • 简介

    javascript是基于事件驱动的,而事件则是一种 触发-响应 机制,有三要素构成:

    1. 事件源

    触发事件的元素

    1. 事件名称

    click为点击事件的名称

    1. 事件处理程序

    事件触发后要执行的代码

    • 事件中的 this

    指向的是触发事件的那个元素

    
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Titletitle>
        <style>
            input[type="button"] {
                width: 50px;
                height: 50px;
                line-height: 50px;
                text-align: center;
                background-color: salmon;
                border: none;
                outline-style: none;
            }
            .hotpink {
                background-color: hotpink!important;
            }
        style>
    head>
    <body>
    <input type="button" value="变色" />
    <input type="button" value="变色" />
    <input type="button" value="变色" />
    <input type="button" value="变色" />
    <input type="button" value="变色" />
    <script>
        let btns = document.getElementsByTagName("input");
        for(let i = 0; i < btns.length; i++) {
            btns[i].onclick = function () {
                console.log(this)
                this.className = "hotpink"; //注意此处不能用btns[i].className的方式,因为当点击时此处代码已经遍历完成,i的值已经成了最大值,只会最后一个按钮会变色
            }
        }
    script>
    body>
    html>
    
    • 常用事件

    onclick:点击事件
    ondblclick:双击事件
    onmousemove:鼠标页面移动事件
    onmousewheel:鼠标滚轮事件
    onmouseover:鼠标移入事件
    onmouseout:鼠标移出事件
    onmouseenter:鼠标进入事件(不支持事件冒泡)
    onmouseleave:鼠标离开事件(不支持事件冒泡)
    onfocus:聚焦事件
    onblur:失焦事件
    onkeydown:键盘按下事件
    onkeyup:键盘弹起事件
    onmousedown:鼠标按下事件
    onmouseup:鼠标弹起事件
    onscroll:滚动条滚动事件
    onresize:窗口大小变动事件

    • onchange

    对于 ,