# 笔记
# 2021 年 8 月 9 日
# 闭包
闭包是指有权访问另一个函数作用域中的变量的函数 TODO: 闭包、面向对象的程序设计
# 2021 年 8 月 10 日
# BOM
// Chrome
window.innerWidth = document.documentElement.clientWidth + '滚动条宽度' = '可视区域宽度'
window.innerHeight = document.documentElement.clientHeight '可视区域高度'
window.outerWidth = '浏览器宽度'
window.outerHeight = '浏览器高度'
# 客户端能力检测(兼容性检测)
建议用属性判断而非浏览器判断
// 兼容低版本ie获取DOM对象
if (document.getElementById) {
return document.getElementById(id)
} else if (document.all) {
return document.all(id)
}
# 2021 年 8 月 11 日
# 客户端检测(userAgent)
电子欺骗
:浏览器通过在自己的用户代理字符串加入一些错误或误导性的信息,来达到欺骗服务器的目的- 通过加入一些目的性的代理字符串,使一些站点的嗅探程序(检测程序)能够命中并识别,以便站点能够“信任”它与其他流行的浏览器是兼容的(理解为网站 W 有嗅探程序 X,X 可以检测并命中浏览器 A 但不能命中 B 浏览器,B 浏览器为了也能被 X 命中,就往用户代理中加入 A 的某些特征代理字符串,以便 X 可以识别 B。让用户知道 B 浏览器也能跑 W 站点甚至更多,达到留住用户的目的)
# Node 类型
- 判断是否有子节点:hasChildNodes()
- previousSibling、nextSibling 分别为前一个兄弟节点,后一个兄弟节点
- 插入到指定位置:insertBefore(newNode, someNode)
- 替换节点:replaceChild(newNode, someNode)
- 删除节点:removeChild()
- 复制节点:cloneNode(Boolean),true 时表示深拷贝
- document.createDocumentFragment() 创建文档碎片(仓库),不会占用额外的资源。在操作真实 DOM 前的所有操作都可以在这个“仓库中先完成(性能优化点之一)
# 2021 年 8 月 12 日
# 使用字体文件
- 字体文件较大情况下,一般都需要经过压缩,否则会延长首页加载完成时间,并会导致文字“闪”的效果
- 灵活使用
font-display:swap
,会平滑变换字体 - 使用
font-spider
抽出网站所有的文字,然后再生成一个新的字体文件,但只能是静态文字,接口返回的数据不能生成
# 滚动到指定 DOM 位置
scrollIntoView()
# 2021 年 8 月 13 日
# vue 项目中的对象初始化
借助 vue
的 $options
属性,$options
保存了 vue
实例的初始化选项,即保存了初始值
Object.assign(this.formData, this.$options.data().formData)
# 集中管理提示文案
抽离页面所有的提示文案,集中到一个 js 文件中,并且以接口为维度划分。
# 2021 年 8 月 16 日
# 白屏时间和首屏时间
白屏时间:在 head
标签结束前或 body
标签开始前插入 script
代码,获取当前的时间戳,再减去 performance.navigationStart
的时间
首屏时间:如果不计图片时间,那么首屏时间即 document.ready
时间减去 performance.navigationStart
的时间;若需要考虑图片加载时间,那么需要给首页的图片/视口内的图片加上 onload
事件,获取加载成功时的时间戳,取最大的值,再减去 performance.navigationStart
的时间,即为首屏时间
# document.ready 和 document.onload
document.ready
:是指 DOM
结构已经加载完成,可以操作 DOM,但不意味着所有关联文件都下载完毕(即
domContentLoadedEnd
)
document.onload
:页面所有元素都已经加载完毕,包括图片资源
# 2021 年 8 月 17 日
# sendBeacon
使用 navigator.sendBeacon()
方法会使用户代理在有机会时异步地向服务器发送数据,同时不会延迟页面的卸载或影响下一导航的载入性能。
注意:sendBeacon
是以 post
方式提交数据
// from MDN
window.addEventListener("unload", logData, false)
function logData() {
navigator.sendBeacon("/log", analyticsData)
}
# 移动端事件
- 移动端不支持
dbclick
事件,会触发方法 - 页面随着手指滚动而滚动时会触发
mousewheel
和scroll
事件 - orientationchange 事件:横屏竖屏触发事件
- mozOrientation 事件:检测设备方向改变
- deviceOrientation 事件:检测设备当前的空间朝向
- devicemotion 事件:检测设备是否在往下掉,或者被走着的人拿在手里
- gesturestart:当一个手指按在屏幕上而另一个手指又触摸屏幕时触发
- gesturechange:当触摸屏幕的任何一个手指的位置发生变化时触发
- gestureend:当任何一个手指从屏幕上离开时触发
# 移动端兼容问题
- 移动端监听 click 事件会有 300ms 的延迟,需要切换成 touchstart 事件
# 2021 年 8 月 18 日
# video(8.26 补)
video
对象属性(全):想要 !🚀 (opens new window);相关事件(全):也想要!🚀 (opens new window)
常见 video
格式的浏览器支持情况概览:
谷歌 | 火狐 | Opera | Edge | |
---|---|---|---|---|
MP4 | √ | √ | √ | √ |
mkv | √ | × | √ | √ |
ogg | √ | √ | √ | √ |
mov | √ | √ | √ | √ |
AVI | × | × | × | × |
webM | √ | √ | √ | √ |
Flv | × | × | × | × |
Wmv | × | × | × | × |
视频自动播放功能支持情况:仅支持静音自动播放
# 2021 年 8 月 19 日
# postman(8.23 补)
- 全局变量设置、环境变量设置
get
请求使用params
提交数据,post
请求使用body-x-www-form-urlencoded
或raw-json
Pre-request script
接口请求前置操作,可以设置变量也可以发起请求Tests
是执行完接口后的操作,可以设置变量,也可以做结果校验Runner
是自动执行集合接口的工具,通过设置Tests
来判断接口执行成功与否
# 2021 年 8 月 20 日
# 油猴(补)
- 浏览器自执行
javascript
脚本工具(Chrome
插件)
# CORS 跨域(补)
# withCredentials
- 跨域请求默认不携带
cookie、SSL
等 - 需要手动设置
withCredentials
为true
,指定某个请求应该发送凭据(cookie
),如果服务器接受凭据,也会相应返回Access-Control-Allow-Credentials: true
axios
中默认值为false
# options
请求
跨域接口请求下的非简单请求才会触发options 请求
options
请求就是预检请求,可用于检测服务器允许的 http
方法。当发起跨域请求时,由于安全原因,触发一定条件时浏览器会在正式请求之前自动先发起 OPTIONS
请求,即 CORS
预检请求,服务器若接受该跨域请求,浏览器才继续发起正式请求。
简单请求与非简单请求
- 除 get、post、head 外的请求都为非简单请求
- 手动设置
Accept/Accept-Language/Content-Language/Content-Type/DPR/Downlink/Save-Data/Viewport-Width/Width
字段之一的为简单请求 - content-type 不为 application/x-www-form-urlencoded、multipart/form-data、text/plain 之一的是非简单请求
# 2021 年 8 月 21 日
# call、apply、bind(8.31 补)
func.call(thisValue, arg1, arg2, ...)
、func.apply(thisValue, [arg1, arg2, ...])
call、apply
可以指定函数内部 this
的指向(即函数执行时所在的作用域)
bind
绑定 this
到某个对象,并返回一个新函数。bind
还可以接受更多的参数,将这些参数绑定原函数的参数
# 2021 年 8 月 22 日
# 高级函数
preventExtensions
:阻止扩展对象,但可以修改和删除已有的成员
isExtendsible
:判断是否可以扩展
seal
:密封对象,仅能修改已有的属性值
freeze
:冻结对象
# 2021 年 8 月 23 日
# 本地 host 代理
- 可以通过
host
代理任意http
域名到本地地址 - 需要修改
host
文件:192.168.195.219(本地) wolfberry.com(指定代理的域名)
- 如果是
vue
项目,需要关闭host
检查:disableHostCheck: true
- 成功配置后,即可使用
wolfberry.com
访问到本地地址192.168.195.219
- 若出现
Invalid Host header
,可以清一下浏览器缓存再重试(DNS
或浏览器缓存导致) - 暂时未发现可以代理
https
的域名
# whistle 代理
- 下载安装
whistle
- 运行
whistle
- 安装浏览器插件 SwitchyOmega 并创建指向
http://local.whistlejs.com
- 打开
http://local.whistlejs.com
,配置代理或抓包 - 注意:本地地址不能抓包,需加一层代理后才能抓到
# 2021 年 8 月 24 日
# postMessage(msg, origin)
跨文档消息传送(cross-document messaging
),简称 XDM。核心是 postMessage
方法
msg
: 最早作为“永远都是字符串”,部分浏览器可传其它数据类型,但存在兼容性问题
origin
:发送消息的文档所在域,通常在接收方用来校验信息来源,过滤掉不必要的数据
source
:发送消息的文档的 windows
对象的代理,可通过 event.source
访问
Tips:event.source.postMessage(msg, origin)
可以向来源窗口发送回执
# 2021 年 8 月 25 日
# 下载和预览文件
- 预览
PDF
,如果后端返回的是arraybuffer
格式数据,需要手动设置responseType
为arraybuffer
,否则打开的文件为空 - 下载
Excel
、Word
等文件同样需要设置responseType
,同时在设置download
属性时需要带上文件后缀 - 注:
responseType
为axios
的配置
相关代码:
// 文件下载
const blob = new Blob([res], { type: "application/x-xls" }) // 处理文档流,将arraybuffer转换成blob格式数据
const fileName = "文件名.xlsx" // 必须带上后缀
const alink = document.createElement("a")
alink.download = fileName
alink.style.display = "none"
alink.href = URL.createObjectURL(blob) // 创建临时资源链接
document.body.appendChild(alink)
alink.click()
URL.revokeObjectURL(alink.href) // 释放URL 对象
document.body.removeChild(alink)
// PDF文件预览
const url = URL.createObjectURL(new Blob([res], { type: `application/pdf` }))
URL.revokeObjectURL(url) // 释放URL 对象
window.open(url)
# 2021 年 8 月 26 日
# 拖拽 drag
默认情况下图片、链接、文本是可以拖动的,其他元素如要支持拖拽,需要设置属性 dragable="true"
,同样,禁止某一元素拖拽,设置 dragable
属性为 false
即可。
# 拖拽源
dragstart
:长按并移动鼠标时触发drag
:拖拽过程中会触发dragend
:释放鼠标时触发
# 拖拽目标
dragenter
:当某个元素拖拽到一个有效的放置目标上时触发dragover
:在放置目标上移动时触发dragleave
:拖拽出放置目标时触发drag
:在放置目标内释放鼠标时触发
拖拽源和目标可通过 event
对象中的 datatransfer
进行数据交互
# 2021 年 8 月 27 日
# 埋点数据
一个较好的解决方案是:利用 1*1 的空白 GIF 图
- 避免跨域(
img
天然支持跨域) - 利用空白
gif
相比PNG/JPG
体积小,1px 透明图,对网页内容的影响几乎没有影响 - 图片请求不占用
Ajax
请求限额 - 不会阻塞页面加载,影响用户的体验,只要
new Image
对象就好
问:能否直接 img.src
后接接口地址?
// 相关代码
var thisPage = location.href
var referringPage = document.referrer ? document.referrer : "none"
var beacon = new Image()
beacon.src =
"http://www.example.com/logger/beacon.gif?page=" +
encodeURI(thisPage) +
"&ref=" +
encodeURI(referringPage)
# Ajax
XMLHttpRequest
,IE < 7
时没有XML
对象,只有ActiveXObject
对象progress
事件,一般在open
方法之前调用,保证可以正常运行abort()
终止接口请求事件,通常需要用try-catch
语句封装,避免当readystate = 4
时再取消,会报错
# 2021 年 8 月 28 日
# jsconfig.json(9.6 补)
目录中存在 jsconfig.json
文件表示该目录是 JavaScript
项目的根目录。jsconfig.json
文件指定根文件和 JavaScript
语言服务提供的功能选项
增加的功能选项有:
1. 自动引入 Vue
组件和普通 Js
模块
2. 在 JS
中自动引入 node_modules
中的 JS
(如下引入并添加 lodash
)
3. crtl+左键
可以点击链接直接跳转到该文件
# 2021 年 8 月 29 日
# 可维护的代码(9.6 补)
可维护性
- 可维护:可理解性,直观性,可适应性,可扩展性,可调实性
- 代码约定:可读性,变量和函数命名,变量类型透明
- 松散耦合:解耦
HTML/JavaScript
,解耦css/JavaScript
,解耦应用逻辑/事件处理程序 - 编程实践:尊重对象的所有权,避免全局量,避免与 null 比较,使用常量
解耦应用逻辑/事件处理程序牢记以下三点:
- 勿将
event
对象传给其他方法,只传来自event
对象中所需的数据 - 任何可以在应用层面的动作都应该可以在不执行任何事件处理程序的情况下进行
- 任何事件处理程序都应该处理事件,然后将处理转交给应用逻辑
# 2021 年 8 月 30 日
# Comet 服务器推送
Comet
是一种服务器向页面推送数据的技术,能够让信息近乎实时地推送到页面上,非常适合处理体育比赛的分数和股票报价等。
在 Chrome、Firefox、Opera、Safari 中(IE 不行),通过监听 readyStateChange
事件及检测 readyState
是否为 3,就可以利用 XHR
对象实现 HTTP
流。随着不断从浏览器中接收数据,readyState
会周期性地变为 3,responseText
属性中就会保存接收到的所有数据。服务端响应数据的 MIME
类型必须是 text/event-stream
服务器发送事件:
- SSE(Server-Sent Events)
- HTTP 流
# 2021 年 8 月 31 日
# 惰性载入函数
背景:在每次使用 XHR
时都需要对浏览器支持情况进行检查,一般情况下都会直接通过 if-else
判断,这样就容易造成:每次调用 XHR
函数时都会执行一次 if-else
,但实际上我们只需要判断一次就知道当前浏览器对 XHR
能力的支持情况,也就是只需要执行一次 if-else
判断分支后就没有再次执行的必要。这就称为惰性载入的技巧
// 案例
function createXHR() {
if(typeof XMLHttpRequest !== 'undefined') {
createXHR = function() {
return new XMLHttpRequest
}
} else if(typeof ActiveXObject !== 'undefined') {
***
} else {
createXHR = function() {
throw new Error('No XHR object available.')
}
}
}
// 转换成匿名自执行函数
var createXHR = (function() {
if(typeof XMLHttpRequest !== 'undefined') {
return function() {
return new XMLHttpRequest()
}
} else if(typeof ActiveXObject !== 'undefined') {
return new ActiveXObject()
} else {
return function() {
throw new Error('No XHR object available.')
}
}
})()