# 笔记

# 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)

  1. 电子欺骗:浏览器通过在自己的用户代理字符串加入一些错误或误导性的信息,来达到欺骗服务器的目的
  2. 通过加入一些目的性的代理字符串,使一些站点的嗅探程序(检测程序)能够命中并识别,以便站点能够“信任”它与其他流行的浏览器是兼容的(理解为网站 W 有嗅探程序 X,X 可以检测并命中浏览器 A 但不能命中 B 浏览器,B 浏览器为了也能被 X 命中,就往用户代理中加入 A 的某些特征代理字符串,以便 X 可以识别 B。让用户知道 B 浏览器也能跑 W 站点甚至更多,达到留住用户的目的)

# Node 类型

  1. 判断是否有子节点:hasChildNodes()
  2. previousSibling、nextSibling 分别为前一个兄弟节点,后一个兄弟节点
  3. 插入到指定位置:insertBefore(newNode, someNode)
  4. 替换节点:replaceChild(newNode, someNode)
  5. 删除节点:removeChild()
  6. 复制节点:cloneNode(Boolean),true 时表示深拷贝
  7. document.createDocumentFragment() 创建文档碎片(仓库),不会占用额外的资源。在操作真实 DOM 前的所有操作都可以在这个“仓库中先完成(性能优化点之一)

# 2021 年 8 月 12 日

# 使用字体文件

  1. 字体文件较大情况下,一般都需要经过压缩,否则会延长首页加载完成时间,并会导致文字“闪”的效果
  2. 灵活使用font-display:swap,会平滑变换字体
  3. 使用 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)
}

# 移动端事件

  1. 移动端不支持 dbclick 事件,会触发方法
  2. 页面随着手指滚动而滚动时会触发 mousewheelscroll 事件
  3. orientationchange 事件:横屏竖屏触发事件
  4. mozOrientation 事件:检测设备方向改变
  5. deviceOrientation 事件:检测设备当前的空间朝向
  6. devicemotion 事件:检测设备是否在往下掉,或者被走着的人拿在手里
  7. gesturestart:当一个手指按在屏幕上而另一个手指又触摸屏幕时触发
  8. gesturechange:当触摸屏幕的任何一个手指的位置发生变化时触发
  9. gestureend:当任何一个手指从屏幕上离开时触发

# 移动端兼容问题

  1. 移动端监听 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 补)

  1. 全局变量设置、环境变量设置
  2. get 请求使用 params 提交数据,post 请求使用 body-x-www-form-urlencodedraw-json
  3. Pre-request script 接口请求前置操作,可以设置变量也可以发起请求
  4. Tests 是执行完接口后的操作,可以设置变量,也可以做结果校验
  5. Runner 是自动执行集合接口的工具,通过设置 Tests 来判断接口执行成功与否

# 2021 年 8 月 20 日

# 油猴(补)

  1. 浏览器自执行 javascript 脚本工具(Chrome 插件)

# CORS 跨域(补)

# withCredentials

  1. 跨域请求默认不携带 cookie、SSL
  2. 需要手动设置 withCredentialstrue,指定某个请求应该发送凭据(cookie),如果服务器接受凭据,也会相应返回 Access-Control-Allow-Credentials: true
  3. 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 代理

  1. 可以通过 host 代理任意 http 域名到本地地址
  2. 需要修改 host 文件:192.168.195.219(本地) wolfberry.com(指定代理的域名)
  3. 如果是 vue 项目,需要关闭 host 检查:disableHostCheck: true
  4. 成功配置后,即可使用 wolfberry.com 访问到本地地址 192.168.195.219
  5. 若出现 Invalid Host header,可以清一下浏览器缓存再重试(DNS 或浏览器缓存导致)
  6. 暂时未发现可以代理 https 的域名

# whistle 代理

  1. 下载安装 whistle
  2. 运行 whistle
  3. 安装浏览器插件 SwitchyOmega 并创建指向 http://local.whistlejs.com
  4. 打开 http://local.whistlejs.com,配置代理或抓包
  5. 注意:本地地址不能抓包,需加一层代理后才能抓到

# 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 日

# 下载和预览文件

  1. 预览 PDF,如果后端返回的是 arraybuffer 格式数据,需要手动设置 responseTypearraybuffer,否则打开的文件为空
  2. 下载 ExcelWord 等文件同样需要设置 responseType,同时在设置 download 属性时需要带上文件后缀
  3. 注:responseTypeaxios 的配置

相关代码:

// 文件下载
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 即可。

# 拖拽源

  1. dragstart:长按并移动鼠标时触发
  2. drag:拖拽过程中会触发
  3. dragend:释放鼠标时触发

# 拖拽目标

  1. dragenter:当某个元素拖拽到一个有效的放置目标上时触发
  2. dragover:在放置目标上移动时触发
  3. dragleave:拖拽出放置目标时触发
  4. drag:在放置目标内释放鼠标时触发

拖拽源和目标可通过 event 对象中的 datatransfer 进行数据交互

# 2021 年 8 月 27 日

# 埋点数据

一个较好的解决方案是:利用 1*1 的空白 GIF 图

  1. 避免跨域(img 天然支持跨域)
  2. 利用空白 gif 相比 PNG/JPG 体积小,1px 透明图,对网页内容的影响几乎没有影响
  3. 图片请求不占用 Ajax 请求限额
  4. 不会阻塞页面加载,影响用户的体验,只要 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

  1. XMLHttpRequestIE < 7 时没有 XML 对象,只有 ActiveXObject 对象
  2. progress 事件,一般在 open 方法之前调用,保证可以正常运行
  3. 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 补)

可维护性

  1. 可维护:可理解性,直观性,可适应性,可扩展性,可调实性
  2. 代码约定:可读性,变量和函数命名,变量类型透明
  3. 松散耦合:解耦 HTML/JavaScript,解耦 css/JavaScript,解耦应用逻辑/事件处理程序
  4. 编程实践:尊重对象的所有权,避免全局量,避免与 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

服务器发送事件:

  1. SSE(Server-Sent Events)
  2. 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.')
        }
    }
})()
Last Updated: 10/20/2021, 4:38:03 PM