Skip to content

极简js代码片段 ​

小技巧 ​

  1. if(value) 直接 value 表示判断是否有内容,默认为有;

  2. 元素.checked=true;复选框被选中

  3. 在函数里面递归调用必须return ,否则不走后面

  4. trim();常用于 value;干掉左右空格;

判断 value 输入为空时,不让提交,如果 value 输入空格,也能提交,此时,需要

input.value.trim();使用 trim 方法可以清除 value 里面的空格并弹窗;,ie8 不支持;,

  1. value 写完后可以在按钮后面加一行代码:input.value = '';清空内容方便用户下次输入;

  2. 数组去重可以创建一个空的数组,indexOf查询没有的往里面放;

  3. 调用一个方法,如果这个方法没有前缀,则this指向window;有前缀指向调用的,所以谁调用的函数,这个 this 就指向谁

  4. document.onkeydown;document 页面直接执行按键输入;

  5. 点的形式都可以使用中括号的形式

    js
    let obj = { name: 'hny' }
    console.log(obj.name)
    // or
    console.log(obj['name'])
    
    // 一般中括号都是用来放变量的, 如下
    var s = 'name'
    console.log(obj[s])
    let obj = { name: 'hny' }
    console.log(obj.name)
    // or
    console.log(obj['name'])
    
    // 一般中括号都是用来放变量的, 如下
    var s = 'name'
    console.log(obj[s])
  6. 当输出对象遇到[object object]时,使用 JSON.stringify 转字符串输出;

  7. 当在不使用模板字符换行时,可以使用折行转义字符 \

    js
    var htmlSTring = "<div>\
        This is a string.\
    </div>";
    var htmlSTring = "<div>\
        This is a string.\
    </div>";
  8. 一个页面不能有两个 window.onscroll,可以使用绑定事件来做两个

    js
    window.addEventListener('scroll', () => {})
    // 如果使用两个window.onscroll, 后一个则会覆盖前一个
    window.addEventListener('scroll', () => {})
    // 如果使用两个window.onscroll, 后一个则会覆盖前一个
  9. 给代码添加 debugger 可以测试 bug;

    debugger可以查看我写的浏览器技巧 断点内容;

  10. Object.prototype.hasOwnProperty.call(obj,i)相当于以下

    js
    obj.hasOwnProperty(i)
    obj.hasOwnProperty(i)
  11. 数组删除假值

    js
    var arr = [1, '', null, undefined, true, false, '2']
    arr.filter(Boolean) // => [1, true, '2']
    var arr = [1, '', null, undefined, true, false, '2']
    arr.filter(Boolean) // => [1, true, '2']
  12. 利用 es6 默认赋值语法,判断参数是否为空值

    js
    const isRequired = () => throw new Error('param is required')
    const print = (num = isRequired()) => {
      console.log('print: ', num)
    }
    const isRequired = () => throw new Error('param is required')
    const print = (num = isRequired()) => {
      console.log('print: ', num)
    }

复制文本到剪切板 ​

js
const copyToClipboard = (text) => navigator.clipboard.writeText(text)

copyToClipboard('Hello, World!')
const copyToClipboard = (text) => navigator.clipboard.writeText(text)

copyToClipboard('Hello, World!')

获取某个日期位于当年的第几天 ​

jsx
const getDayOfYear = (date) =>
  Math.floor((date - new Date(date.getFullYear(), 0, 0)) / 1000 / 60 / 60 / 24)

getDayOfYear(new Date(2017, 0, 1))
const getDayOfYear = (date) =>
  Math.floor((date - new Date(date.getFullYear(), 0, 0)) / 1000 / 60 / 60 / 24)

getDayOfYear(new Date(2017, 0, 1))

将 rgb 颜色灰度化 (基于光感加权平均) ​

js
const rgbToGray = (r, g, b) => 0.2126 * r + 0.7152 * g + 0.0722 * b

rgbToGray(255, 255, 255)
const rgbToGray = (r, g, b) => 0.2126 * r + 0.7152 * g + 0.0722 * b

rgbToGray(255, 255, 255)

解析 url 地址 ​

js
const parseUrlQuery = (url) => {
  q = {}

  url.replace(/([^?&=]+)=([^&]+)/g, (_, k, v) => (q[k] = v))

  return q
}

console.log(parseUrlQuery('https://www.baidu.com/?a=1&b=2')) // {a:1,b:2}
const parseUrlQuery = (url) => {
  q = {}

  url.replace(/([^?&=]+)=([^&]+)/g, (_, k, v) => (q[k] = v))

  return q
}

console.log(parseUrlQuery('https://www.baidu.com/?a=1&b=2')) // {a:1,b:2}

筛选对象属性 ​

js
const pick = (obj, ...props) =>
  Object.fromEntries(Object.entries(obj).filter(([key]) => props.includes(key)))

const obj = { a: 1, b: 2, c: 3 }

pick(obj, 'a', 'c') // {a:1,c:3}
const pick = (obj, ...props) =>
  Object.fromEntries(Object.entries(obj).filter(([key]) => props.includes(key)))

const obj = { a: 1, b: 2, c: 3 }

pick(obj, 'a', 'c') // {a:1,c:3}

随机颜色 ​

jsx
const randomColor = () =>
  '#' +
  Math.floor(Math.random() * 0xffffff)
    .toString(16)
    .padEnd(6, '0')

console.log(randomColor())
const randomColor = () =>
  '#' +
  Math.floor(Math.random() * 0xffffff)
    .toString(16)
    .padEnd(6, '0')

console.log(randomColor())

随机字符串 ​

js
const randomString = (n) =>
  Array.from({ length: n }, () => String.fromCharCode(Math.floor(Math.random() * 26) + 97)).join('')

console.log(randomString(10)) // iajxwxjq
const randomString = (n) =>
  Array.from({ length: n }, () => String.fromCharCode(Math.floor(Math.random() * 26) + 97)).join('')

console.log(randomString(10)) // iajxwxjq

去掉字符串里面的标签 ​

js
const removeTags = (fragment) =>
  new DOMParser().parseFromString(fragment, 'text/html').body.textContent || ''

removeTags('<p>Hello, <b>world</b>!</p>') // "Hello, world!"
const removeTags = (fragment) =>
  new DOMParser().parseFromString(fragment, 'text/html').body.textContent || ''

removeTags('<p>Hello, <b>world</b>!</p>') // "Hello, world!"

判断语句省略写法 ​

js
//判断;真就真
if(count === otherche.length){   //判断是否等于长度
    allche.checked = true;
}else{
    allche.checked = false;
}    //因为就给allche.checked赋一个值,true或false;
//省略写法
allche.checked = (count === otherche.length);   //将后面两个值赋给前面一个;



//判断真假 为真就为假
if(check[0].checked){    如果为真,就为假
    check[i].checked = false;
}else{   如果为假,就为真
    check[i].checked = true;
}
//省略写法:
check[i].checked = !check[0].checked;    //取返
// 如果第二个为真,就变假给第一个,如果第二个为假,就变真给第一个;
// 只要是true或false的,都可以利用感叹号取非;


//按钮事件 真就真
if(allche.checked){    //如果被选中就全部选中
    che[i].checked = true;
}else{
    che[i].checked = false;
}
//省略写法
che[i].checked = allche.checked;   //全部等于这个;

if(fn){
    fn()
}
//省略写法
fn && fn();    前面为真,才看后面的;
//判断;真就真
if(count === otherche.length){   //判断是否等于长度
    allche.checked = true;
}else{
    allche.checked = false;
}    //因为就给allche.checked赋一个值,true或false;
//省略写法
allche.checked = (count === otherche.length);   //将后面两个值赋给前面一个;



//判断真假 为真就为假
if(check[0].checked){    如果为真,就为假
    check[i].checked = false;
}else{   如果为假,就为真
    check[i].checked = true;
}
//省略写法:
check[i].checked = !check[0].checked;    //取返
// 如果第二个为真,就变假给第一个,如果第二个为假,就变真给第一个;
// 只要是true或false的,都可以利用感叹号取非;


//按钮事件 真就真
if(allche.checked){    //如果被选中就全部选中
    che[i].checked = true;
}else{
    che[i].checked = false;
}
//省略写法
che[i].checked = allche.checked;   //全部等于这个;

if(fn){
    fn()
}
//省略写法
fn && fn();    前面为真,才看后面的;

js 基础技巧 ​

计数器

js 最基础的使用技巧

实例:多个复选框全选可以创建一个计数器,选中一个计数器+1,判断计数器是否和复选框的个数一样,如果一样,则让全选按钮被选中;

保存 this 指向

函数里面再创建一个函数时,这时的 this 指向就变了,可以创建一个变量,保存 this 指向,里面就可以随便使用该变量,也不用担心 this 的指向问题, 也可以使用箭头函数避免这个问题

js
// vue示例
methods: {
    // 一种写法
    msg () {
        var that = this
        function fn(){
            console.log(that) // 该that指向vue实例, this指向调用他的this
        }
    },
    // 另一种写法
    msg () {
        cont fn = () => {
            console.log(this) // 该this指向vue实例
        }
    }
}
// vue示例
methods: {
    // 一种写法
    msg () {
        var that = this
        function fn(){
            console.log(that) // 该that指向vue实例, this指向调用他的this
        }
    },
    // 另一种写法
    msg () {
        cont fn = () => {
            console.log(this) // 该this指向vue实例
        }
    }
}

取名字技巧 ​

设置的都用:set开头

获取的都用:get开头

卸载都用: un

函数:handle

创建块:demo(演示),wrap(包装),box(盒子),panel(面版)

定时器使用函数需要传参时 ​

js
// 禁止写法
setInterval(timer(1), 1000) // 因为这种写法的函数直接执行了

// 正确写法
setInterval(function () {
  timer(1)
}, 1000)

// 错误写法
div.onclick = change()

// 正确写法
div.onclick = function () {
  change()
}
// 禁止写法
setInterval(timer(1), 1000) // 因为这种写法的函数直接执行了

// 正确写法
setInterval(function () {
  timer(1)
}, 1000)

// 错误写法
div.onclick = change()

// 正确写法
div.onclick = function () {
  change()
}

随机 id ​

js
Math.random().toString(36).substr(3, 6) //得到6位随机id
Math.random().toString(36).substr(3, 6) //得到6位随机id

查看随机 6 位数;

js
Array.from({ length: 20 }, (i) => Math.ceil(Math.random() * 6))
Array.from({ length: 20 }, (i) => Math.ceil(Math.random() * 6))

随机 16 进制颜色 ​

js
const RandomColor = () =>
  '#' +
  Math.floor(Math.random() * 0xffffff)
    .toString(16)
    .padEnd(6, '0') // 由于会出现5位数, 因此加上padEnd保险
const RandomColor = () =>
  '#' +
  Math.floor(Math.random() * 0xffffff)
    .toString(16)
    .padEnd(6, '0') // 由于会出现5位数, 因此加上padEnd保险

合并多个对象 ​

js
const o = {
  name: 'hny',
}
const e = {
  eat: 'banana',
}
const obj = { ...o, ...e } // => {name: 'hny', eat: 'banana'}
const obj2 = Object.assign(o, e) // => {name: 'hny', eat: 'banana'}
const o = {
  name: 'hny',
}
const e = {
  eat: 'banana',
}
const obj = { ...o, ...e } // => {name: 'hny', eat: 'banana'}
const obj2 = Object.assign(o, e) // => {name: 'hny', eat: 'banana'}

模板标签替换 ​

js
let text = '大家好,我的{{name}},今年{{age}}岁'
let obj = {name:'zs',age:18}
let result = text.replace(/{{(.*?)}}/g,e=>{
    return obj[e.replace(/{|}/g,'')
})  // 大花括号也可以没有转义符;
let text = '大家好,我的{{name}},今年{{age}}岁'
let obj = {name:'zs',age:18}
let result = text.replace(/{{(.*?)}}/g,e=>{
    return obj[e.replace(/{|}/g,'')
})  // 大花括号也可以没有转义符;
js
const template = 'My name is ${name}, age ${age}, I am a ${job.name}'
const employee = {
  name: 'fatfish',
  age: 100,
  job: {
    name: 'front end development',
  },
}

// ag: 1
String.prototype.render = function (obj) {
  const template = this
  const variableRegex = /\$\{([^${}]+)\}/g
  const getVariableValue = (variable) => {
    // [ 'name' ]、[ 'age' ]、[ 'job', 'name' ]
    variable = variable.split('.')
    let variableValue = obj
    while (variable.length) {
      variableValue = variableValue[variable.shift()]
    }
    return variableValue
  }
  const renderStr = template.replace(variableRegex, ($0, variable) => {
    return getVariableValue(variable)
  })
  return renderStr
}

// ag: 2
String.prototype.render = function (obj) {
  const template = this
  // var { name, age, job } = obj
  eval(`var {${Object.keys(obj).join(',')}} = obj`)
  // `My name is ${name}, age ${age}, I am a ${job.name}`
  const renderStr = eval('`' + template + '`')
  return renderStr
}

// ag: 3
String.prototype.render = function (obj) {
  with (obj) {
    return eval('`' + this + '`')
  }
}
const template = 'My name is ${name}, age ${age}, I am a ${job.name}'
const employee = {
  name: 'fatfish',
  age: 100,
  job: {
    name: 'front end development',
  },
}

// ag: 1
String.prototype.render = function (obj) {
  const template = this
  const variableRegex = /\$\{([^${}]+)\}/g
  const getVariableValue = (variable) => {
    // [ 'name' ]、[ 'age' ]、[ 'job', 'name' ]
    variable = variable.split('.')
    let variableValue = obj
    while (variable.length) {
      variableValue = variableValue[variable.shift()]
    }
    return variableValue
  }
  const renderStr = template.replace(variableRegex, ($0, variable) => {
    return getVariableValue(variable)
  })
  return renderStr
}

// ag: 2
String.prototype.render = function (obj) {
  const template = this
  // var { name, age, job } = obj
  eval(`var {${Object.keys(obj).join(',')}} = obj`)
  // `My name is ${name}, age ${age}, I am a ${job.name}`
  const renderStr = eval('`' + template + '`')
  return renderStr
}

// ag: 3
String.prototype.render = function (obj) {
  with (obj) {
    return eval('`' + this + '`')
  }
}

参考:面试官:你能实现一个 JavaScript 模板引擎吗?

交换数组指定位置 ​

[1,2,3,4,5] ===> [5,2,3,4,1]

js
function arrIndexExchange(array, x, y) {
  return array.splice(x - 1, 1, ...array.splice(y - 1, 1, array[x - 1]))
}
function arrIndexExchange(array, x, y) {
  return array.splice(x - 1, 1, ...array.splice(y - 1, 1, array[x - 1]))
}

生成 uuid ​

uuid 的格式为:8-4-4-4-12

js
function S4() {
  return (((1 + Math.random()) * 0x10000) | 0).toString(16).substr(0, 4)
}
function uuid() {
  return `${S4()}${S4()}-${S4()}-${S4()}-${S4()}-${S4()}${S4()}${S4()}`
}
function S4() {
  return (((1 + Math.random()) * 0x10000) | 0).toString(16).substr(0, 4)
}
function uuid() {
  return `${S4()}${S4()}-${S4()}-${S4()}-${S4()}-${S4()}${S4()}${S4()}`
}

鼠标禁止右键 ​

html
<body oncontentmenu="return false">
  <div></div>
</body>
<body oncontentmenu="return false">
  <div></div>
</body>

复制功能 ​

js
const copyFun = (cont) => {
  const textArea = document.createElement('textarea')
  textArea.value = cont
  document.body.appendChild(textArea)
  textArea.select()
  document.execCommand('copy') //开启复制;
  document.body.removeChild(textArea)
}
const copyFun = (cont) => {
  const textArea = document.createElement('textarea')
  textArea.value = cont
  document.body.appendChild(textArea)
  textArea.select()
  document.execCommand('copy') //开启复制;
  document.body.removeChild(textArea)
}

将 Unicode 码转回英文 ​

String.fromCharCode() //括号填写数字,

例子:取随机 26 个小写英文字母,

在 ASCII 码中,26 个小写英文字母在 97-122 之间

js
String.fromCharCode(97 + Math.ceil(Math.random() * 25)) //返回一个小写字母
String.fromCharCode(97 + Math.ceil(Math.random() * 25)) //返回一个小写字母

将 url 转换成对象形式取值 ​

  • 使用 while 循环+正则
js
function formatSearch(search, o = {}) {
  let reg = /(\w+)=(\w+)/gi
  while (reg.exec(search)) {
    o[RegExp.$1] = RegExp.$2
  }
  return o
}
// 将match传入即可;
function formatSearch(search, o = {}) {
  let reg = /(\w+)=(\w+)/gi
  while (reg.exec(search)) {
    o[RegExp.$1] = RegExp.$2
  }
  return o
}
// 将match传入即可;
  • 使用 api
js
let str = '?name=hny&age=18&sex=1'
Object.fromEntries(new URLSearchParams(str)) // {name:'hny',age:18,sex:1}
let str = '?name=hny&age=18&sex=1'
Object.fromEntries(new URLSearchParams(str)) // {name:'hny',age:18,sex:1}
  • 使用正则
js
function formatUrl(search, o = {}) {
  search.replace(/([^?&=]+)=([^&]+)/g, (_, k, v) => (o[k] = v))
  return o
}
// 传入match即可
function formatUrl(search, o = {}) {
  search.replace(/([^?&=]+)=([^&]+)/g, (_, k, v) => (o[k] = v))
  return o
}
// 传入match即可

简单封装 qs ​

js
const qs = {
  parse: (str) => Object.fromEntries(new URLSearchParams(str)),
  stringify: (obj) =>
    Object.keys(obj)
      .reduce((pre, cur) => ((pre += `${cur}=${obj[cur]}&`), pre), '?')
      .slice(0, -1),
}
const qs = {
  parse: (str) => Object.fromEntries(new URLSearchParams(str)),
  stringify: (obj) =>
    Object.keys(obj)
      .reduce((pre, cur) => ((pre += `${cur}=${obj[cur]}&`), pre), '?')
      .slice(0, -1),
}

实现图片的异步加载 ​

img 文档: https://www.w3school.com.cn/jsref/dom_obj_image.asp

js
// data-*  是html5的新特性
;<img data-src="" src="" alt="" /> // 通过img.dataset.src可以获取到data-src的数据;

// 可以通过循环获取img对象来修改对象的src;
function loadImg(obj, url) {
  var img = new Image()
  img.src = url
  // 当图片加载完成时的事件
  img.onload = function () {
    obj.src = img.src // 当图片加载完成时,渲染页面的src;
  }
  // 当图片加载失败时的事件
  img.onerror = function () {}
}
// data-*  是html5的新特性
;<img data-src="" src="" alt="" /> // 通过img.dataset.src可以获取到data-src的数据;

// 可以通过循环获取img对象来修改对象的src;
function loadImg(obj, url) {
  var img = new Image()
  img.src = url
  // 当图片加载完成时的事件
  img.onload = function () {
    obj.src = img.src // 当图片加载完成时,渲染页面的src;
  }
  // 当图片加载失败时的事件
  img.onerror = function () {}
}

清除缓存技巧 ​

数据不更新,本地有缓存,可以在网址后面加个时间戳

js
var t = Date.now()
var url = `?t=${t}`
var t = Date.now()
var url = `?t=${t}`

临时使用$获取元素 ​

当一个函数里面需要获取多个节点时,可以使用下面方法

js
;(function ($) {
  $('div').scrollTop = $('.center').clientHeight
})(document.querySelector.bind(document))
;(function ($) {
  $('div').scrollTop = $('.center').clientHeight
})(document.querySelector.bind(document))

检测移动端 ​

js
isMobile () {
    return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)
}
isMobile () {
    return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)
}

解决谷歌翻译代码块的问题 ​

将以下代码添加到一个新的书签,网址写以下代码

js
javascript: (function () {
  // 不需要翻译的单词
  var wordArr = ['options', 'node', 'postcss', 'gulp', 'grunt']
  var reg = eval(`/${wordArr.join('|')}/ig`)
  // 不需要翻译的标签名
  var labelArr = ['pre', 'code']
  var reg2 = eval(`/<${labelArr.join('>|<')}>/ig`)
  document.documentElement.innerHTML = document.documentElement.innerHTML.replace(
    reg,
    (val) => `<span class='notranslate'>${val}</span>`,
  )
  document.documentElement.innerHTML = document.documentElement.innerHTML.replace(
    reg2,
    (val) => `<${val.slice(1, -1)} class='notranslate'>`,
  )
})()
javascript: (function () {
  // 不需要翻译的单词
  var wordArr = ['options', 'node', 'postcss', 'gulp', 'grunt']
  var reg = eval(`/${wordArr.join('|')}/ig`)
  // 不需要翻译的标签名
  var labelArr = ['pre', 'code']
  var reg2 = eval(`/<${labelArr.join('>|<')}>/ig`)
  document.documentElement.innerHTML = document.documentElement.innerHTML.replace(
    reg,
    (val) => `<span class='notranslate'>${val}</span>`,
  )
  document.documentElement.innerHTML = document.documentElement.innerHTML.replace(
    reg2,
    (val) => `<${val.slice(1, -1)} class='notranslate'>`,
  )
})()

总数格式化 ​

例如:1000,转换为 1k

js
function formatStatistics(num) {
  if (!num) {
    return 0
  } else if (num > 999) {
    // 取小数点前后
    let [dotBefore, dotAfter] = (num / 1000).toFixed(2).split('.')
    // 解决1300出现1.30的情况
    let dotAfterNum = dotAfter % 10 > 0 ? dotAfter : dotAfter[0]
    return `${dotBefore}${dotAfter > 0 ? '.' + dotAfterNum : ''}k`
  } else {
    return num
  }
}
function formatStatistics(num) {
  if (!num) {
    return 0
  } else if (num > 999) {
    // 取小数点前后
    let [dotBefore, dotAfter] = (num / 1000).toFixed(2).split('.')
    // 解决1300出现1.30的情况
    let dotAfterNum = dotAfter % 10 > 0 ? dotAfter : dotAfter[0]
    return `${dotBefore}${dotAfter > 0 ? '.' + dotAfterNum : ''}k`
  } else {
    return num
  }
}

对接 url 传输加密 ​

encodeURIComponent对链接加密,将 url 上面的符号添加%转码

decodeURIComponent对加密的 url 进行解密

escape:加密汉字

unescape:解密

解决 toFixed 四舍五入的问题 ​

js
export function toFixed(value, precision) {
  if (typeof value === 'undefined') return ''

  return new Intl.NumberFormat(undefined, {
    useGrouping: false,
    minimumFractionDigits: precision,
    maximumFractionDigits: precision,
  }).format(value)
}
export function toFixed(value, precision) {
  if (typeof value === 'undefined') return ''

  return new Intl.NumberFormat(undefined, {
    useGrouping: false,
    minimumFractionDigits: precision,
    maximumFractionDigits: precision,
  }).format(value)
}

arguments.callee ​

属性包含当前正在执行的函数

主要用途是由于函数内部需要调用自己,可以直接使用 arguments.callee 调用,如果直接写当前函数名,该函数就会紧紧耦合在一起,由于函数名只是一个包含指针的变量,因此将另一个函数名也指向同一个函数,则不可用了,因为调用自己的名字不一样了

调用arguments.callee.toString()返回这个匿名函数;

arguments.callee可以直接调用当前函数;

arguments.callee.caller 这个属性中保存着调用当前函数的函数的引用(可以查看红宝书的详细介绍 115 页)

常用对象的方法 ​

判断对象的数据类型 ​

js
const isType = (type) => (target) => `[object ${type}]` === Object.prototype.toString.call(target)
const isArray = isType('Array')
console.log(isArray([])) // true

//分解
function isType(type) {
  return function (target) {
    ;`[object ${type}]` === Object.prototype.toString.call(target)
  }
}
const isType = (type) => (target) => `[object ${type}]` === Object.prototype.toString.call(target)
const isArray = isType('Array')
console.log(isArray([])) // true

//分解
function isType(type) {
  return function (target) {
    ;`[object ${type}]` === Object.prototype.toString.call(target)
  }
}

精准判断类型:(类型需要大写)

js
'[object 类型]' === Object.prototype.toString.call(形参)
'[object 类型]' === Object.prototype.toString.call(形参)

动态属性名 ​

声明一个变量;使用中括号代替,也可以是对象变量属性;

js
// 动态属性名
let dys = 'email'
let user = { name: 'join', [dys]: 'john@qq.com' }

let flag = true
let user = { name: 'join', [flag ? 'c' : 'd']: 2 }
// 动态属性名
let dys = 'email'
let user = { name: 'join', [dys]: 'john@qq.com' }

let flag = true
let user = { name: 'join', [flag ? 'c' : 'd']: 2 }

例子 2

js
let obj = [
  { name: 'lis', flag: 'no' },
  { name: 'zs', flag: 'yes' },
]
Array.from(obj, ({ name, flag }) => {
  return { [name]: visi }
  // 名字需要是引号的,所以需要中括号;
})
// [{lis:no},{zs:yes}]
let obj = [
  { name: 'lis', flag: 'no' },
  { name: 'zs', flag: 'yes' },
]
Array.from(obj, ({ name, flag }) => {
  return { [name]: visi }
  // 名字需要是引号的,所以需要中括号;
})
// [{lis:no},{zs:yes}]

有条件的象征对象 ​

在对象里面使用...去使用布尔值;

js
function obj(flag) {
  return {
    name: 'limin',
    ...(flag && { age: 18 }),
  }
}
obj(true) // {name:'',age:''}
obj(false) // {name: ''}   // 如果不传入也是一个值;
// 解析:如果flag成立,则...{}将对象解构, 如果不成功则不解构

// 延伸 动态添加数组值;
let arr = [{ name: 'hh' }, ...[...(true ? [{ name: 'ls' }] : '')], { name: 'op' }]
function obj(flag) {
  return {
    name: 'limin',
    ...(flag && { age: 18 }),
  }
}
obj(true) // {name:'',age:''}
obj(false) // {name: ''}   // 如果不传入也是一个值;
// 解析:如果flag成立,则...{}将对象解构, 如果不成功则不解构

// 延伸 动态添加数组值;
let arr = [{ name: 'hh' }, ...[...(true ? [{ name: 'ls' }] : '')], { name: 'op' }]

解构原始对象 ​

提取两部分,分为两个对象;

js
let obj = { name: 'lishi', age: 18, city: '北京' }
let user = {},
  userOther = {}
;({ name: user.name, ...userOther } = obj)
let obj = { name: 'lishi', age: 18, city: '北京' }
let user = {},
  userOther = {}
;({ name: user.name, ...userOther } = obj)

设置 REM ​

js
export const setRem = () => {
  const minWidth = 320
  const maxWidth = 640
  let W = document.documentElement.clientWidth
  W = W > maxWidth ? maxWidth : W < minWidth ? minWidth : W
  document.documentElement.style.fontSize = W / 3.75 + 'px'

  window.onresize = function () {
    let W = document.documentElement.clientWidth
    W = W > maxWidth ? maxWidth : W < minWidth ? minWidth : W
    document.documentElement.style.fontSize = W / 3.75 + 'px'
  }
}
export const setRem = () => {
  const minWidth = 320
  const maxWidth = 640
  let W = document.documentElement.clientWidth
  W = W > maxWidth ? maxWidth : W < minWidth ? minWidth : W
  document.documentElement.style.fontSize = W / 3.75 + 'px'

  window.onresize = function () {
    let W = document.documentElement.clientWidth
    W = W > maxWidth ? maxWidth : W < minWidth ? minWidth : W
    document.documentElement.style.fontSize = W / 3.75 + 'px'
  }
}

判断 touch 事件滑动的方向 ​

根据移动的值正负来判断

js
//滑动处理
var startX, startY, moveEndX, moveEndY, X, Y
mybody.addEventListener(
  'touchstart',
  function (e) {
    e.preventDefault()
    startX = e.touches[0].pageX
    startY = e.touches[0].pageY
  },
  false,
)
mybody.addEventListener('touchmove', function (e) {
  e.preventDefault()
  moveEndX = e.changedTouches[0].pageX
  moveEndY = e.changedTouches[0].pageY
  X = moveEndX - startX
  Y = moveEndY - startY
  if (Math.abs(X) > Math.abs(Y) && X > 0) {
    alert('向右')
  } else if (Math.abs(X) > Math.abs(Y) && X < 0) {
    alert('向左')
  } else if (Math.abs(Y) > Math.abs(X) && Y > 0) {
    alert('向下')
  } else if (Math.abs(Y) > Math.abs(X) && Y < 0) {
    alert('向上')
  } else {
    alert('没滑动')
  }
})
//滑动处理
var startX, startY, moveEndX, moveEndY, X, Y
mybody.addEventListener(
  'touchstart',
  function (e) {
    e.preventDefault()
    startX = e.touches[0].pageX
    startY = e.touches[0].pageY
  },
  false,
)
mybody.addEventListener('touchmove', function (e) {
  e.preventDefault()
  moveEndX = e.changedTouches[0].pageX
  moveEndY = e.changedTouches[0].pageY
  X = moveEndX - startX
  Y = moveEndY - startY
  if (Math.abs(X) > Math.abs(Y) && X > 0) {
    alert('向右')
  } else if (Math.abs(X) > Math.abs(Y) && X < 0) {
    alert('向左')
  } else if (Math.abs(Y) > Math.abs(X) && Y > 0) {
    alert('向下')
  } else if (Math.abs(Y) > Math.abs(X) && Y < 0) {
    alert('向上')
  } else {
    alert('没滑动')
  }
})

判断两个对象是否相等 ​

js
function isEqual(x, y) {
  // 处理没有传入参数的情况
  if (typeof x === 'undefined' || typeof y === 'undefined') return false

  // 处理不是对象的情况, 如果两个基本类型则直接判断
  if (x === y) return true

  // 处理不是对象的情况
  if (!(x instanceof Object) || !(y instanceof Object)) return false

  // 必须是同一原型链
  if (x.constructor !== y.constructor) return false

  // 如果是数组进行比较
  if (Array.isArray(x) && Array.isArray(y)) {
    // 如果长度不同,则false
    if (x.length !== y.length) return false

    for (var i = 0; i < x.length; i++) {
      // 如果相等则跳出
      if (x[i] === y[i]) continue

      // 判断不是对象的跳出
      if (typeof x[i] !== 'object') return false

      // 递归重新调用
      if (!isEqual(x[i], y[i])) return false
    }
    return true
  }

  for (var p in x) {
    if (x.hasOwnProperty(p)) {
      // 如果y里面没有p则false
      if (!y.hasOwnProperty(p)) return false

      // 如果基础类型相等, 则跳出该循环, 不相等的情况肯定又是对象
      if (x[p] === y[p]) continue

      // 数字、字符串、函数必须严格相等;
      if (typeof x[p] !== 'object') return false

      // 递归调用
      if (!isEqual(x[p], y[p])) return false
    }
  }

  for (p in y) {
    if (y.hasOwnProperty(p) && !x.hasOwnProperty(p)) return false
  }
  return true
}
function isEqual(x, y) {
  // 处理没有传入参数的情况
  if (typeof x === 'undefined' || typeof y === 'undefined') return false

  // 处理不是对象的情况, 如果两个基本类型则直接判断
  if (x === y) return true

  // 处理不是对象的情况
  if (!(x instanceof Object) || !(y instanceof Object)) return false

  // 必须是同一原型链
  if (x.constructor !== y.constructor) return false

  // 如果是数组进行比较
  if (Array.isArray(x) && Array.isArray(y)) {
    // 如果长度不同,则false
    if (x.length !== y.length) return false

    for (var i = 0; i < x.length; i++) {
      // 如果相等则跳出
      if (x[i] === y[i]) continue

      // 判断不是对象的跳出
      if (typeof x[i] !== 'object') return false

      // 递归重新调用
      if (!isEqual(x[i], y[i])) return false
    }
    return true
  }

  for (var p in x) {
    if (x.hasOwnProperty(p)) {
      // 如果y里面没有p则false
      if (!y.hasOwnProperty(p)) return false

      // 如果基础类型相等, 则跳出该循环, 不相等的情况肯定又是对象
      if (x[p] === y[p]) continue

      // 数字、字符串、函数必须严格相等;
      if (typeof x[p] !== 'object') return false

      // 递归调用
      if (!isEqual(x[p], y[p])) return false
    }
  }

  for (p in y) {
    if (y.hasOwnProperty(p) && !x.hasOwnProperty(p)) return false
  }
  return true
}

10 秒内不重新请求接口 ​

场景:解决接口数据返回慢的问题

js
let fetchData = JSON.parse(sessionStorage.getItem('fetchData')) || {
  lastUpdate: -1,
  valid: false,
}
if (+new Date() - lastUpdate > 10000 || !fetchData.valid) {
  // 重新请求接口, 接口返回之后设置数据;
  sessionStorage.setItem('fetchData', {
    lastUpdate: +new Date(),
    valid: true,
  })
}
let fetchData = JSON.parse(sessionStorage.getItem('fetchData')) || {
  lastUpdate: -1,
  valid: false,
}
if (+new Date() - lastUpdate > 10000 || !fetchData.valid) {
  // 重新请求接口, 接口返回之后设置数据;
  sessionStorage.setItem('fetchData', {
    lastUpdate: +new Date(),
    valid: true,
  })
}

执行字符串的语句 ​

  1. eval
  2. new Function
  3. setTimeout

计算百分比 ​

参数 1:是要计算百分比的数组 参数 2:是数组的下标 参数 3:要保留几位小数

js
export function getPercentValue(valueList, idx, precision) {
  // 判断是否为空
  if (!valueList[idx]) {
    return 0
  }
  // 求和
  var sum = valueList.reduce(function (acc, val) {
    return acc + (isNaN(val) ? 0 : val)
  }, 0)
  if (sum === 0) {
    return 0
  }
  // 10的2次幂是100,用于计算精度。
  var digits = Math.pow(10, precision)
  // 扩大比例100,
  var votesPerQuota = valueList.map(function (val) {
    return ((isNaN(val) ? 0 : val) / sum) * digits * 100
  })
  // 总数,扩大比例意味的总数要扩大
  var targetSeats = digits * 100
  // 再向下取值,组成数组
  var seats = votesPerQuota.map(function (votes) {
    return Math.floor(votes)
  })
  // 再新计算合计,用于判断与总数量是否相同,相同则占比会100%
  var currentSum = seats.reduce(function (acc, val) {
    return acc + val
  }, 0)
  // 余数部分的数组:原先数组减去向下取值的数组,得到余数部分的数组
  var remainder = votesPerQuota.map(function (votes, idx) {
    return votes - seats[idx]
  })
  // 给最大最大的余额加1,凑个占比100%;
  while (currentSum < targetSeats) {
    //  找到下一个最大的余额,给其加1
    var max = Number.NEGATIVE_INFINITY
    var maxId = null
    for (var i = 0, len = remainder.length; i < len; ++i) {
      if (remainder[i] > max) {
        max = remainder[i]
        maxId = i
      }
    }
    // 对最大项余额加1
    ++seats[maxId]
    // 已经增加最大余数加1,则下次判断就可以不需要再判断这个余额数。
    remainder[maxId] = 0
    // 总的也要加1,为了判断是否总数是否相同,跳出循环。
    ++currentSum
  }
  // 这时候的seats就会总数占比会100%
  return seats[idx] / digits
}
export function getPercentValue(valueList, idx, precision) {
  // 判断是否为空
  if (!valueList[idx]) {
    return 0
  }
  // 求和
  var sum = valueList.reduce(function (acc, val) {
    return acc + (isNaN(val) ? 0 : val)
  }, 0)
  if (sum === 0) {
    return 0
  }
  // 10的2次幂是100,用于计算精度。
  var digits = Math.pow(10, precision)
  // 扩大比例100,
  var votesPerQuota = valueList.map(function (val) {
    return ((isNaN(val) ? 0 : val) / sum) * digits * 100
  })
  // 总数,扩大比例意味的总数要扩大
  var targetSeats = digits * 100
  // 再向下取值,组成数组
  var seats = votesPerQuota.map(function (votes) {
    return Math.floor(votes)
  })
  // 再新计算合计,用于判断与总数量是否相同,相同则占比会100%
  var currentSum = seats.reduce(function (acc, val) {
    return acc + val
  }, 0)
  // 余数部分的数组:原先数组减去向下取值的数组,得到余数部分的数组
  var remainder = votesPerQuota.map(function (votes, idx) {
    return votes - seats[idx]
  })
  // 给最大最大的余额加1,凑个占比100%;
  while (currentSum < targetSeats) {
    //  找到下一个最大的余额,给其加1
    var max = Number.NEGATIVE_INFINITY
    var maxId = null
    for (var i = 0, len = remainder.length; i < len; ++i) {
      if (remainder[i] > max) {
        max = remainder[i]
        maxId = i
      }
    }
    // 对最大项余额加1
    ++seats[maxId]
    // 已经增加最大余数加1,则下次判断就可以不需要再判断这个余额数。
    remainder[maxId] = 0
    // 总的也要加1,为了判断是否总数是否相同,跳出循环。
    ++currentSum
  }
  // 这时候的seats就会总数占比会100%
  return seats[idx] / digits
}

根据路径找对应值 ​

js
function getPropByPath(obj, path, strict) {
  if (!obj || !path) return undefined
  let tempObj = obj
  path = path.replace(/\[(\w+)\]/g, '.$1')
  path = path.replace(/^\./, '')

  const keyArr = path.split('.')
  let i = 0
  for (let len = keyArr.length; i < len - 1; ++i) {
    if (!tempObj && !strict) break
    const key = keyArr[i]
    if (key in tempObj) {
      tempObj = tempObj[key]
    } else {
      if (strict) {
        throw new Error('please transfer a valid prop path to form item!')
      }
      break
    }
  }
  return {
    o: tempObj,
    k: keyArr[i],
    v: tempObj ? tempObj[keyArr[i]] : null,
  }
}
function getPropByPath(obj, path, strict) {
  if (!obj || !path) return undefined
  let tempObj = obj
  path = path.replace(/\[(\w+)\]/g, '.$1')
  path = path.replace(/^\./, '')

  const keyArr = path.split('.')
  let i = 0
  for (let len = keyArr.length; i < len - 1; ++i) {
    if (!tempObj && !strict) break
    const key = keyArr[i]
    if (key in tempObj) {
      tempObj = tempObj[key]
    } else {
      if (strict) {
        throw new Error('please transfer a valid prop path to form item!')
      }
      break
    }
  }
  return {
    o: tempObj,
    k: keyArr[i],
    v: tempObj ? tempObj[keyArr[i]] : null,
  }
}

获取 Y 轴最大值 ​

js
/**
 * echarts 获取y轴最大值
 * @returns
 */
export function yAxisMax(maxValue, splitNumber = 5) {
  if (Number.isNaN(maxValue / 1) || maxValue / 1 < 10) {
    return 10
  }
  const max = Math.ceil(maxValue)
  const itemValue = `${Math.ceil(max / splitNumber)}`
  const mins = Math.ceil(+itemValue / 10 ** (itemValue.length - 1))
  const item = mins * 10 ** (itemValue.length - 1)
  // item 需要是5的整数倍
  const res = Math.ceil(item / splitNumber) * splitNumber * splitNumber
  return res
}
/**
 * echarts 获取y轴最大值
 * @returns
 */
export function yAxisMax(maxValue, splitNumber = 5) {
  if (Number.isNaN(maxValue / 1) || maxValue / 1 < 10) {
    return 10
  }
  const max = Math.ceil(maxValue)
  const itemValue = `${Math.ceil(max / splitNumber)}`
  const mins = Math.ceil(+itemValue / 10 ** (itemValue.length - 1))
  const item = mins * 10 ** (itemValue.length - 1)
  // item 需要是5的整数倍
  const res = Math.ceil(item / splitNumber) * splitNumber * splitNumber
  return res
}

环境判断 ​

js
const UA = window.navigator.userAgent.toLowerCase()

// Android
const isAndroid = /android/.test(UA)

// IOS
const isIOS = /iphone|ipad|ipod|ios/.test(UA)

// 浏览器环境
const inBrowser = typeof window !== 'undefined'

// IE
const isIE = /msie|trident/.test(UA)

// Edge
const isEdge = UA.indexOf('edge/') > 0

// Chrome
const isChrome = /chrome\/\d+/.test(UA) && !isEdge

// 微信
const isWeChat = /micromessenger/.test(UA)

// 移动端
const isMobile = 'ontouchstart' in window
const UA = window.navigator.userAgent.toLowerCase()

// Android
const isAndroid = /android/.test(UA)

// IOS
const isIOS = /iphone|ipad|ipod|ios/.test(UA)

// 浏览器环境
const inBrowser = typeof window !== 'undefined'

// IE
const isIE = /msie|trident/.test(UA)

// Edge
const isEdge = UA.indexOf('edge/') > 0

// Chrome
const isChrome = /chrome\/\d+/.test(UA) && !isEdge

// 微信
const isWeChat = /micromessenger/.test(UA)

// 移动端
const isMobile = 'ontouchstart' in window

微信 api promise 化 ​

js
function promisify(fn) {
  return function (options) {
    return new Promise((resolve, reject) => {
      fn(
        Object.assign({}, options, {
          success: resolve,
          fail: reject,
        }),
      )
    })
  }
}

// 例 获取系统信息
promisify(wx.getSystemInfo)
  .then((res) => {
    console.log('success', res)
  })
  .catch((err) => {
    console.log('fail', err)
  })
function promisify(fn) {
  return function (options) {
    return new Promise((resolve, reject) => {
      fn(
        Object.assign({}, options, {
          success: resolve,
          fail: reject,
        }),
      )
    })
  }
}

// 例 获取系统信息
promisify(wx.getSystemInfo)
  .then((res) => {
    console.log('success', res)
  })
  .catch((err) => {
    console.log('fail', err)
  })

验证 url 是否有效 ​

js
function isUrl(string) {
  if (typeof string !== 'string') {
    return false
  }
  try {
    new URL(string)
    return true
  } catch (err) {
    return false
  }
}

isUrl('maomao') // false

isUrl('https://github.com/maomao1996') // true
isUrl('https://a.b.c') // true
function isUrl(string) {
  if (typeof string !== 'string') {
    return false
  }
  try {
    new URL(string)
    return true
  } catch (err) {
    return false
  }
}

isUrl('maomao') // false

isUrl('https://github.com/maomao1996') // true
isUrl('https://a.b.c') // true

注意

该技巧只适用于一些验证不严格的场景,严格场景下可以使用这个 npm 包 —— is-url

提取身份证信息 ​

  • 参数 ​

    • idCard: 身份证号码
    • separator: 出生年月日的分割字符,默认为 /
  • 返回值 ​

    • age: 年龄(实岁)
    • birthday: 出生年月日
    • gender: 性别(0 女 1 男)
js
function getIdCardInfo(idCard, separator = '/') {
  if (
    !/^[1-9]\d{5}(?:18|19|20)\d{2}(?:0[1-9]|10|11|12)(?:0[1-9]|[1-2]\d|30|31)\d{3}[\dXx]$/.test(
      idCard,
    )
  ) {
    throw Error(`${idCard}不是一个身份证号码`)
  }
  // 提取 idCard 中的字符
  const idSubstr = (s, e) => idCard.substr(s, e)
  // 拼接日期
  const splice = (d) => d.join(separator)
  // 获取出生年月日 性别(0 女 1 男)
  let birthday, gender
  if (idCard.length === 18) {
    birthday = splice([idSubstr(6, 4), idSubstr(10, 2), idSubstr(12, 2)])
    gender = idSubstr(-2, 1) & 1
  } else {
    birthday = splice(idSubstr(6, 2), idSubstr(8, 2), idSubstr(10, 2))
    gender = idSubstr(-1, 1) & 1
  }
  // 获取年龄(实岁)
  const birthDate = new Date(birthday)
  const newDate = new Date()
  const year = newDate.getFullYear()
  let age = year - birthDate.getFullYear()
  if (newDate < new Date(splice([year, birthday.substring(5)]))) {
    age--
  }
  return {
    age,
    birthday,
    gender,
  }
}
function getIdCardInfo(idCard, separator = '/') {
  if (
    !/^[1-9]\d{5}(?:18|19|20)\d{2}(?:0[1-9]|10|11|12)(?:0[1-9]|[1-2]\d|30|31)\d{3}[\dXx]$/.test(
      idCard,
    )
  ) {
    throw Error(`${idCard}不是一个身份证号码`)
  }
  // 提取 idCard 中的字符
  const idSubstr = (s, e) => idCard.substr(s, e)
  // 拼接日期
  const splice = (d) => d.join(separator)
  // 获取出生年月日 性别(0 女 1 男)
  let birthday, gender
  if (idCard.length === 18) {
    birthday = splice([idSubstr(6, 4), idSubstr(10, 2), idSubstr(12, 2)])
    gender = idSubstr(-2, 1) & 1
  } else {
    birthday = splice(idSubstr(6, 2), idSubstr(8, 2), idSubstr(10, 2))
    gender = idSubstr(-1, 1) & 1
  }
  // 获取年龄(实岁)
  const birthDate = new Date(birthday)
  const newDate = new Date()
  const year = newDate.getFullYear()
  let age = year - birthDate.getFullYear()
  if (newDate < new Date(splice([year, birthday.substring(5)]))) {
    age--
  }
  return {
    age,
    birthday,
    gender,
  }
}

大文件分片上传 ​

js
import SparkMD5 from ''; // 导入MD5计算文件哈希
const CHUNK_SIZE = 1024 * 1024 * 5; // 5MB
const THREAD_COUNT = navigator.hardwareConcurrency || 4;// cpu核心数

const function createChunk(file, chunkIndex, CHUNK_SIZE) {
  return new Promise((resolve) => {
    const start = chunkIndex * CHUNK_SIZE;
    const end = Math.min(file.size, start + CHUNK_SIZE);
    const spark = new SparkMD5.ArrayBuffer();
    const fileReader = new FileReader();
    const blob = file.slice(start, end);
    fileReader.onload = function (e) {
      spark.append(e.target.result);
      resolve({
        start,
        end,
        chunkIndex,
        hash: spark.end(),
        blob
      })
    }
  });
  fileReader.readAsArrayBuffer(blob);
}

const function cutFile(file) {
  return new Promise((resolve) => {
    const chunkCount = Math.ceil(file.size / CHUNK_SIZE);
    const threadChunkCount = Math.ceil(chunkCount / THREAD_COUNT);
    const start = i * threadChunkCount;
    const end = (i + 1) * threadChunkCount > chunkCount ? chunkCount : (i + 1) * threadChunkCount;
    const result = [];
    let finishCount = 0;
    for (let i = 0; i < THREAD_COUNT; i++) {
      // 创建一个线程,分配任务
      const worker = new Worker(async (e) => {
        const {
          file,
          CHUNK_SIZE,
          startChunkIndex: start,
          endChunkIndex: end
        } = e.data;

        const proms = [];
        for (let i = start; i < end; i++) {
          proms.push(createChunk(file, i, CHUNK_SIZE));
        }
        const chunks = await Promise.all(proms);
        postMessage(chunks);
      }, {
        type: 'module'
      })
    };

    worker.postMessage({
      file,
      CHUNK_SIZE,
      startChunkIndex: start,
      endChunkIndex: end
    });

    worker.onmessage = e => {
      for (let i = start, ; i < end; i++) {
        result[i] = e.data[i - start];
      }
      worker.terminate();// 结束线程
      finishCount++;
      if (finishCount === THREAD_COUNT) {
        resolve(result)
      }
    }
  });
}
import SparkMD5 from ''; // 导入MD5计算文件哈希
const CHUNK_SIZE = 1024 * 1024 * 5; // 5MB
const THREAD_COUNT = navigator.hardwareConcurrency || 4;// cpu核心数

const function createChunk(file, chunkIndex, CHUNK_SIZE) {
  return new Promise((resolve) => {
    const start = chunkIndex * CHUNK_SIZE;
    const end = Math.min(file.size, start + CHUNK_SIZE);
    const spark = new SparkMD5.ArrayBuffer();
    const fileReader = new FileReader();
    const blob = file.slice(start, end);
    fileReader.onload = function (e) {
      spark.append(e.target.result);
      resolve({
        start,
        end,
        chunkIndex,
        hash: spark.end(),
        blob
      })
    }
  });
  fileReader.readAsArrayBuffer(blob);
}

const function cutFile(file) {
  return new Promise((resolve) => {
    const chunkCount = Math.ceil(file.size / CHUNK_SIZE);
    const threadChunkCount = Math.ceil(chunkCount / THREAD_COUNT);
    const start = i * threadChunkCount;
    const end = (i + 1) * threadChunkCount > chunkCount ? chunkCount : (i + 1) * threadChunkCount;
    const result = [];
    let finishCount = 0;
    for (let i = 0; i < THREAD_COUNT; i++) {
      // 创建一个线程,分配任务
      const worker = new Worker(async (e) => {
        const {
          file,
          CHUNK_SIZE,
          startChunkIndex: start,
          endChunkIndex: end
        } = e.data;

        const proms = [];
        for (let i = start; i < end; i++) {
          proms.push(createChunk(file, i, CHUNK_SIZE));
        }
        const chunks = await Promise.all(proms);
        postMessage(chunks);
      }, {
        type: 'module'
      })
    };

    worker.postMessage({
      file,
      CHUNK_SIZE,
      startChunkIndex: start,
      endChunkIndex: end
    });

    worker.onmessage = e => {
      for (let i = start, ; i < end; i++) {
        result[i] = e.data[i - start];
      }
      worker.terminate();// 结束线程
      finishCount++;
      if (finishCount === THREAD_COUNT) {
        resolve(result)
      }
    }
  });
}

web 端获取定位 ​

html
<button onclick="getLocation()">Get Location</button>
<p id="status"></p>
<button onclick="getLocation()">Get Location</button>
<p id="status"></p>
js
function getLocation() {
  const status = document.getElementById('status')

  // 检查浏览器是否支持Geolocation API
  if (navigator.geolocation) {
    // 获取当前位置
    navigator.geolocation.getCurrentPosition(showPosition, showError)
    status.textContent = 'Locating...'
  } else {
    status.textContent = 'Geolocation is not supported by this browser.'
  }
}

function showPosition(position) {
  const status = document.getElementById('status')
  const latitude = position.coords.latitude
  const longitude = position.coords.longitude

  status.textContent = `Latitude: ${latitude}, Longitude: ${longitude}`

  // 打印到控制台
  console.log(`Latitude: ${latitude}, Longitude: ${longitude}`)
}

function showError(error) {
  const status = document.getElementById('status')
  switch (error.code) {
    case error.PERMISSION_DENIED:
      status.textContent = 'User denied the request for Geolocation.'
      break
    case error.POSITION_UNAVAILABLE:
      status.textContent = 'Location information is unavailable.'
      break
    case error.TIMEOUT:
      status.textContent = 'The request to get user location timed out.'
      break
    case error.UNKNOWN_ERROR:
      status.textContent = 'An unknown error occurred.'
      break
  }
}
function getLocation() {
  const status = document.getElementById('status')

  // 检查浏览器是否支持Geolocation API
  if (navigator.geolocation) {
    // 获取当前位置
    navigator.geolocation.getCurrentPosition(showPosition, showError)
    status.textContent = 'Locating...'
  } else {
    status.textContent = 'Geolocation is not supported by this browser.'
  }
}

function showPosition(position) {
  const status = document.getElementById('status')
  const latitude = position.coords.latitude
  const longitude = position.coords.longitude

  status.textContent = `Latitude: ${latitude}, Longitude: ${longitude}`

  // 打印到控制台
  console.log(`Latitude: ${latitude}, Longitude: ${longitude}`)
}

function showError(error) {
  const status = document.getElementById('status')
  switch (error.code) {
    case error.PERMISSION_DENIED:
      status.textContent = 'User denied the request for Geolocation.'
      break
    case error.POSITION_UNAVAILABLE:
      status.textContent = 'Location information is unavailable.'
      break
    case error.TIMEOUT:
      status.textContent = 'The request to get user location timed out.'
      break
    case error.UNKNOWN_ERROR:
      status.textContent = 'An unknown error occurred.'
      break
  }
}

下载文件 ​

文件放在 public/excel

jsx
webpack
<template>
  <div>
    <button @click="downloadExcel">下载Excel文件</button>
  </div>
</template>

<script>
export default {
  methods: {
    downloadExcel() {
      const fileName = 'example.xlsx';
      const filePath = process.env.BASE_URL + 'excel/' + fileName;
      const link = document.createElement('a');
      link.href = filePath;
      link.download = fileName;
      link.click();
    }
  }
}
</script>


vite
<template>
  <div>
    <button @click="downloadExcel">下载Excel文件</button>
  </div>
</template>

<script>
export default {
  methods: {
    downloadExcel() {
      const fileName = 'example.xlsx';
      const filePath = `${import.meta.env.BASE_URL}excel/${fileName}`;
      const link = document.createElement('a');
      link.href = filePath;
      link.download = fileName;
      link.click();
    }
  }
}
</script>
webpack
<template>
  <div>
    <button @click="downloadExcel">下载Excel文件</button>
  </div>
</template>

<script>
export default {
  methods: {
    downloadExcel() {
      const fileName = 'example.xlsx';
      const filePath = process.env.BASE_URL + 'excel/' + fileName;
      const link = document.createElement('a');
      link.href = filePath;
      link.download = fileName;
      link.click();
    }
  }
}
</script>


vite
<template>
  <div>
    <button @click="downloadExcel">下载Excel文件</button>
  </div>
</template>

<script>
export default {
  methods: {
    downloadExcel() {
      const fileName = 'example.xlsx';
      const filePath = `${import.meta.env.BASE_URL}excel/${fileName}`;
      const link = document.createElement('a');
      link.href = filePath;
      link.download = fileName;
      link.click();
    }
  }
}
</script>

a 标签下载 ​

jsx
<a :href="`${完整的下载地址}`" target="downloadFile">{{文件名称}}</a>
<iframe style="display: none;" name="downloadFile"></iframe>
<a :href="`${完整的下载地址}`" target="downloadFile">{{文件名称}}</a>
<iframe style="display: none;" name="downloadFile"></iframe>

动态生成 a 标签下载 ​

jsx
// 用fetch发送请求 对请求回来的二进制文件流进行处理
fetch('/upload/user.png').then((res) => {
  res.blob().then((blob) => {
    const blobUrl = window.URL.createObjectURL(blob)
    // 这里的文件名根据实际情况从响应头或者url里获取
    const filename = 'user.txt'
    const a = document.createElement('a')
    a.href = blobUrl
    a.download = filename
    a.click()
    window.URL.revokeObjectURL(blobUrl)
  })
})
// 用fetch发送请求 对请求回来的二进制文件流进行处理
fetch('/upload/user.png').then((res) => {
  res.blob().then((blob) => {
    const blobUrl = window.URL.createObjectURL(blob)
    // 这里的文件名根据实际情况从响应头或者url里获取
    const filename = 'user.txt'
    const a = document.createElement('a')
    a.href = blobUrl
    a.download = filename
    a.click()
    window.URL.revokeObjectURL(blobUrl)
  })
})