极简js代码片段
小技巧
if(value)直接 value 表示判断是否有内容,默认为有;元素.checked=true;复选框被选中在函数里面递归调用必须
return,否则不走后面trim();常用于 value;干掉左右空格;
判断 value 输入为空时,不让提交,如果 value 输入空格,也能提交,此时,需要
input.value.trim();使用 trim 方法可以清除 value 里面的空格并弹窗;,ie8 不支持;,
value 写完后可以在按钮后面加一行代码:input.value = '';清空内容方便用户下次输入;
数组去重可以创建一个空的数组,
indexOf查询没有的往里面放;调用一个方法,如果这个方法没有前缀,则
this指向window;有前缀指向调用的,所以谁调用的函数,这个 this 就指向谁document.onkeydown;document 页面直接执行按键输入;点的形式都可以使用中括号的形式
jslet 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])当输出对象遇到[object object]时,使用 JSON.stringify 转字符串输出;
当在不使用模板字符换行时,可以使用折行转义字符
\jsvar htmlSTring = "<div>\ This is a string.\ </div>";var htmlSTring = "<div>\ This is a string.\ </div>";一个页面不能有两个 window.onscroll,可以使用绑定事件来做两个
jswindow.addEventListener('scroll', () => {}) // 如果使用两个window.onscroll, 后一个则会覆盖前一个window.addEventListener('scroll', () => {}) // 如果使用两个window.onscroll, 后一个则会覆盖前一个给代码添加 debugger 可以测试 bug;
debugger可以查看我写的浏览器技巧 断点内容;Object.prototype.hasOwnProperty.call(obj,i)相当于以下jsobj.hasOwnProperty(i)obj.hasOwnProperty(i)数组删除假值
jsvar 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']利用 es6 默认赋值语法,判断参数是否为空值
jsconst 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) }
复制文本到剪切板
const copyToClipboard = (text) => navigator.clipboard.writeText(text)
copyToClipboard('Hello, World!')const copyToClipboard = (text) => navigator.clipboard.writeText(text)
copyToClipboard('Hello, World!')获取某个日期位于当年的第几天
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 颜色灰度化 (基于光感加权平均)
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 地址
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}筛选对象属性
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}随机颜色
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())随机字符串
const randomString = (n) =>
Array.from({ length: n }, () => String.fromCharCode(Math.floor(Math.random() * 26) + 97)).join('')
console.log(randomString(10)) // iajxwxjqconst randomString = (n) =>
Array.from({ length: n }, () => String.fromCharCode(Math.floor(Math.random() * 26) + 97)).join('')
console.log(randomString(10)) // iajxwxjq去掉字符串里面的标签
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!"判断语句省略写法
//判断;真就真
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 的指向问题, 也可以使用箭头函数避免这个问题
// 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(面版)
定时器使用函数需要传参时
// 禁止写法
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
Math.random().toString(36).substr(3, 6) //得到6位随机idMath.random().toString(36).substr(3, 6) //得到6位随机id查看随机 6 位数;
Array.from({ length: 20 }, (i) => Math.ceil(Math.random() * 6))Array.from({ length: 20 }, (i) => Math.ceil(Math.random() * 6))随机 16 进制颜色
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保险合并多个对象
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'}模板标签替换
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,'')
}) // 大花括号也可以没有转义符;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]
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
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()}`
}鼠标禁止右键
<body oncontentmenu="return false">
<div></div>
</body><body oncontentmenu="return false">
<div></div>
</body>复制功能
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 之间
String.fromCharCode(97 + Math.ceil(Math.random() * 25)) //返回一个小写字母String.fromCharCode(97 + Math.ceil(Math.random() * 25)) //返回一个小写字母将 url 转换成对象形式取值
- 使用 while 循环+正则
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
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}- 使用正则
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
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
// 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 () {}
}清除缓存技巧
数据不更新,本地有缓存,可以在网址后面加个时间戳
var t = Date.now()
var url = `?t=${t}`var t = Date.now()
var url = `?t=${t}`临时使用$获取元素
当一个函数里面需要获取多个节点时,可以使用下面方法
;(function ($) {
$('div').scrollTop = $('.center').clientHeight
})(document.querySelector.bind(document));(function ($) {
$('div').scrollTop = $('.center').clientHeight
})(document.querySelector.bind(document))检测移动端
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)
}解决谷歌翻译代码块的问题
将以下代码添加到一个新的书签,网址写以下代码
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
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 四舍五入的问题
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 页)
常用对象的方法
判断对象的数据类型
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)
}
}精准判断类型:(类型需要大写)
'[object 类型]' === Object.prototype.toString.call(形参)'[object 类型]' === Object.prototype.toString.call(形参)动态属性名
声明一个变量;使用中括号代替,也可以是对象变量属性;
// 动态属性名
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
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}]有条件的象征对象
在对象里面使用...去使用布尔值;
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' }]解构原始对象
提取两部分,分为两个对象;
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
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 事件滑动的方向
根据移动的值正负来判断
//滑动处理
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('没滑动')
}
})判断两个对象是否相等
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 秒内不重新请求接口
场景:解决接口数据返回慢的问题
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,
})
}执行字符串的语句
- eval
- new Function
- setTimeout
计算百分比
参数 1:是要计算百分比的数组 参数 2:是数组的下标 参数 3:要保留几位小数
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
}根据路径找对应值
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 轴最大值
/**
* 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
}环境判断
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 windowconst 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 化
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 是否有效
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') // truefunction 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
提取身份证信息
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,
}
}大文件分片上传
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 端获取定位
<button onclick="getLocation()">Get Location</button>
<p id="status"></p><button onclick="getLocation()">Get Location</button>
<p id="status"></p>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
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 标签下载
<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 标签下载
// 用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)
})
})
Cao Note