JS Web API
JS基础知识,规定语法(ECMA 262标准)
JS Web API,网页操作的API(W3C标准)
前者是后者的基础,两者结合才能真正实际应用
DOM
前言
vue 和 React 框架应用广泛,封装了 DOM 操作
但 DOM 操作一直都是前端工程师的基础、必备知识
只会 vue 而不懂 DOM 操作的前端程序员,不会长久
题目
DOM是哪种数据结构
DOM操作的常用API
attr 和 property的区别
property
:修改对象属性,不会体现到 html 结构中
attribute
:修改 html 属性,会改变 html 结构
两者都有可能引起 DOM 重新渲染
一次性插入多个DOM节点,考虑性能
知识点
DOM本质
<!-- 可自定义标签 -->
<?xml version="1.0" encoding="UTF-8" ?>
<note>
<to> Tove</to>
<form> Jani</from>
<heading> Reminder</heading>
<body> Don't forget me this weekend!</body>
<other>
<a></a>
<b></b>
</other>
</note>
<!-- 不可自定义标签 -->
<!DOCTYPE html>
< html >
< head >
< meta charset = "UTF-8" >
< title > Document</ title >
</ head >
< body >
< div >
< p > this is a p</ p >
</ div >
</ body >
</ html >
- 本质是棵树
DOM节点操作
获取DOM节点
const div1 = document . getElementById ( 'div1' ) // 元素
const divList = document . getElementsByTagName ( 'div' ) // 集合
console . log ( divList . length )
console . log ( divList [ 0 ])
const containerList = document . getElementsByClassName ( 'container' )
// 集合
const pList = document . querySelectorAll ( 'p' ) // 集合
attribute
const pList = document . querySelectorAll ( 'p' )
const p = pList [ 0 ]
p . getAttribute ( 'data-name' )
p . setAttribute ( 'data-name' , 'imooc' )
p . getAttribute ( 'style' )
p . setAttribute ( 'style' , 'font-size:30px' )
property
形式
const pList = document . querySelectorAll ( 'p' )
const p = pList [ 0 ]
console . log ( p . style . width ) // 获取样式
p . style . width = '100px' // 修改样式
console . log ( p . className ) // 获取class
p . className = 'p1' // 修改class
// 获取 nodeName 和 nodeType
console . log ( p . nodeName )
console . log ( p . nodeType ) // 1
DOM结构操作
新增/插入节点
const div1 = document . getElementById ( 'div1' )
// 添加新节点
const p1 = document . createElement ( 'p' )
p1 . innerHTML = 'this is p1'
div1 . appendChild ( p1 ) // 添加新创建的元素
// 移动已有节点。注意是移动!!!
const p2 = document . getElementById ( 'p2' )
div1 . appendChild ( p2 )
获取子元素列表,获取父元素
// 获取父元素
console . log ( p1 . parentNode )
// 获取子元素列表
const div1ChildNodes = div1 . chindNodes
console . log ( div1 . childNodes )
const div1ChildNodesP = Array . prototype . slice . call ( div1 . childNodes ). filter ( child => {
if ( child . nodeType === 1 ){
return true
}
return false
})
console . log ( 'div1ChildNodesP' , div1ChildNodesP )
删除子元素
const div1 = document . getElementById ( 'div1' )
const child = div1 . childNodes
div1 . removeChild ( child [ 0 ])
DOM性能
DOM操作非常“昂贵”,避免频繁的DOM操作
对DOM查询做缓存
// 不缓存 DOM 查询结果
for ( let i = 0 ; i < document . getElementsByTagName ( 'p' ). length ; i ++ ) {
// 每次循环,都会计算 length,频繁进行 DOM 查询
}
// 缓存 DOM 查询结果
const pList = document . getElementsByTagName ( 'p' )
const length = pList . length
for ( let i = 0 ; i < length ; i ++ ) {
// 缓存 length,只进行一次 DOM 查询
}
将频繁操作改为一次性操作
const listNode = document . getElementById ( 'list' )
// 创建一个文档片段,此时还没有插入到 DOM 树中
const frag = document . createDocumentFragment ()
// 执行插入
for ( let x = 0 ; x < 10 ; x ++ ) {
const li = document . createELement ( "li" )
li . innerHTML = "List item " + x
frag . appendChild ( li )
}
// 都完成之后,再插入到 DOM 中
listNode . appendChild ( frag )
BOM
题目
如何识别浏览器的类型
分析拆解url各个部分
知识点
navigator
const ua = navigator . userAgent
const isChrome = ua . indexOf ( 'Chorme' )
console . log ( isChrome )
screen
console . log ( screen . width )
console . log ( screen . height )
location
location . href // https://coding.imooc.com/class/chapter/115.html?a=100&b=200#Anchor
location . protocol // https
location . host // 'coding.imooc.com'
console . log ( location . pathname ) // "/class/chapter/115.html"
console . log ( location . search ) // "?a=100&b=200"
console . log ( location . hash ) // "#Anchor"
history
history . back () // 后退
history . forward () // 前进
事件
题目
编写一个通用的事件监听函数
// 通用的事件绑定函数
function bindEvent ( elem , type , selector , fn ) {
if ( fn == null ) {
fn = selector
selector = null
}
elem . addEventListener ( type , event => {
const target = event . target
if ( selector ) {
// 代理绑定
if ( target . matches ( selector )) {
fn . call ( target , event )
}
} else {
// 普通绑定
fn . call ( target , event )
}
})
}
// 普通绑定
const btn1 = document . getElementById ( 'btn1' )
bindEvent ( btn1 , 'click' , fucntion ( event ) {
// console.log(e.target) // 获取触发的元素
event . preventDefault () // 阻止默认行为
alert ( this . innerHTML )
})
// 代理绑定
const div3 = document . getElementById ( 'div3' )
bindEvent ( div3 , 'click' , 'a' , fucntion ( event ) {
event . preventDefault ()
alert ( this . innerHTML )
})
描述事件冒泡的流程
基于DOM树形结构
事件会顺着触发元素往上冒泡
应用场景:代理
无限下拉的图片列表,如何监听每个图片的点击?
事件代理
用 e.target
获取触发元素
用 metches
来判断是否是触发元素
知识点
事件绑定
const btn = document . getElementById ( 'btn1' )
btn . addEventListener ( 'click' , event => {
console . log ( 'clicked' )
})
// 通用的绑定函数
function bindEvent ( elem , type , fn ) {
elem . addEventListener ( type , fn )
}
const a = document . getElementById ( 'link1' )
bindEvent ( a , 'click' , e => {
// console.log(e.target) // 获取触发的元素
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 >
const p1 = document . getElementById ( 'p1' )
const body = document . body
bindEvent ( p1 , 'click' , e => {
e . stopPropagation () // 阻止冒泡
alert ( '激活' )
})
bindEvent ( body , 'click' , e => {
alert ( '取消' )
})
事件代理
代码简洁
减少浏览器内存占用
但是,不要滥用
< div id = "div1" >
< a href = "#" > a1</ a >< br />
< a href = "#" > a2</ a >< br />
< a href = "#" > a3</ a >< br />
< a href = "#" > a4</ a >< br />
</ div >
< button > 加载更多...</ button >
const div1 = document . getElementById ( 'div1' )
div1 . addEventListener ( 'click' , e => {
event . preventDefault ()
const target = e . target
if ( target . nodeName === 'A' ) {
alert ( target . innerHTML )
}
})
ajax
题目
手写一个简易的ajax
function ajax ( url , successFn ) {
const xhr = new XMLHttpRequest ()
xhr . open ( "GET" , url , true )
xhr . onreadystatechange = function () {
if ( xhr . readyState === 4 ) {
if ( xhr . status == 200 ) {
successFn ( xhr . responseText )
}
}
}
xhr . send ( null )
}
function ajax ( url ) {
const p = new Primise (( resolve , reject ) => {
const xhr = XMLHttpRequest ()
xhr . open ( "GET" , url , true )
xhr . onreadtstatechangee = function () {
if ( xhr . readyState === 4 ) {
if ( xhr . status === 200 ) {
resolve (
JSON . prase ( xhr . responseText )
)
} else if ( xhr . status === 404 ) {
reject ( new Error ( '404 not found' ))
}
}
}
})
return p
}
const url = '/data/test.json'
ajax ( url ). then (
res => console . log ( res )
). catch (
err => console . error ( err )
)
跨域的常用实现方式
知识点
XMLHttpRequest
// get 请求
const xhr = new XMLHttpRequest ()
xhr . open ( "GET" , "/api" , true ) // true 代表异步请求 false 同步
xhr . onreadystatechange = function () {
if ( xhr . readyState === 4 ) {
if ( xhr . status === 200 ) {
// console.log(
// JSON.parse(xhr.responseText)
// )
alert ( xhr . responseText )
} else {
console . log ( '其他情况' )
}
}
}
xhr . send ( null )
// post 请求
const xhr = new XMLHttpRequest ()
xhr . open ( "POST" , "/login" , true ) // true 代表异步请求 false 同步
xhr . onreadystatechange = function () {
if ( xhr . readyState === 4 ) {
if ( xhr . status === 200 ) {
// console.log(
// JSON.parse(xhr.responseText)
// )
alert ( xhr . responseText )
} else {
console . log ( '其他情况' )
}
}
}
const postData = {
userName : 'zhangsan' ,
password : 'xxx'
}
xhr . send ( JSON . stringify ( postData )) // 字符串
状态码
xhr.readyState
0 - (未初始化)还没有调用send()方法
1 - (载入)已调用send()方法,正在发送请求
2 - (载入完成)send()方法执行完成,已经接受到全部响应内容
3 - (交互)正在解析响应内容
4 - (完成)响应内容解析完成,可在客户端调用
xhr.status
2xx - 表示成功处理请求,如 200
3xx - 需要重定向,浏览器直接跳转,如 301 302 304
4xx - 客户端请求错误,如404(url不对) 403(没权限)
5xx - 服务端错误
跨域
跨域:同源策略,跨域解决方案(仅浏览器机制)
所有的跨域,都必须经过server端允许和配合
未经server端允许就实现跨域,说明浏览器有漏洞,危险信号
什么是跨域(同源策略)
ajax请求时,浏览器要求当前网页和server必须同源(安全)
同源:协议、域名、端口,三者必须一致
前端:http://a.com:8080/
; server: https://b.com/api/xxx
(存在跨域)
加载图片css js可无视同源策略
img
标签 可用于统计打点,可使用第三方统计服务
link
标签 可使用CDN,CDN一般都是外域
script
标签 可使用CDN,CDN一般都是外域;可实现JSONP
JSONP
srcipt
可绕过跨域限制
服务端可以任意动态拼接数据返回
所以,script
就可以获得跨域的数据,只要服务端愿意返回
CORS(服务端设置 http header)
cors
存储
题目
描述cookie localStorage sessionStorage区别
容量
API易用性
是否跟随http请求发送出去
知识点
cookie
本身用于浏览器和server
被“借用”到本地存储来
可用document.cookie = '...'
来修改
cookie的缺点
存储大小,最大4KB
http请求时需要发送到服务端,增加请求数据量
只能用 document.cookie = '...'
来修改,太过简陋
localStorage 和 sessionStorage
HTML5专门为存储而设计,最大可存5M
API简单易用 setItem getItem
不会随着 http 请求被发送出去
localStorage 和 sessionStorage 区别
localStorage 数据会永久存储,除非代码或手动删除
sessionStorage 数据只存在于当前对话,浏览器关闭则清空
一般用 localStorage 会更多一些
2023-09-25 07:56:30
2023-09-13 09:24:06