文件下载
后端下载文件的接口是get请求,直接拼接链接下载
import { host } from '@/api/request'
import qs from 'qs'
export function downloadFile(url, paramsObj) {
var aEl = document.createElement("a");
aEl.href = `${host}${url}?${qs.stringify(paramsObj)}`;
aEl.setAttribute('download', true)
aEl.style.display = "none";
document.body.appendChild(aEl);
aEl.click();
aEl.remove();
}
通过接口获取二进制文件并用后端给的名字下载
vue axios无法获取响应头Content-Disposition字段
默认情况下,header只有六种 simple response headers(简单响应首部)暴露给外部:
Cache-Control
Content-Language
Content-Type
Expires
Last-Modified
Pragma
暴露给外部,意思是既可以在 Network 里看到,也可以在前端代码里获取到他们的值。
目前的情况是Network 可以看到,但是axios的response拿不到Content-Disposition,Content-Range。
响应首部 Access-Control-Expose-Headers 就是控制暴露的开关,列出哪些首部可以作为响应的一部分暴露给外部。
response.setHeader("Access-Control-Expose-Headers", "Content-Disposition");
通过后端获取blob并下载
- axios拦截配置特殊处理
service.interceptors.response.use(
(response) => {
// ----后端返回二进制时,要用响应头信息-------
if (response.config.responseType === 'blob') {
return response
}
......
// axios请求里,要多配一个属性 responseType: 'blob',
export function getFile(data) {
return request({
url: "/getfile",
method: "get",
responseType: 'blob',
data,
});
}
- 接口获取数据后,调用该函数触发下载
// 下面的函数是处理接口返回数据时的方法
export function downloadBlob(res, fileName = '') {
const blob = new Blob([res]);
var aEl = document.createElement("a");
aEl.href = URL.createObjectURL(blob);
fileName = fileName || (res.headers['content-disposition'].split("="))[1]
aEl.download = fileName;
aEl.style.display = "none";
document.body.appendChild(aEl);
aEl.click();
aEl.remove();
window.URL.revokeObjectURL(aEl.href)
}
指定挂载容器
- 这样可以把内部直接挂载到body上(to 选择器)
setup里直接await
- 会堵塞组件正常渲染,顶级会自动默认加async
- 子组件里被await阻塞时,可以通过这种方式先展示个默认组件
研究瀑布流
- dompurify 防止 XSS 攻击
收藏/动画与样式
vscode+jsDoc
js文件里 function xx() 上方写 /** 时 下面就有提示补全气泡,选中就能生成这种结构 对于methods内写的函数,上方要手动粘贴进去这种注释结构,写了后也有提示
/**
* @param {*} element
* @param {*} fn
* @returns
*/
最小字体低于12px无法再缩小的问题
- 谷歌浏览器的策略其实改了,可以无限制缩小字体。这个地方设置成12px 字体就无法持续缩小(响应式页面 字体转成了0.8vw 缩小页面宽度时 文字不能持续缩小 导致页面扭曲)
巧用可选链
if (params && params.filter) return 'Foo'
if (params?.filter) return 'Foo'
刷新dns以及固定dns域名解析ip
- 控制台输入命令
ipconfig /flushdns
刷新dns
固定域名解析
- C:\windows\system32\drivers\etc,文件夹中找到hosts文件并用记事本打开。
- 新建一个文本文件,把hosts文件内容拷过去,在后面添加域名映射,然后后缀txt去掉,拖到etc文件夹里替换原本的hosts文件
- 文本修改格式:按照 ip地址 域名 的格式添加单独的一行记录。例如
112.124.39.29 www.server110.com
注意,IP地址前面不要有空格,ip地址和域名之间,要有至少1个空格。 4. ping 域名-->回车查看结果 确认这个域名映射是否改好了 5. ctrl+f5强制刷新浏览器缓存
设置dns解析服务器
有的网络下无法访问网页时,要手动指定dns服务器
控制面板\网络和 Internet\网络连接
找到当前联通网络的那个,双击,点属性,ipv4双击,使用下面的DNS服务器地址,设置首选/备用dns
- 114.114.114.114 //国内好用
- 223.5.5.5 //阿里
js小技巧
摘自 作者:shichuan juejin.cn/post/723081…
获取变量的类型
const getType = (variable) => Object.prototype.toString.call(variable).slice(8, -1).toLowerCase();
getType(''); // string
getType(0); // number
getType(); // undefined
getType(null); // null
getType({}); // object
getType([]); // array
getType(0); // number
getType(() => {}); // function
从数组中删除特定元素
- 传统做法是先findIndx 再splice,没下面这个高效
const removedArray = array.filter((item) => item !== elementToRemove);
AES加密
- 模式有CBC(有向量模式)和ECB(无向量模式),向量模式可以简单理解为偏移量,使用CBC模式需要定义一个IvParameterSpec对象(偏移量)
- ECB模式 加密/解密 blog.csdn.net/m0_61854862…
一、 安装crypto-js
npm install crypto-js
二、封装AES文件
import CryptoJS from "crypto-js"
const key = CryptoJS.enc.Utf8.parse("key秘钥字符串");
export default {
// 加密
encrypt(word) {
let srcs = CryptoJS.enc.Utf8.parse(word);
let encrypted = CryptoJS.AES.encrypt(srcs, key, {
mode: CryptoJS.mode.ECB,
padding: CryptoJS.pad.Pkcs7
});
return encrypted.toString();
},
// 解密
decrypt(word) {
var decrypt = CryptoJS.AES.decrypt(word, key, {
mode: CryptoJS.mode.ECB,
padding: CryptoJS.pad.Pkcs7
});
return CryptoJS.enc.Utf8.stringify(decrypt).toString();
}
};
三、使用
import AES from "AES.js";
AES.encrypt(word)
四、假如key秘钥不足16位 则用 '\0' 补齐
"Zhtx2020" => "Zhtx2020\0\0\0\0\0\0\0\0"
import
import { prefixNameHtml } from '@/utils/common.js'
看上去只是导入了一个,实际上整个文件都会从头到尾执行一遍,最后才会导入
页面引导(步骤)
async函数里返回值
- 返回普通值
实际返回的是promise,且 then接收的值即为return的值
async commonBack(val) {
return val
},
const val = await this.commonBack(false) // false
- 返回promise
return的promise的resolve 即为调用该async函数的then。
return的promise的reject 即为调用该async函数的catch
async promiseBack(val) {
return new Promise((resolve, reject) => {
if (val) {
resolve('异步成功返回')
} else {
reject('异步失败返回')
}
})
},
const val2 = await this.promiseBack(true)
console.log(val2) // 异步成功返回
try {
await this.promiseBack(false)
} catch (e) {
console.log(e) // 异步失败返回
}
案例一
- 使用场景:操作触发拉取、复制任务时,一系列异步操作逐个触发,触发一个校验一个然后触发下一个
- 这种情况下,把请求及处理,都放到async函数里,这俩操作可以共用这个核心
async getCommonTagsPromise() {
let crmTagIds = []
const progressShow = (i) => {
this.$store.commit(
'updatePCLoading',
`标签获取进度 ${Math.floor(i + 1 / this.selAccount.length)}`
)
}
// 拉一个标签找交集,再拉另一个
for (let i = 0; i < this.selAccount.length; i++) {
const { tagIdList } = await getAndFormatAccountTags(
this.selAccount[i].saleUserId,
true
)
// 标签只会变少不会多
if (i === 0) {
crmTagIds.push(...tagIdList)
} else {
// 所有标签信息都在子标签的id里,平铺找交集后 最终再复原树
crmTagIds = getOverlap(crmTagIds, tagIdList)
}
progressShow()
}
// 通过id,复原标签树结构
const tagList = this.restoreTagTree(crmTagIds)
this.crmTagList = batchSendFormatTags(tagList, 'crm', 'CRM')
this.flatTagList = flatTreeArray(this.crmTagList)
//即使不返回值 调用它的函数await也会等待执行完
},
async getCommonTags() {
this.$store.commit('openPCLoading', '拉取标签中...')
await this.getCommonTagsPromise()
this.$store.commit('closeLoading')
},
案例二
这是最简洁的方法,适用于大多数情况。如果你不需要对resolve
或reject
进行特殊处理,可以直接返回异步函数的结果。
// 模拟异步操作
function fetchDataA() {
return new Promise((resolve) => {
setTimeout(() => resolve("数据A"), 1000);
});
}
function fetchDataB(dataA) {
return new Promise((resolve) => {
setTimeout(() => resolve(`${dataA} + 数据B`), 500);
});
}
// 定义一个异步函数
async function asyncOperation() {
try {
const dataA = await fetchDataA();
console.log('获取到的数据A:', dataA);
const result = await fetchDataB(dataA);
console.log('最终结果:', result);
return result;
} catch (error) {
throw error; // 或者进行其他错误处理
}
}
// 使用异步函数
asyncOperation()
.then(result => {
console.log('外部调用成功:', result);
})
.catch(error => {
console.error('外部调用失败:', error);
});