# 笔记

# 2022 年 4 月 1 日

# 统计网站在线时长思考

常规方法:通过监听 beforeUnload 方法,判断用户退出或关闭页面的操作,但会有以下几点问题

  • 当直接关闭浏览器或关闭电脑时,无法监听 beforeUnload 事件
  • beforeUnload 事件兼容性问题,各个浏览器的表现行为不一致

其他方法:开启一个定时器,每隔一段时间(1/5/10min)记录结束时间 endTimelocalstorage,进入平台记录开始时间 startTime,当可以正常监听到 beforeUnload 事件时,可以通过 sendBeacon 方法提交到后端;若页面非正常关闭时,可以在下一次访问页面时再提交这个访问时间

存在优势:

  • 能够保证非正常关闭页面情况下数据不丢失
  • 数据误差较小(1/5/10min

存在劣势:

  • 非正常关闭页面情况下,需要下一次访问才能将上一次的访问时间发送给后端
  • 在同时打开多页面的情况下,会产生重复数据,难以去重

onvisibilitychange 兼容性研究

鼠标点击 tab 切换 alt+tab 切换程序 点击-缩小浏览器 win+D 缩小浏览器 × 关闭浏览器 alt+F4 关闭浏览器 刷新
Chrome
火狐 ×
Edge
Opera
360 ×

# 2022 年 4 月 2 日

# JS 保存快捷方式思考

pc 端保存当前页面到桌面,参考代码如下(来源于百度),利用桌面快捷方式为 .url 后缀的文件,模拟点击事件生成这么一个文件而达到“桌面快捷方式”的目的

function urlDownload(content, fileName) {
  const eleLink = document.createElement("a")
  eleLink.download = fileName
  eleLink.style.display = "none"
  const blob = new Blob([content])
  eleLink.href = URL.createObjectURL(blob)
  document.body.appendChild(eleLink)
  eleLink.click()
  document.body.removeChild(eleLink)
}
const title = document.title
const { protocol, href, hostname } = location
const content = `[{000214A0-0000-0000-C000-000000000046}]
  Prop3=19,11
  [InternetShortcut]
  IDList=
  URL=${href}
  IconFile=${protocol}//${hostname}/favicon.ico
  IconIndex=1`

移动端 JavaScript 应该没有提供这个能力,需要在桌面生成快捷方式(原子组件),应该是属于 APP 的能力,而 JavaScript(非 node) 只是基于浏览器运行的,没有那么高的权限来操作系统

谷歌了之后发现 PWA 也有这个能力,是基于 A2HS (opens new window) 实现的能力(PC 端也可以下载,但展示形式有点不太一样)

# 2022 年 4 月 3 日

# unknown 类型

TypeScript 3.0 引入了一个顶级的 unknown 类型。 对照于 anyunknown 是类型安全的。 任何值都可以赋给 unknown,但是当没有类型断言或基于控制流的类型细化时 unknown 不可以赋值给其它类型,除了它自己和 any 外。 同样地,在 unknown 没有被断言或细化到一个确切类型之前,是不允许在其上进行任何操作的。

const getDogName = () => {
 let x: unknown;
 return x;
};

const dogName = getDogName();
console.log((dogName as string).toLowerCase());

参考文档地址:https://www.tslang.cn/docs/release-notes/typescript-3.0.html (opens new window)

# 2022 年 4 月 4 日

# js 判断 360 系浏览器

遇到过的都说苦,这流氓 360 害人不浅

以下代码为网上参考代码,来源:https://juejin.cn/post/6844903504968957965 (opens new window)

function checkIeFor360() {
  return (
    (navigator.msPointerEnabled == undefined ? true : navigator.msPointerEnabled) &&
    (navigator.msDoNotTrack == 1 || window.doNotTrack == 1) &&
    ((Number(window.screenX) ? window.screenLeft - window.screenX != 8 : false) ||
      ((navigator.userAgent.indexOf("MSIE 7.0") != -1 ||
        navigator.userAgent.indexOf("MSIE 8.0") != -1) &&
        console.count == undefined))
  )
}

// 检测极速内核下的360浏览器
function checkChromeFor360() {
  var uas = navigator.userAgent.split(" "),
    result = false
  // 排除ua自带标志的双核浏览器, 余下chrome,chromium及360浏览器
  if (uas[uas.length - 1].indexOf("Safari") == -1) {
    return result
  }
  for (var key in navigator.plugins) {
    // np-mswmp.dll文件在chromium及chrome未查询到
    if (navigator.plugins[key].filename == "np-mswmp.dll") {
      return !result
    }
  }
  return result
}

if (navigator.userAgent.indexOf("Safari") != -1) {
  document.writeln(checkChromeFor360())
} else {
  document.writeln(checkIeFor360())
}

# 2022 年 4 月 5 日

# 自动化生成骨架屏思考

参考地址:https://github.com/Jocs/jocs.github.io/issues/22 (opens new window)

# 2022 年 4 月 6 日

# vuex 阅后感 -- 注入

vuex 也是一种 vue plugin,通过暴露 install 方法,再由 Vue 全局引入

3.x 版本的代码上看,还存在一些兼容代码,当 vue 版本在 2.0 以下时是直接挂载到 vue 原型上,而 2.x3.x 则是通过 mixin 的方式注入到每一个实例的初始化(beforeCreate)钩子中

if (version >= 2) {
  Vue.mixin({ beforeCreate: vuexInit })
} else {
  const _init = Vue.prototype._init
  Vue.prototype._init = function(options = {}) {
    options.init = options.init ? [vuexInit].concat(options.init) : vuexInit
    _init.call(this, options)
  }
}

但从最新的代码(4.x)来看,好像已经摒弃了兼容代码,直接使用全局注入的方式,将 store 注入到每一个实例

install (app, injectKey) {
  app.provide(injectKey || storeKey, this)
  app.config.globalProperties.$store = this
  const useDevtools = this._devtools !== undefined
    ? this._devtools
    : __DEV__ || __VUE_PROD_DEVTOOLS__
  if (useDevtools) {
    addDevtools(app, this)
  }
}