零碎知识17(重点:文件下载/dns解析/async返回值)

35 阅读1分钟

文件下载

后端下载文件的接口是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();
}

通过接口获取二进制文件并用后端给的名字下载

blog.csdn.net/timebeign/a… blog.csdn.net/weixin_4970…

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 选择器)

image.png

setup里直接await

  • 会堵塞组件正常渲染,顶级会自动默认加async

image.png

  • 子组件里被await阻塞时,可以通过这种方式先展示个默认组件 image.png

研究瀑布流

github.com/huodoushige…

  • dompurify 防止 XSS 攻击

收藏/动画与样式

vscode+jsDoc

js文件里 function xx() 上方写 /** 时 下面就有提示补全气泡,选中就能生成这种结构 对于methods内写的函数,上方要手动粘贴进去这种注释结构,写了后也有提示

/**
 * @param {*} element 
 * @param {*} fn 
 * @returns 
 */

最小字体低于12px无法再缩小的问题

  • 谷歌浏览器的策略其实改了,可以无限制缩小字体。这个地方设置成12px 字体就无法持续缩小(响应式页面 字体转成了0.8vw 缩小页面宽度时 文字不能持续缩小 导致页面扭曲) image.png

巧用可选链

if (params && params.filter) return 'Foo'
if (params?.filter) return 'Foo'

刷新dns以及固定dns域名解析ip

  • 控制台输入命令 ipconfig /flushdns 刷新dns

固定域名解析

参考

  1. C:\windows\system32\drivers\etc,文件夹中找到hosts文件并用记事本打开。
  2. 新建一个文本文件,把hosts文件内容拷过去,在后面添加域名映射,然后后缀txt去掉,拖到etc文件夹里替换原本的hosts文件
  3. 文本修改格式:按照 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加密

摘自:blog.51cto.com/u_14172/106…

  • 模式有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' 看上去只是导入了一个,实际上整个文件都会从头到尾执行一遍,最后才会导入

页面引导(步骤)

driverjs.com/docs/config…

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')
   },

案例二

这是最简洁的方法,适用于大多数情况。如果你不需要对resolvereject进行特殊处理,可以直接返回异步函数的结果。

// 模拟异步操作
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);
    });

github下载打包后的文件

image.png