17. 三个代码优化点
- window对象,书写的时候可以省掉window.索引
正常:
const shareChannels = getQueryString(window.location.search, 'shareChannels');
优化:
const shareChannels = getQueryString(location.search, 'shareChannels');
- 只会在一个地方使用的常量,不必提取到公共常量文件
反例: 把只会在一个地方使用的常量,提取到src/common/constants.ts中,这段代码,放到使用的业务文件里面就行了,阅读与查找起来更方便
export const taskContentMap: TLooseStrObj = {
'090101':
'首次“一对一专属理财经理”自我介绍;告知客户服务升级(贵宾客户专属产品及服务权益体系升级亮点);邀请添加客户企业微信;邀约与客户首次面访时间',
'090102': '新增邀约',
// ...
};
- 可以优化的if判断语句
正常:
const launchBtn = document.getElementById('launch-btn');
if(launchBtn){
launchBtn.removeEventListener('launch', handleLaunch);
}
优化:
const launchBtn = document.getElementById('launch-btn');
launchBtn?.removeEventListener('launch', handleLaunch);
16. IOS13的一个兼容性问题
IOS13手机操作系统,如果H5应用的域名使用的是https协议, 在网站中,以Ajax的方式,请求一张同域名但协议却是http图片文件数据,是获取不到图片的二进制数据的,需要修改成https协议才可以,而在Android上没有这个问题,而且不是所有的IOS系统都是如此,高版本的也没有这个问题。
15. 一个中文占几个字节?
ASCII 字符集总共规定了128种字符规范,但是并没有涵盖西文字母之外的字符,当需要计算机显示存储中文的时候,就需要一种对中文进行编码的字符集,国家标准委员会对中文制定了3种编码规则 GB2312,GBK和GB-18030。GB2312只涵盖了6000 多个汉字,还有很多没有包含在其中,所以出现了GBK和GB-18030,GBK是双字节编码,每个字符用两个字节表示。GB18030是多字节字符集,它的字符可以用一个、两个或四个字节表示。码位空间由各字节的范围确定。Unicode 在一个字符集中包含了世界上所有文字和符号,统一编码,来终结不同编码产生乱码的问题。Unicode 是一个符号集, 它只规定了每个符号的二进制值,但是符号具体如何存储它并没有规定,前面提到, Unicode 字符集的编码范围是 0x0000 - 0x10FFFF,因此需要 1 到 3 个字节来表示。
- ASCII 码中,一个英文字母(不分大小写)为一个字节,ASCII码只能表示英文字母、数字、标点符号等基本字符。
- UTF-8 编码中,采用变长存储文字和符号。 少数是汉字每个占用3个字节,多数占用4个字节。UTF-8 的编码规则如下(U+ 后面的数字代表 Unicode 字符代码):
U+ 0000 ~ U+ 007F: 0XXXXXXX
U+ 0080 ~ U+ 07FF: 110XXXXX 10XXXXXX
U+ 0800 ~ U+ FFFF: 1110XXXX 10XXXXXX 10XXXXXX
U+10000 ~ U+1FFFF: 11110XXX 10XXXXXX 10XXXXXX 10XXXXXX
- UTF-16 编码中,通常汉字占2个字节,CJKV扩展B区、扩展C区、扩展D区中的汉字占4个字节(一般字符的Unicode范围是U+0000至U+FFFF),而这些扩展部分的范围大于U+20000,因而要用两个UTF-16)
- UTF-32 编码中,世界上任何字符的存储都需要 4 个字节。
- Unicode 编码中,一个英文为一个字节,一个中文为两个字节。
- 符号:英文标点为一个字节,中文标点为两个字节。例如:英文句号 . 占1个字节的大小,中文句号 。占2个字节的大小。
14. pre和p标签的区别
pre默认支持\n
转义换行符,但内容超出不能自动换行,需要添加如下的设置,才能换行。p标签默认自动换行,可是对\n
不识别,所以要处理富文本的内容展示,还得用pre标签
pre {
white-space: pre-wrap;
word-wrap: break-word;
}
13. 发现postcss-plugin-px2rem
插件一个bug
如下一段代码,经过postcss-plugin-px2rem
插件转换后,上下两部分的字体大小既然一样,是不是很诡异。
.cardWrap {
.infoWrap {
// ...
.left {
.infoValue {
// ...
font-size: 18px;
}
}
.common {
// ...
.commonItem {
// ...
.infoValue {
font-size: 14px;
}
}
}
}
而本地调试的时候,发现没问题。看了一下package.json中postcss-plugin-px2rem
版本的写法,瞬间明白了。Dev-Ops CI工具构建工具,每次构建时,会重新安装postcss-plugin-px2rem
,如下的这种写法,即便是存在yarn.lock文件,也会对postcss-plugin-px2rem
进行升级,而postcss-plugin-px2rem
最新的版本肯定有问题,本地安装一次之后,就不会再安装了。所以本地工作正常。
{
"postcss-plugin-px2rem": "^0.8.1",
}
12. 今天发现coding代码平台的一个大坑,在线解决冲突的话,会把公共分支的内容,合并到自己的特性分支
比如说你要把自己的特性分支feature/20231116-功能说明-姓名拼写合并到release/20231116, 合并代码的时候出现了冲突,你在coding网站在线解决冲突而非本地命令行,会把release/20231116的功能同步到自己的特性分支feature/20231116-功能说明-姓名拼写,造成潜在的发版隐患。
11. 分享一个便捷生成各种尺寸测试图片的网站
点击这里跳转到dummyimage.com,这个网站支持生成各种尺寸的测试图片,图片的格式支持jpg|gif|png, 支持自定义图片的背景色,文字颜色,图片上的文字,是个很好的测试工具、
10. 判断语句,需要优化的一个点。可以一次性判断的结果,就无需每次都去判断。
instance.interceptors.response.use(
function (response) {
const { headers, status, statusText, data, config } = response;
if (status === 200) {
// 不好的写法
if (location.href.includes('needEncrypt')) {
// ...
}
}
}
);
// 好的做法
const isNeedEncrypt=location.href.includes('needEncrypt');
instance.interceptors.response.use(
function (response) {
const { headers, status, statusText, data, config } = response;
if (status === 200) {
if (isNeedEncrypt) {
// ...
}
}
}
);
9. 使用浏览器浏览网页时,为什么不建议同时打开很多标签页?
如下图所示,每打开一个网页,都会占用一定的内存,而操作系统分配给浏览器的内存不是无限制的,所以不要打开过多的浏览器标签页,因为那样会造成浏览器运行缓慢或崩溃。
8. 在电脑端emoji表情展示正常,在手机端有些emoji表情展示不出来,如下图所示,是什么原因?
emoji 也是Unicode字符。2010年,Unicode 开始为 Emoji 分配码点。比如:U+1F4C5,U+1F468, U+1F600等。 Unicode 只是规定了 Emoji 的码点和含义,并没有规定它的样式。举例来说,码点U+1F600表示一张微笑的脸,但是这张微笑的脸表情长什么样,则由各个系统自己实现。如果用户的系统没有实现这个Emoji符号,用户就会看到一个没有内容的方框,因为系统无法渲染这个码点。所以在PC端展示正常的emoji表情,在Android或IOS系统上,可能展示不太正常,解决方案是:
- 下载响应操作系统的emoji字体,然后用css自定义一个字体类型,进行加载显示
- 用图片代替emoji表情
- 升级手机操作系统
7. 手机和电脑连接同一个WiFi,手机无法访问电脑上的IP地址网页,该如何解决?
如果你的系统没有windows防火墙功能,而许多网上的文章都说要开启防火墙功能,沿着这条思路走,就是一条死胡同。正确的解决方法是,让电脑共享出一个移动WiFi热点,用手机去连接电脑上的这个WiFi热点,然后启动电脑端的单页应用项目时,会显示本机的IP地址,在手机上用这个地址去访问电脑上的网页,你会发现,是可以访问的。
6. 在vue3 hook中使用vue-router需要注意一个细节,给route赋值的时候,有可能router还没初始化,造成运行时报错。
import { useDefaultLink } from '@shared/hooks';
import { useGlobalStore } from '@shared/store';
import { useRoute } from 'vue-router';
const route = useRoute();
export const useToArticleDetail = () => {
const { toPath } = useDefaultLink();
const globalStore = useGlobalStore();
const _query = {
objId: newsId,
// 会报错TypeError: Cannot read properties of undefined (reading 'query')
unionId:route.query.unionId,
};
}
正确的解决思路是用别的工具,解析url上的查询参数
import { getQueryString } from '@shared/utils';
const unionId = getQueryString('unionId') || '';
5. 容易产生bug的一段代码
下面这段代码中的这一句operationType.value = retdata.operationType || '';
,在特定场景下,会产生缺陷。就是retdata.operationType等于0的时候,0是个有效值,但operationType.value
最终会把赋值为'',造成下一个接口提交数据报错。
let res;
if (isEdit.value) {
res = await videoApi.updateVideo(data);
} else {
res = await videoApi.createVideo(data);
}
const { ret, retdata = {} } = res;
const { auditOperation, commitBy = '' } = retdata;
operationType.value = retdata.operationType || '';
console.log({ operationType: operationType.value });
4. 后端接口返回的文本中有换行符,业务要求,换行要正常显示,正确的做法是?
刚开始试了一下v-html
, 发现没有任何效果, 正确的做法是使用pre
标签,但要注意一些细节问题,浏览器会对pre标签设置一些默认样式,要对默认的字体,行高进行重置,才是正常的效果。
3. 业务场景复杂的展示效果调试技巧
要产生某一些业务数据,操作流程和需要满足的业务条件很多,如果想看某种场景下的展示效果,直接写死一些假数据,调整页面布局。无需按照常规思维,按步骤操作,那样太浪费时间了。
2. 如果要测试一个交互场景问题,要填写许多表单项之后,才能触达这种交互场景,有没有省力省时的调试技巧?
这里分享一种思维,我遇到的具体问题肯定和大家不一样,就是对要测试的交互场景进行抽象,找出关键部分,用最少的资源条件,进行交互场景的模拟。完整的从头到尾填写许多表单数据之后,测试交互问题的常规思路不足取。
1. Antd Menu组件, 通过react-router跳转页面,管理后台左侧响应的菜单不高亮,如何修复?
解决思路:从当前页面url获取到路由路径,根据路由路径从左侧导航菜单列表中,找到Menu组件要设置打开的父级菜单和当前页面的id, 进行设置即可。setCurrent用于设置高亮的菜单项,setOpenKeys用于设置高亮的菜单项父级菜单处于展开状态。另外还发现,管理后台左侧的导航菜单与路由不是一一对应的,有些路由比如说编辑类页面路由,是无需设置高亮的。
import React, { useState, useEffect } from 'react';
import { Menu } from 'antd';
import { useLocation, Link } from 'react-router-dom';
const MenuList = () => {
const location = useLocation();
const [, rootPath] = location.pathname.split('/');
const [current, setCurrent] = useState(rootPath);
const [openKeys, setOpenKeys] = useState();
const { menu = [] } = useSelector((state) => state.base);
if(current !== rootPath) {
setCurrent(rootPath);
menu.some((item) => {
return item.resources.some((subItem) => {
if (subItem.resShortCode === rootPath) {
// 注意这里必须转换成字符串
setOpenKeys(`${item.resId}`);
}
return subItem.resShortCode === rootPath;
});
});
}
return(
<Menu
theme="dark"
mode="inline"
selectedKeys={[current]}
openKeys={[openKeys]}
>)
}