(二)JS-Web-API知识梳理

知识点梳理

  • BOM 操作
  • DOM 操作
  • 事件绑定
  • Ajax
  • 存储

BOM

BOM(浏览器对象模型)是浏览器本身的一些信息的设置和获取,例如获取浏览器的宽度、高度,设
置让浏览器跳转到哪个地址。

  • navigator
  • screen
  • location
  • history

常用功能的代码示例
获取浏览器特性(即俗称的 UA )然后识别客户端,例如判断是不是 Chrome 浏览器

var ua = navigator.userAgent
var isChrome = ua.indexOf('Chrome')
console.log(isChrome)
// 获取屏幕的宽度和高度

console.log(screen.width)
console.log(screen.height)
// 获取网址、协议、path、参数、hash 等
console.log(location.href) 
console.log(location.protocol) // https:
console.log(location.pathname) // /timeline/frontend
console.log(location.search) // ?a=10&b=10
console.log(location.hash) // #some
// 调用浏览器的前进、后退功能等
history.back()
history.forward()
复制代码

DOM

服务器把 HTML发送给浏览器,浏览器需要把 HTML 转变成 DOM才能识别,HTML 是一棵树,DOM 也是一棵树。对 DOM
的理解,可以暂时先抛开浏览器的内部因素,先从 JS 着手,即可以认为 DOM 就是 JS 能识别的 HTML
结构,一个普通的 JS 对象或者数组。

image.png

获取DOM节点

// 通过 id 获取
var div1 = document.getElementById('div1') // 元素
// 通过 tagname 获取
var divList = document.getElementsByTagName('div') // 集合
console.log(divList.length)
console.log(divList[0])
// 通过 class 获取
var containerList = document.getElementsByClassName('container') // 集合
// 通过 CSS 选择器获取
var pList = document.querySelectorAll('p') // 集合

复制代码

property

DOM 节点就是一个 JS 对象,它符合之前讲述的对象的特征 —— 可扩展属性

都是 JS 范畴的属性,符合 JS 语法标准的。

attribute

attribute 是直接改变 HTML 的属性

get 和 set attribute 时,还会触发 DOM 的查询或者重绘、重排,频繁操作会影响页面性能

DOM 树操作

// 新增节点
var div1 = document.getElementById('div1')
// 添加新节点
var p1 = document.createElement('p')
p1.innerHTML = 'this is p1'
div1.appendChild(p1) // 添加新创建的元素
// 移动已有节点。注意,这里是“移动”,并不是拷贝
var p2 = document.getElementById('p2')
div1.appendChild(p2)
// 获取父元素
var div1 = document.getElementById('div1')
var parent = div1.parentElement
// 获取子元素
var div1 = document.getElementById('div1')
var child = div1.childNodes
// 删除节点
var div1 = document.getElementById('div1')
var child = div1.childNodes
div1.removeChild(child[0])

复制代码

事件

var btn = document.getElementById('btn1')
btn.addEventListener('click', function (event) {
// event.preventDefault() // 阻止默认行为
// event.stopPropagation() // 阻止冒泡
console.log('clicked')
})

复制代码
// 通用的事件绑定函数
function bindEvent(elem, type, fn) {
elem.addEventListener(type, fn)
}
var a = document.getElementById('link1')
// 写起来更加简单了
bindEvent(a, 'click', function(e) {
e.preventDefault() // 阻止默认行为
alert('clicked')
})
复制代码

冒泡

<body>
<div id="div1">
<p id="p1">激活</p>
<p id="p2">取消</p>
<p id="p3">取消</p>
<p id="p4">取消</p>
</div>
<div id="div2">
<p id="p5">取消</p>
<p id="p6">取消</p>
</div>
</body>


// 要求点击 p1 时候进入激活状态,点击其他任何 <p> 都取消激活状态
var body = document.body
bindEvent(body, 'click', function (e) {
// 所有 p 的点击都会冒泡到 body 上,因为 DOM 结构中 body 是 p 的上级节点,事件会沿着
DOM 树向上冒泡
alert('取消')
})
var p1 = document.getElementById('p1')
bindEvent(p1, 'click', function (e) {
e.stopPropagation() // 阻止冒泡
alert('激活')
})

复制代码

事件代理

<div id="div1">
<a href="">a1</a>
<a href="">a2</a>
<a href="">a3</a>
<a href="">a4</a>
</div>
<button>点击增加一个 a 标签</button>


事件代理:
function bindEvent(elem, type, selector, fn) {
// 这样处理,可接收两种调用方式 bindEvent(div1, 'click', 'a', function () {...})
和 bindEvent(div1, 'click', function () {...}) 这两种
if (fn == null) {
    fn = selector
    selector = null
}
// 绑定事件
elem.addEventListener(type, function (e) {
var target
if (selector) {
    // 有 selector 说明需要做事件代理
    // 获取触发时间的元素,即 e.target
    target = e.target
    // 看是否符合 selector 这个条件
    if (target.matches(selector)) {
        fn.call(target, e)
    }
} else {
    // 无 selector ,说明不需要事件代理
    fn(e)
}
})
}

// 使用代理,bindEvent 多一个 'a' 参数
var div1 = document.getElementById('div1')
bindEvent(div1, 'click', 'a', function (e) {
    console.log(this.innerHTML)
})

复制代码

Ajax

XMLHttpRequest

// 手写 XMLHttpRequest
var xhr = new XMLHttpRequest()
xhr.onreadystatechange = function () {
// 这里的函数异步执行,可参考之前 JS 基础中的异步模块
if (xhr.readyState == 4) {
    if (xhr.status == 200) {
        alert(xhr.responseText)
    }
  }
}
xhr.open("GET", "/api", false)
xhr.send(null)

// 状态码说明
xhr.readyState 的状态码说明:
0 -代理被创建,但尚未调用 open() 方法。
1 - open() 方法已经被调用。
2 - send() 方法已经被调用,并且头部和状态已经可获得。
3 -下载中, responseText 属性已经包含部分数据。
4 -下载操作已完成

xhr.status 即 HTTP 状态码,有 2xx 3xx 4xx 5xx 这几种,比较常用的有以下几种:
200 正常
3xx
301 永久重定向。如 http://xxx.com 这个 GET 请求(最后没有 / ),就会被 301 到
http://xxx.com/ (最后是 / )
302 临时重定向。临时的,不是永久的
304 资源找到但是不符合请求条件,不会返回任何主体。如发送 GET 请求时,head 中有
If-Modified-Since: xxx (要求返回更新时间是 xxx 时间之后的资源),如果此时服务器
端资源未更新,则会返回 304 ,即不符合要求
404 找不到资源
5xx 服务器端出错了
复制代码

Fetch API

通过 Fetch 提供的 fetch() 这个全局函数
方法可以很简单地发起异步请求,并且支持 Promise 的回调。

fetch('some/api/data.json', {
    method:'POST', //请求类型 GET、POST
    headers:{}, // 请求的头信息,形式为 Headers 对象或 ByteString
    body:{}, //请求发送的数据 blob、BufferSource、FormData、URLSearchParams(get 或
    head 方法中不能包含 body)
    mode:'', //请求的模式,是否跨域等,如 cors、 no-cors 或 same-origin
    credentials:'', //cookie 的跨域策略,如 omit、same-origin 或 include
    cache:'', //请求的 cache 模式: default、no-store、reload、no-cache、 force-cache
或 only-if-cached
}).then(function(response) { ... });

Fetch 支持 headers 定义,通过 headers 自定义可以方便地实现多种请求方法( PUT、GET、POST
等)、请求头(包括跨域)和 cache 策略等;除此之外还支持 response(返回数据)多种类型,
复制代码

跨域

url 哪些地方不同算作跨域?
协议
域名
端口

但是 HTML 中几个标签能逃避过同源策略—— <script src="https://juejin.cn/post/xxx"> 、 <img src="https://juejin.cn/post/xxxx"/> 、 <link
href="https://juejin.cn/post/xxxx"> ,这三个标签的 src/href 可以加载其他域的资源,不受同源策略限制。
复制代码
  • 解决跨域 – JSONP

  • 解决跨域 – 服务器端设置 http header

response.setHeader("Access-Control-Allow-Origin", "http://m.juejin.com/"); //
第二个参数填写允许跨域的域名称,不建议直接写 "*"
response.setHeader("Access-Control-Allow-Headers", "X-Requested-With");
response.setHeader("Access-Control-Allow-Methods",
"PUT,POST,GET,DELETE,OPTIONS");
// 接收跨域的cookie
response.setHeader("Access-Control-Allow-Credentials", "true");

复制代码

存储

  • cookie
cookie 本身不是用来做服务器端存储的(计算机领域有很多这种“狗拿耗子”的例子,例如 CSS 中的
float),它是设计用来在服务器和客户端进行信息传递的,因此我们的每个 HTTP 请求都带着
cookie。但是 cookie 也具备浏览器端存储的能力(例如记住用户名和密码),因此就被开发者用上
了。

存储量太小,只有 4KB
所有 HTTP 请求都带着,会影响获取资源的效率
API 简单,需要封装才能用

复制代码
  • localStorage 和 sessionStorage

针对 localStorage.setItem ,使用时尽量加入到 try-catch 中,某些浏
览器是禁用这个 API 的

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享