每月进步一点点--202304

1,821 阅读28分钟

37. 在ts文件中使用useRoute,因为执行过早,还没进入到业务页面之前,便去获取页面url的查询参数,造成业务逻辑错误,应该怎么处理?

用vue的useHook函数

import { ref, onMounted } from 'vue';
import { useRoute } from 'vue-router';


export const useDrcProduct = () => {
  const productType = ref(false);
  onMounted(() => {
    // 在mount函数中获取url查询参数
    productType.value = ['0', '2', '3', '4', '5'].includes(useRoute()?.query?.type as string);

  });

  return {
    productType,
  };
};

36. 突然之间,vue3项目,ant-design-vue3的组件都出现红色的波浪线,如何解决?

经过调查,是VSCode的Vue Language Features (Volar)插件上一版本不稳定造成的,切换到最新的预发布发版,问题就解决了。

image.png

35. vue3如何封装小组件?

<div class="tips"><span class="star">*</span>为必填项,填写后才可以保存</div>

方法一 用vue3 的h函数语法

语法为:

  • h 函数的第1个参数是标签名,
  • 2个是属性, 在这个例子里可以理解为html的所有属性,
  • 3个是内容, "内容"不仅仅可以是字符串, 还可以是VNode或2者混合
<script> 
    import { h } from "vue"; 
    const RedStar=()=>{
        const props = { class: 'tips' }; 
        const star = h("span", {class:'star"},'为必填项,填写后才可以保存'); 
        return h("div", props, [star]);
    }; 
}
</script>

方法二 用jsx语法

方法二需要在vite.config.ts中配置@vitejs/plugin-vue-jsx插件

// tsx语法支持
import vueJsx from '@vitejs/plugin-vue-jsx';
export default ()=>{
  return {
    plugins: [
      // ...
      vueJsx(),
    ]
  }
}
<script setup lang="tsx">
    const RedStar=()=>{
         return <div class="tips"><span class="star">*</span>为必填项,填写后才可以保存</div>
    }
<script>

34. Jenkins推送部署包成功,有些页面资源加载报404,是什么原因?

最后查明, 虽然推送显示的消息是成功提示,可是实际上推送的包有缺失,原本十几M的文件,去站点上查看只有6M多,少了一些文件。

33. Ant-Design-Vue Input组件的disabled属性有bug,该如何解决?

发现ant-design-vue Input组件一个bug, 给disabled设置空字符时会返回true, null和undefined返回正常,解决方法: 对空字符用!!转换成Boolean值。 企业微信截图_16823856018450.png

企业微信截图_16823856235604.png

32. 使用coding,提交合并代码请求后,收不到企业微信消息,怎么解决?

解决方法: 在企业微信群中创建一个机器人,向这个机器人推送coding上的代码通知,具体配置方法可以参考这篇文章

31. 网络请求工具使用的是axios,切换路由时, 如何取消上一页面所有的请求?

import axios from 'axios';
http.interceptors.request.use(config => {
    // 给请求设置标记
    config.cancelToken = store.source.token;
    return config;
}, err => {
    return Promise.reject(err);
})

router.beforeEach((to, from, next) => {
    // 取消上一页面的请求
    store.source.cancel && store.source.cancel();
    
    // 路由切换,更新取消请求标记
    const CancelToken = axios.CancelToken;
    store.source = CancelToken.source();
    next();
})

// store全局变量
store = {
    source: {
        token: null,
        cancel: null
  }
};

30. 如何判断字体是否加载成功?

import FontFaceObserver from 'fontfaceobserver';

/**
 * 判断系统是否安装好某字体
 * @param {*} f 字体对应的font-family属性代码
 */
export const isSupportFontFamily = async (fontFamily: string) => {
  const font = new FontFaceObserver(fontFamily, { weight: 400 });
  return await font.load();
};

调用方法

    isSupportFontFamily('source-han-sans-simplified-c').then(
      () => {
        console.log('思源黑体加载正常');
      },
      () => {
        Toast({
          message: '无法匹配到指定字体,图片生成失败,请刷新页面后再次尝试',
        });
        throw new Error('无法匹配到指定字体,图片生成失败,请刷新页面后再次尝试');
      }
    );

29.企业微信中vConsole下,为什么会不断发 aegis.qq.com/collect请求

aegis.qq.com/collect 是腾讯云出品的一个前端性能监控工具上报的默认域名。在Android手机,企业微信和小程序中,打开开发者模式,aegis会自动监控前端错误,在错误发生时上报错误的具体情况,

image.png

28.dom事件中的passive是什么意思?

passive是被动事件监听器,被动事件监听器是针对移动端滚动体验的优化,默认值是false

   dom.addEventListener(
      'mousemove',
      (e: Event) => {
        console.log(e);
        if (e.cancelable) {
          e.preventDefault();
        }
      },
      { passive: false }
    );

开启和不开启的区别是: 开启之后,浏览器的滚动不会受到touchstart和touchmove事件中是否调用了preventDefault要进行判断的阻塞。

image.png

不开启的话,浏览器就要先判断touchstart和touchmove事件是否调用了preventDefault,然后才开始滚动。

image.png

27.VSCode 如何把默认的终端设置成GitBash?

VSCode默认的终端不显示git分支名称, 如果需要经常切换git分支,就不方便。所以需要将VSCode默认打开的终端配置成GitBash。配置方法如下:

  1. CTRL+Shift+P 打开设置窗口,选择用户配置
  2. 将如下内容添加到C:\Users\用户名\AppData\Roaming\Code\User\setting.json文件中。
    "terminal.integrated.profiles.windows": {
        // 命名中不能有空格
        "GitBash": {
          "path": "C:/Program Files/Git/bin/bash.exe",
          "args": [],
          "icon": "terminal-bash"
        },
        "PowerShell": {
          "source": "PowerShell",
          "icon": "terminal-powershell"
        },
        "Command Prompt": {
          "path": ["${env:windir}\\Sysnative\\cmd.exe", "${env:windir}\\System32\\cmd.exe"],
          "args": [],
          "icon": "terminal-cmd"
        }
      },
    "terminal.integrated.defaultProfile.windows": "GitBash",

26. 企业微信,如何拉新员工进群以及设置管理员?

点击通讯录Tab,然后点击添加成员,如果点击右上角的+号按钮,那就走偏了。

image.png

在我的企业--权限管理--管理组旁边有个+号,点击此+号,可以将某个成员设置为管理员。

image.png

25. Android Webview 版本太高,导致真机调试功能无法使用,如何处理?

image.png image.png 解决方案:

  1. 下载安装PC端QQ浏览器
  2. 在QQ地址栏输入 qqbrowser://inspect/#devices
  3. 点击inspect fallback, 就会看到浏览器调试窗口。

image.png

24. Nginx中Content-type被意外修改,导致tinymce富文本编辑器无法使用,如何解决?

使用好好的tinymce富文本编辑器,突然加载不出来, 通过排查,发现是跟富文本编辑器相关的三个资源文件,加载不正常,导致富文本编辑器显示不出来,经过多方协同排查,最后发现是Nginx上的content-type被修改导致的。

image.png image.png

Nginx一般根据conf/mime.types文件中配置的文件扩展名(文件扩展名对大小写不敏感)指定响应头中的content-type字段,默认的content-type类型是application/octet-stream。 当浏览器在请求资源时,会通过http/https返回头中的content-type决定如何显示/处理将要加载的数据,如果这个类型浏览器能够支持阅览,浏览器就会直接展示该资源,比如png、jpeg、video等格式。application/octet-stream是应用程序文件的默认值。意思是未知的应用程序文件, 浏览器并不认得这是什么类型,也不知道应该如何展示,只知道这是一种二进制文件,因此遇到content-type为application/octet-stream的文件时,浏览器会直接把它下载下来。如果下面的include mime.types; 被注释掉的话,就会造成浏览器对文件类型解析错误。

...
http {
    include       mime.types;
    default_type  application/octet-stream;
    ...
}

conf/mime.types文件内容

types {
    text/html                                        html htm shtml;
    text/css                                         css;
    text/xml                                         xml;
    image/gif                                        gif;
    image/jpeg                                       jpeg jpg;
    application/javascript                           js;
    application/atom+xml                             atom;
    application/rss+xml                              rss;

    text/mathml                                      mml;
    text/plain                                       txt;
    text/vnd.sun.j2me.app-descriptor                 jad;
    text/vnd.wap.wml                                 wml;
    text/x-component                                 htc;

    image/png                                        png;
    image/svg+xml                                    svg svgz;
    image/tiff                                       tif tiff;
    image/vnd.wap.wbmp                               wbmp;
    image/webp                                       webp;
    image/x-icon                                     ico;
    image/x-jng                                      jng;
    image/x-ms-bmp                                   bmp;

    font/woff                                        woff;
    font/woff2                                       woff2;

    application/java-archive                         jar war ear;
    application/json                                 json;
    application/mac-binhex40                         hqx;
    application/msword                               doc;
    application/pdf                                  pdf;
    application/postscript                           ps eps ai;
    application/rtf                                  rtf;
    application/vnd.apple.mpegurl                    m3u8;
    application/vnd.google-earth.kml+xml             kml;
    application/vnd.google-earth.kmz                 kmz;
    application/vnd.ms-excel                         xls;
    application/vnd.ms-fontobject                    eot;
    application/vnd.ms-powerpoint                    ppt;
    application/vnd.oasis.opendocument.graphics      odg;
    application/vnd.oasis.opendocument.presentation  odp;
    application/vnd.oasis.opendocument.spreadsheet   ods;
    application/vnd.oasis.opendocument.text          odt;
    application/vnd.openxmlformats-officedocument.presentationml.presentation
                                                     pptx;
    application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
                                                     xlsx;
    application/vnd.openxmlformats-officedocument.wordprocessingml.document
                                                     docx;
    application/vnd.wap.wmlc                         wmlc;
    application/x-7z-compressed                      7z;
    application/x-cocoa                              cco;
    application/x-java-archive-diff                  jardiff;
    application/x-java-jnlp-file                     jnlp;
    application/x-makeself                           run;
    application/x-perl                               pl pm;
    application/x-pilot                              prc pdb;
    application/x-rar-compressed                     rar;
    application/x-redhat-package-manager             rpm;
    application/x-sea                                sea;
    application/x-shockwave-flash                    swf;
    application/x-stuffit                            sit;
    application/x-tcl                                tcl tk;
    application/x-x509-ca-cert                       der pem crt;
    application/x-xpinstall                          xpi;
    application/xhtml+xml                            xhtml;
    application/xspf+xml                             xspf;
    application/zip                                  zip;

    application/octet-stream                         bin exe dll;
    application/octet-stream                         deb;
    application/octet-stream                         dmg;
    application/octet-stream                         iso img;
    application/octet-stream                         msi msp msm;

    audio/midi                                       mid midi kar;
    audio/mpeg                                       mp3;
    audio/ogg                                        ogg;
    audio/x-m4a                                      m4a;
    audio/x-realaudio                                ra;

    video/3gpp                                       3gpp 3gp;
    video/mp2t                                       ts;
    video/mp4                                        mp4;
    video/mpeg                                       mpeg mpg;
    video/quicktime                                  mov;
    video/webm                                       webm;
    video/x-flv                                      flv;
    video/x-m4v                                      m4v;
    video/x-mng                                      mng;
    video/x-ms-asf                                   asx asf;
    video/x-ms-wmv                                   wmv;
    video/x-msvideo                                  avi;
}

如果我们不想使用conf/mime.types文件配置的默认规则,需要指定css文件的conntent-type字段加上指定编码参数,比如说加上charset:utf-8,该如何配置呢? 解决方法如下:

# 配置特定的文件扩展名
location ~ .*\.css$ {
     # 取消默认的types配置
     types { } 
     # 重新指定content-type返回类型
     default_type 'text/css; charset:utf-8';
}

23. Indicate whether to send a cookie in a cross-site request by specifying its SameSite attribute 是什么原因引起的,该如何解决?

这句话翻译成中文的意思是: 通过设置SameSite 属性指示是否在跨站时发送 cookie。举例说明一下,就是A站点页面引入了B站点页面, B站点页面向A站点发请求时, Chrome发现A,B站点不同源。就不会把A站点的cookie携带到A站点。Google 在2020年2月4号发布的 Chrome 80 版本中默认屏蔽所有第三方 Cookie,默认为所有 Cookie 加上 SameSite=Lax 属性,并且将Cookie设为 SameSite=None(允许跨域传送cookie时)时,必须加上secure属性(就是强制要求网站必须采用https协议), SameSite的作用是防止跨域传送cookie,从而从源头上防止 CSRF 攻击和用户追踪。想详细了解cookie的SameSite属性,可以看看这篇文章

SameSite=Lax的规则

请求类型示例正常情况Lax
链接<a href="..."></a>发送 Cookie发送 Cookie
预加载<link rel="prerender" href="..."/>发送 Cookie发送 Cookie
GET 表单<form method="GET" action="...">发送 Cookie发送 Cookie
POST 表单<form method="POST" action="...">发送 Cookie不发送
iframe<iframe src="..."></iframe>发送 Cookie不发送
AJAX$.get("...")发送 Cookie不发送
Image<img src="...">发送 Cookie不发送

可是有时候(比如说统一局域网内),又需要B站点向A站点发请求时,携带A站点的cookie到A站点,做身份认证,那么此时该如何解决呢。解决方案是: 修改A页面站点Nginx配置文件,添加SameSite=None; Secure响应头。这样在B站点下向A站点发请求,浏览器就会携带A站点的cookie到A站点。

server {
        listen                  80;
        server_name             xxx.xxx.com;
        charset                 utf-8;
        # 重点是这一句
        add_header Set-Cookie   'SameSite=None; Secure';
        index index.html;
        root  '网站根目录';
}

22. 查看WiFi密码的指令

通过查看无线网络属性--安全选项卡的方式,只能查看当前连接WiFi的密码,用cmd命令,可以查看电脑连接过的所有WiFi密码。

# 查看所有连接过的WiFi
netsh wlan show profiles
# 查看某个WiFi的密码
netsh wlan show profiles WiFi名称 key=clear

上述命令的含义是:

  • netsh 网络命令
  • wlan 无线网
  • show 展示
  • profiles 信息
  • key=clear 明文显示,清除加密key

21. Chrome浏览器,误点了总是打开此类文件,如何重置?

使用Chrome自带的截图功能,截图完成后,想去下载路径文件夹看看,截图内容。一不留神,点击了总是打开此类文件选项,后续每次截图,浏览器都会弹出截图内容,很是恼人,却不知道怎么关闭。后面下载别的文件模板,又看到了这个选项,进行了精准的搜索后,才找到了关闭的方法。

image.png

在浏览器地址栏输入chrome://settings/downloads, 点击下载特定类型文件后自动将其打开右边的清除按钮,即可关闭这个烦人的弹窗。

image.png

20. 误删除电脑环境变量--系统变量--Path变量怎么办?

更改环境变量时应该谨慎行事,因为错误的更改可能会导致系统问题,如果误删,应该如何恢复呢?

image.png

快速恢复方式:

  1. 按住Win+R键,在运行栏输入cmd打开命令窗口
  2. 在命令窗口输入echo %Path%指令,就能查询出默认的环境变量值

image.png

  1. 重新设置Path环境变量,重启命令窗口生效。

19. 微信分享, 分享出去的文章,分享卡片图标不展示,是什么原因?

调用微信分享的JS-SDK分享API,分享出去的文章,标题和文章描述显示正常,图标显示不正常。 可能的原因有:

  1. 标题中含有敏感词;
  2. 图片的大小不能大于32K;
  3. 图片尺寸不能小于200*200;
  4. 部分手机不支持png格式的图片,建议换成jpg格式;
  5. 分享那一刻,网络不太好。这一条只适合偶尔出现图标显示不出来的情况。

其实大多数情况下,分享图标不显示,都是分享配置参数不对,微信JS-SDK也会在控制台报错提示。

wx.ready(function () {      
  wx.updateTimelineShareData({ 
    title: '', // 分享标题
    link: '', // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
    imgUrl: '', // 分享图标
    success: function () {
      // 设置成功
    }
  })
});

18. CSS 给div设置了box-sizing:border-box和固定高度的情况下, 如何动态改变div高度?

需求是这样的, 要让保存按钮固定在页面底部,保存按钮与页面背景色不一致,有黑色底部工具条的时候,要添加安全底部距离,没有的时候不用加。分析一下这个需求,首先肯定要使用fixed定位, fixed定位要求必须设置高度,为了布局方便,我们一般都使用的是border-box盒子模型,而出现安全底部高度时,这个变化的高度背景色与保存按钮背景色一致才美观,要做到这一点,必须给保存区块div加一个padding-bottom:env(safe-area-inset-bottom), 此时border-box+固定高度+padding-bottom三者就冲突了,在border-box+固定高度的制约下,padding-bottom:env(safe-area-inset-bottom)无法实现,化解这个矛盾的关键是用min-height属性替代height属性,另外也要给页面加一个安全底部边距,就能实现需求要求的效果。

image.png

17. 在PC端,如何滚动截屏?

  1. 打开谷歌浏览器开发者工具 按F12或Ctrl+Shift+I
  2. 按下Ctrl+Shift+P组合快捷键
  3. 输入screen,选择截取完整尺寸的屏幕截图,过一会儿截图就会下载下来。

image.png

各种截图方式的功能说明见下表:

截图方式功能说明
当前节点屏幕截图生成选中dom节点的截取
截取区域屏幕截图会出现一个十字箭头,自己选择区域,生成所选区域的截图
截取完整尺寸的屏幕截图滚动截图,截取页面所有内容
截取屏幕截图生成当前屏幕展示内容截图

后记:发现Chrome自带的截取完整尺寸的屏幕截图功能有瑕疵,某一区域出现滚动条,而整个页面未出现滚动条时,截取内容不全。 后面找到了一个Chrome截图插件GoFullPage, 可以滚动截取屏幕所有内容,才是自己期望的功能。

16. 如何用TS泛型,约束接口请求参数和响应数据类型?

每个接口的请求参数和返回数据是不相同的,那么应该如何约束动态的接口请求入参和返回数据类型呢。你第一直觉肯定想到了TS的泛型,你的直觉是对的。那么具体要怎么做,请看下面的示例:

    // 这是返回数据的内容结构,变化的是retdata部分
    export interface ApiResult<T> {
      ret: number;
      retmsg?: string;
      retdata?: T;
      traceId?: string;
      [key: string]: any;
    }


// 通用写法
export const getDemoInfo = async <T,U>(params: T | any): Promise<ApiResult<U>> =>
  await axios.get(`/xxx/config/xxx`, { params });

// 赋予类型定义
export const getDemoInfo = async (params: {paramsA:string}): Promise<ApiResult<{retdataA:string}>> =>
  await axios.get(`/xxx/config/xxx`, { params });

15. Failed to load module script: The server responded with a non-JavaScript MIME type of "text/plain"Strict MIME type checking is enforced for module scripts per HTML spec. 错误是什么含义?

这个错误说的意思是,本来浏览器要加载一个js文件,结果却返回一个text/plain类型的文件。造成这种报错的原因一般是网站配置了如下的路径匹配转发规则。

location ~ ^/path-prefix {
    add_header Cache-Control no-store;
    add_header Content-Encoding gzip;
    try_files $uri $uri/ /网站部署根目录/index.html;
 }

而加载资源的路径,因为不是绝对路径,浏览器自动补充的路径是location.origin+/path-prefix,所以触发了上面的nginx转发配置, 指向了index.html文件,返回了类型为text/plain类型的index.html文件内容,而非真正想加载类型为script的js文件内容。消除这个错误的方法就是将静态资源的路径改成绝对路径。

image.png

14. <a target="_blank" rel="noreferrer noopener" />中的noreferrer noopener 是什么含义?

  • 先说说noreferrer的用途

当发起一个HTTP请求时,它会附带Referrer请求头来标识请求来源。当点击A页面跳转B页面链接时,请求B页面的请求头Referrer中会附带A页面的URL信息。

如果B页面是外部文档,那就可能存在安全隐患,比如说B网站根据A网站请求来源返回A网站高仿钓鱼页面,窃取用户信息。

因此跳转外部链接,要设置rel=noreferrer来避免源网站Referrer信息泄露。

  • 再说说noopener的用途

通过 <a target="_blank" />跳转新页面,新页面可以通过window.opener 访问源页面的窗口对象,并且可以使用 window.opener.location = newURL改变源网页的内容。这给源页面带来了安全隐患。设置noopener属性之后,新页面就获取不到window.opener对象了。

  • 还有个nofollow属性,顺带也介绍一下

使用了此属性是想告诉搜索引擎不要把访问这个链接的次数计算到源网站的PR值中去。

PR值的全称为“PageRank”,意思是网页级别,也叫网页权重值。pr值,是google搜索的一个发明。在谷歌排名算法中pr值越高,关键词排名越好。网站友情链接质量是计算pr值的重要标准,交换友情链接站点的权重越高,对自己网站pr值提升越快。。

13. VSCode.ESLint 和VSCode.Preitter扩展 与 npm 的eslint和prettier安装包是什么关系,eslint和prettier为什么会冲突?

与其说是VSCode.ESLint 和VSCode.Preitter扩展 与 npm 的eslint和prettier安装包的关系,不如说VSCode扩展和npm同名包是什么关系。它们的关系是各自都能独立运行,执行相应的功能。但如果VSCode扩展和npm同名包都配置了规则,VSCode扩展会优先读取npm包的配置规则。一般我们的项目一定会安装相应的npm包,但可能不会安装VSCode相应的扩展,我的建议是两者同时安装,VSCode扩展会实时给开发提示和纠正问题,而npm包在CI流水线上,再做一次把关,毕竟不是每个开发者,都对代码质量有较高的追求。

eslint和prettier为什么会冲突, 因为它们在代码格式化这一块是重叠的。eslint除了检查代码质量,也会对js文件进行格式化,而eslint对文件进行格式化这个功能,说实话是有点鸡肋的。想做又没做好。只能格式化js文件,不能格式vue,html,css,json等,且格式化风格还与prettier冲突,eslint默认是双引号,加分号。而prettier默认是单引号,不加分号。于是就会出现保存代码的时候eslint先格式化化一遍,prettier随后又格式化一遍,代码不停颤抖,这就不是给开发者助力而是添堵了。eslint和prettier重合的规则有很多,如果需要每个都配置一遍的话,就会很繁琐,好在eslint出了一个eslint-plugin-prettier插件,是把prettier当作eslint的一个插件,规则重合的部分按照prettier的规则来。

12. VSCode StyleLint扩展报如下错误,如何解决?

TypeError: this.getPosition is not a function  
at LessParser.inlineComment (/web/node_modules/postcss-less/lib/LessParser.js:71:28)  
at LessParser.isInlineComment (/web/node_modules/postcss-less/lib/nodes/inline-comment.js:37:12)  
at LessParser.other (/web/node_modules/postcss-less/lib/LessParser.js:156:36)  
at LessParser.parse (/web/node_modules/postcss/lib/parser.js:75:16)  
at parse (/web/node_modules/postcss-less/lib/index.js:11:12)  
at new LazyResult (/web/node_modules/stylelint/node_modules/postcss/lib/lazy-result.js:133:16)  
at getPostcssResult (/web/node_modules/stylelint/lib/getPostcssResult.js:77:30)  
at async lintSource (/web/node_modules/stylelint/lib/lintSource.js:76:4)  
at async /web/node_modules/stylelint/lib/standalone.js:218:27  
at async Promise.all (index 0)

看这个报错,是postcss-less/lib/LessParser.js文件出现报错。而postcss-less是第三方比较成熟的npm包,出现这个问题一般肯定是postcss-less和stylelint包不兼容。VSCode-Stylelint扩展现在只支持v14+以上的stylelint版本。

我们的项目中使用的stylelint版本是14.8.5, 并不是stylelint的最高版本
又查了一下postcss-less的所有版本,发现安装的是现阶段最高的版本。
# 查看某个包的版本
npm view postcss-less versions

那么明显是postcss-less版本太高,将postcss-less降了一个版本试了一下,发现报错提示消失了,果然与猜测的一样,是postcss-less与stylelint包版本不兼容引起的。

yarn remove postcss-less && yarn add -D postcss-less@5.0.0

还有一点要注意,如果vscode加载了多个项目,要将每个项目中的postcss-less包都要进行降级, 否则这个错误提示会反复发作。另外还有个大坑,如果有的项目下的.vscode/settings.json配置了stylelint功能,而这个项目未安装与stylelint相关的npm包,也会报上面的错误。要在setting.json文件中移除stylelint的相关设置才行。

image.png

11.裁剪直角梯形如何实现?

如下图所示,要将一个图片裁剪成直角梯形,刚开始的思路是用三角形遮盖,发现要画一个瘦高的直角三角形,远没有直接将图片裁剪成梯形来得容易。所以最后采用css的clip-path属性,实现了这个效果。

下面的图是裁剪原理, X轴的取值是0-100%/0-313px(用绝对像素表示也可以),Y轴的取值是0-100%/0-394px, 不会出现负值。第一点的坐标设定为是0 0, 第二个点的坐标设定为0 100%, 第三个点的坐标设定为 80% 100%,第四个点的坐标设定为0 100%,然后连点成线就可以了。 完整代码请点这里

另外,这个卡片还有一个阴影效果。在实现图片裁剪和阴影效果的过程中,我发现两个特别好用的在线工具,在此分享一下。

10. npm ERR! ERESOLVE unable to resolve dependency tree 错误原因及解决方案?

CI构建一直很丝滑如顺, 直到某一天,shell命令窗口输出如下错误信息:

npm ERR! ERESOLVE unable to resolve dependency tree

解释这个错误之前,得先引入一个概念peerDependency,在 package.json 中,有一个字段叫对等依赖 peerDependencies,这个字段的含义用大白话说,就是根目录和根目录中的子依赖同时声明依赖某个包,把这个包仅安装到根目录下,子依赖引用这个包时,从根目录下的node_moudules中找。 举个例子说明一下这个字段的用途。假设有一个demo项目下的package.json文件中的dependencies字段里声明了packA作为依赖,而其下面有两个依赖包dep1和dep2,它们也依赖packA。如果我们在dep1和dep2的package.json用dependencies而不是peerDepenedencies来声明,那么npm install安装完项目依赖包之后的文件结构如下图所示:可以看出packA总共被安装了3次,多安装了2次。

demo
│  package.json
│  
└─node_modules
    ├─packA
    ├─dep1
    │  │  package.json
    │  │  
    │  └─node_modules
    │      └─packA
    │      └─...
    └─dep2
        │  package.json
        │  
        └─node_modules
            └─packA
            └─...

如果在依赖包dep1和dep2的package.json文件里的peerDependencies字段声明一下核心依赖库packA,然后在根目录的package.json文件里的dependencies字段也声明一下packA,执行npm install,生成的依赖结构就会如下图所示:packA不会被重复安装。

demo
│  package.json
│  
└─node_modules
    ├─packA
    ├─dep1
    │  │  package.json
    │  │  
    │  └─node_modules
    │      └─...
    └─dep2
        │  package.json
        │  
        └─node_modules
            └─...

从npm v7 开始,install默认以peerDependencies的方式下载依赖包。如果在根目录的package.json中显式声明了依赖包,那么各个子项目里的 peerDepenedencies 声明就会被忽略。 如果未在根目录的package.json中显式依赖包,就会按照子项目的peerDepenedencies中声明的版本将依赖安装到根目录中的node_modules文件夹下。如果各个子项目依赖包的版本不兼容,那么就会报错,无法解析依赖树。导致安装过程中断。因为是从 npm v7 引入的,因此 npm v3~v6 不会发生这个错误。解决方法有三种:

# 推荐方法一
使用cnpm或者yarn
# 方法二 用npm v3~v6的方式安装
npm install --legacy-peer-deps
# 方法三 强制安装
npm install -f

9. 为什么分享出去的链接,修改页面功能重新部署之后,不刷新页面的情况下,更新不生效?

原因是服务器对分享出去的链接网站的index.html做了缓存,在缓存未失效的情况下,不会去加载最新的index.html,尽管index.html中引入资源文件路径的hash值发生了改变,可浏览器压根就没有执行最新的index.html。所以修改只对新分享的链接生效,已经分享出去的链接,只能通过刷新,才能看到最新的改动。要想从根源上解决这个问题,需要禁止服务器缓存index.html文件。

location / {
    # 重点是这句 禁止缓存 html
    add_header Cache-Control "no-store";
    
    root   "站点index.html所在文件夹";
    index  index.html index.htm;
    try_files $uri $uri/ /index.html;
}

8. 使用的一个上传下载文件脚本,有时从远程机器能正常下载文件,有时不能,原因何在?

背景是这样的:给银行做项目,需要借助行方提供的一个上传下载脚本,把内网项目同步到外网排查问题,发现上传下载脚本,下载文件时而正常,时而抽风。心里一直很疑惑。某天突然看到桌子上的入厂协议。瞬间想通了原因,银行对数据安全性要求较高,晚上不允许员工加班到很晚,担心员工呆在公司,把一些敏感数据窃取出去。所以下载工具的使用时段,可能也与这一点密切相关。随后测试了一下,果然如此,上班时间,下载远程电脑的项目代码就没问题,下班之后,下载就会报错。知道这个规律之后,用起来多了一份顺畅,少了一份磕绊,开心。

7. 部分有底部黑条的Android手机,将constant(safe-area-inset-bottom)env(safe-area-inset-bottom)解析为0,如何设置安全底部?

从 iPhone X 开始出现了刘海和底部黑条区域,Android系统也有样学样,造成现在越来越多地新机型需要添加安全区域。IOS设置安全底部的方式是:

<meta name="viewport" content="width=device-width, viewport-fit=cover" />
body {
  padding-bottom: constant(safe-area-inset-bottom); /* 兼容 iOS < 11.2 */
  padding-bottom: env(safe-area-inset-bottom); /* 兼容 iOS >= 11.2 */
}

实践发现,早期不需要安全底部的Android手机, 设置了安全底部属性之后,会将其解析为0。大多需要安全底部的Android手机也会按照iOS的标准来实现安全区域,但有极个别有底部黑色条的Android手机,通过Chrome开发工具查看样式,虽然识别了safe-area-inset-top预定义变量,却将其解析为0。造成底部内容被黑条遮挡,而W3C官方未提供判断手机是否有底部黑条的方法。所以当浏览器将safe-area-inset-top解析为0后,开发者不知道是否需要添加安全底部。最后思考一番之后,觉得无论是苹果手机,还是安卓手机,任何时候都可以加上安全底部。把那些需要底部安全距离却将底部安全距离解析为0的Android机型用navigator.userAgent找出来,手动加一个和safe-area-inset-bottom值相同的边距即可。建议不要在每个页面单独设置,在body或页面容器上统一设置,这样管理起来更方便。

image.png

6. Google自带的翻译功能无法使用,如何解决?

查看Stack Overflow上面的问题解答,有些回答篇幅较长,且包含许多生僻的单词,这时候就需要翻译工具。然而Chrome自带的翻译功能用不了,虽然可以用别的翻译工具替代,但还是有些不习惯。网上查找了一下,发现了一个可用的地址,在此分享给大家。

image.png

先在cmd窗口下, 执行ping 172.217.212.90, 如果可以ping通,则说明下面的配置还可用。接着修改hosts文件:

172.217.212.90 translate.googleapis.com
172.217.212.90 translate.google.com

再执行 ipconfig /flushdns 刷新dns。注意这个IP不是永久IP,若失效可在下面的网址留言,让作者更新。

5. Mixed Content: The page at 'xxx' was loaded over HTTPS, but requested an insecure image 'xxx'. This content should also be served over HTTPS.怎么修复?

HTTP协议是超文本传输协议(HyperText Transfer Protocol)的缩写,HTTPS全称是Hypertext Transfer Protocol Secure , 从名称可以看出,HTTPS是HTTP协议的安全版本,HTTP协议的数据传输是明文的,是不安全的,HTTPS使用了SSL/TLS协议进行了加密处理。HTTPS 页面上不允许出现 http 请求,一旦出现就提示上述错误。W3C 工作组也考虑到了从HTTP升级到HTTPS困难,早在2015年4月份就出了一个 Upgrade Insecure Requests 的草案,它的作用就是如果页面采用的协议是https,而页面包含了大量的 http 资源(图片、音频,视频,文件,脚本,样式,iframe等),页面一旦发现存在上述响应头,会在加载 http 资源时自动替换成 https 请求。

所以处理方法有两种:

  • 第一种在服务器的请求头中添加如下设置:
header("Content-Security-Policy: upgrade-insecure-requests");
  • 第二种在客户端页面添加一个meta标签
<meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">

4. 打开企微调试模式后,刚进入页面就出现一个已在调试程序中暂停的覆盖层,如何关闭?

image.png

出现这个覆盖层是因为页面出现了错误,而这个错误实际上并不影响页面正常运行,可以忽略。若不关闭,页面就不会响应用户的操作。关闭调试状态的方式是: 点击工具栏的设置齿轮
image.png 在偏好设置里,勾选停用已暂停的状态叠加层

并取消触发断点后聚焦于来源面板选中状态。

3. PC端企微的调试模式,为什么有时能正常打开,有时无法打开。

PC端企微的调试模式,有时可以正常打开,有时不行,很邪乎。有时候着急用的时候却打不开,让人感到很捉急。经过试验,发现可以稳定打开的方式是:

  1. 关闭PC端企微,重新打开。
  2. 在导航处于消息面板高亮状态下,只在消息面板下有效,鼠标点击右侧空白区域。 image.png
  3. 按下Ctrl+Alt+Shift+D组合键,就可打开调试模式。

2. 为什么不对图片进行gzip压缩?

项目中页面加载比较慢,我在优化的时候,发现构建工具对css,js文件都做了gzip压缩,却未对图片做压缩。于是我添加了对图片进行gzip压缩的配置,结果发现, 对图片进行gzip压缩,没有任何效果。如下图所示: image.png

通常gzip对纯文本内容(如html,js,css)可压缩到原大小的40%。但对图片(如png、gif、jpg、jpeg)并不推荐使用gzip压缩(svg是个例外),首先经过压缩后的图片文件gzip能压缩的空间很小。事实上,添加标头,压缩字典,并校验响应体可能会让它的体积更大。gzip压缩主要适用于文本文件,由于文本文件通常包含大量的重复字符和空格,gzip压缩算法可以将文件中的重复字符和空格删除,并在文件头中记录这些删除的信息,以便在解压时重新还原这些字符和空格。图像文件、音频文件、视频文件文件,它们通常是连续的像素点,是二进制文件,不是文本格式结构,因此 gzip 压缩无法有效地压缩它们。

延伸拓展文本文件和二进制文件的区别:

概括起来就是能用记事本打开的就是文本文件,否则就是二进制文件。

  • 处理方式不同

文本文件可以直接读取和修改,一般不需要进行特殊处理,而二进制文件则需要通过文件系统或编程语言来进行读取和修改。

  • 存储数据类型不同

文本文件是基于字符编码的文件,常见的编码有ASCII编码,UNICODE编码等。 二进制文件是基于值编码的文件文本文件只能存储char型字符变量。二进制文件可以存储char/int/short/long/float/……各种变量值。

  • 每条数据长度不同

文本文件每条数据通常是固定长度的。以ASCII为例,每条数据(每个字符)都是1个字节。进制文件每条数据不固定。如short占两个字节,int占四个字节,float占8个字节……

  • 文件扩展名不同

文本文件的扩展名一般是txt,csv,js,css,html,xml,yaml,json等, 二进制文件的扩展名一般是各种图片、音频、视频的扩展名, 还有其它文件类型如pdf,exe,doc,docx,xls,xlsx,rtf等

1. Android手机Chrome Inspect调试功能在企微有些企业可用,在有些企业无法使用的原因是?

  • 这是不可用的截图
  • 这是可用状态截图

最后查明可能的原因有两点:

  1. 从Android 4.4开始,打开Android WebView的调试开关, 就能在PC端使用 chrome://inspect/#devices 远程调试原生 Android 应用中WebView H5网页。可能是Android WebView这个开关没打开。
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
    WebView.setWebContentsDebuggingEnabled(true);
}

2. 如果WebView代码中使用了代码混淆,需要禁用混淆才能使Inspect工具正常工作。

本文正在参加「金石计划」