js
for...in
循环内部出错时,不会报错,但是会停止后续所有代码进行。这次同事使用
for...in
循环遍历一个多级对象。他直接使用obj.xx.prop
根据部分属性内的prop属性来判断属性的类型,但是有的属性比如xx为undefined
。一般我们知道,使用直接使用
undefined.prop
也就是对undefined
使用.
操作符是会直接报错的。但是在for...in
循环内却没有任何提示,只会中断代码进程,造成意外bug1
2
3
4//直接在循环内抛出错误也一样不会提示
for (let key in values) {
throw Error('err')
}解决方法:
- 相同情况避免使用
for...in
遍历 - 每次在
for...in
循环内套一层try...catch
捕获错误,后续代码也能继续,但是麻烦
- 相同情况避免使用
toFixed
、Math.round
都不是真正的四舍五入,而是使用银行家舍入法,当舍去的位数值为5,且5前的位数是偶数,则不会进位1
2
3
4
5
6
7
81.255.toFixed(2) //1.25
//完美四舍五入
//Number.EPSILON表示 1与Number可表示的大于1的最小的浮点数之间的差值
function toFixed(num, place) {
const step = Math.pow(10, place);
return Math.round((num + Number.EPSILON) * step) / step;
}
vue
vue中使用sass,安装
node-sass@4.14.1
,sass-loader@8.0.2
。这两个版本稳定,其他兼容问题多node-sass需要与sass-loader版本匹配
node-sass还要与node版本相配,否则会报
Error:Can't find Python executable "python"
。与node版本匹配如下表:
NodeJS Minimum node-sass version Node Module Node 14 4.14+ 83 Node 13 4.13+ 79 Node 12 4.12+ 72 Node 11 4.10+ 67 Node 10 4.9+ 64 Node 8 4.5.3+ 57 vue中使用swiper,安装
vue-awesome-swiper@3
可以完美使用,新版使用swiper6,出现设置autoplay不生效的问题- 另外使用时swiper-slide内容添加点击事件,在设置loop后第二轮过后点击事件不生效。原来loop会新增swiper-slide实现无缝,但vue中就没有绑定到所有元素上:
添加配置属性on监听点击:
1
2
3
4
5
6
7on: {
//用tab点击事件,click有明细延迟
tap: function() {
//this.realIndex得到当前点击准确索引,传给methods中的点击处理方法
_this.clickHandler(this.realIndex)
}
}- 而且由于图片数量和路径由接口数据决定,导致初始化计算错误,轮播的
loop
无缝失效。给轮播父级加上v-if="picArr.length"
即可
better-scroll
- 实例方法
scrollTo
动画滚动到指定位置 - 实例方法
refresh
重新计算滚动高度,
- 实例方法
新版
observeDom: true
监视元素变化,自动计算滚动高度全局常量挂载到window上后可在组件内复用,但除开组件这种加载顺序靠后的,像vuex内就获取不到(因为执行时还未完成挂载)。混入的内容是依附组件的,也能获取到
在vue-cli3中,通过路径跳转本地的文件,必须将本地文件放到public目录下,放到assets会找不到文件
vue生产环境需要配置vue.config.js=>
productionSourceMap: false
,打包后不生成map文件(用于查找报错位置),节省空间vue-cli3打包开启gzip压缩文件(需要服务端开启gzip才有效):
npm i compression-webpack-plugin@5 -D
不加@5
默认安装最新版7.1,会报错vue.config.js
中配置:1
2
3
4
5
6
7
8
9
10
11
12const CompressionPlugin = require("compression-webpack-plugin")
configureWebpack: {
plugins: [
new CompressionPlugin({
//需要压缩的文件正则
test: /\.js$|\.html$|\.css$|\.jpg$|\.jpeg$|\.png$|\.gif$|\.webp$|\.svg$/,
// test: /\.(js|css)(\?.*)?$/i,
threshold: 10240,//文件大小大于这个值时启用压缩
deleteOriginalAssets: false//压缩后保留原文件
})
]
}
使用eslint + prettier规范代码格式老报错:
除了在
vue.config.js
中取消规范:lintOnSave:false
, 还可以:先命令行
npm run lint
规范代码,如果报错且没有修改成功,可以修改package.json
script=>lint:"vue-cli-service lint"
改为"eslint --fix --ext .js,.vue src"
之后。此时多数格式问题都被规范了,但定义的全局常量
CONST
挂载到了window,eslint确报错这个常量未定义。需要在package.json的eslintConfig中:1
2
3
4>//配置全局常量
>"globals": {
"CONST": true
>}配置eslint不以分号结尾(eslint + prettier时无效,原因后文的注意):
1
2//第一个参数2改为1报错改为警告,为0表示关闭规则。注意关闭后默认会要分号
"semi": [2, "never"]不需要规范的文件/目录,在根目录创建
.eslintignore
文件声明:1
/src/assets/font
注意: 当项目使用eslint + prettier规范代码时,eslint主要检查代码质量并给出提示,而prettier主要规范代码风格。此时给eslint配置分号和引号等代码风格相关的会与prettier冲突,只需要根目录创建
.prettierrc
文件:
1
2
3
4
5
6 >{
"printWidth": 120, //换行宽度
"tabWidth": 2, //缩进
"singleQuote": true,//单引号
"semi": false //是否有分号风格
>}
还可以在vscode下载prettier和eslint,并配置默认格式化方式为prettier:
1 | "prettier.printWidth": 120, |
动态路由配置(前端鉴权)
当某些页面必须特定身份才能访问,最好不要一开始就将所有路由配置上去
router目录下新增动态路由文件,存放动态路由routes可能的配置
判断到用户身份的变化,使用
router.addRoutes
选择对应的配置添加。由于需要给已有的路由添加子路由,直接添加会冲突,因此要重新覆盖原路由,addRoutes
参数必须是包含已有路由规则,需要拿到路由初始的配置:1
2import baseRoute from '@/router/index'
baseRoute.options.routes //初始配置的路由针对用户身份对原先的路由配置添加修改,再将修改后的配置通过
addRoutes
传入1
2
3
4
5import VueRouter from 'vue-router'
//matcher对已配置的路由name校准,要给已有的路由添加子路由,难免会有配置的重复出现导致警告
//解决: 创建一个新的router,将matcher给当前的matcher,重置校准
vm.$router.matcher = new VueRouter().matcher
vm.$router.addRoutes(routes)针对未配置的路由,使用路由守卫不允许访问
1
2
3
4
5
6
7
8router.beforeEach((to, from, next) => {
//matched数组为空为0未匹配到路由规则
//from的matched数组为空表示页面刷新触发的(刚刷新时动态路由还未添加),不回退
if (!to.matched.length && from.matched.length) return router.go(-1)
document.title = to.meta.name || ''
document.body.scrollTop = document.documentElement.scrollTop = 0
next()
})退出登录时无法删除已添加的路由规则,只有重新刷新页面,但又想跳转到首页。我的方法是用路由后置守卫判断缓存是否刷新,每页都能用:
1
2
3
4
5
6
7router.afterEach(() => {
//缓存中有RELOAD表示要刷新页面
if (localStorage.getItem('RELOAD')) {
localStorage.removeItem('RELOAD')
location.reload()
}
})
还可以给路由meta添加roles,角色身份变化时从需要鉴权的路由表中筛选出可访问的路由进行addRoutes,roles内存在的当前角色才有权限访问。
并且可以定义权限白名单,如登录页,在全局路由守卫上判断白名单上的路由不需要登录即可访问
路由中携带参数最好放到meta中,直接放到name不能修改,路由name只读
多行文本实现提及功能,需要获取多行文本光标距屏幕边缘
left
、top
。用网上找的方法正常情况可以,但当多行文本出现滚动条时距离就会不准确
用第三方插件:
ant-design
,完美实现了提及功能,还有vue-mention
自己实现的话,大概思路如下:
1
2
3
4
5- 创建并定义一个与目标多行文本样式一模一样的div元素设置contenditable成为富文本(设置div样式word-wrap: break-word否则不会换行,overflow-y:auto),最后放一个span A获取文本最末尾的位置。
- 文本输入内容时将输入内容赋值到div内靠前
- 输入@时在光标长度的位置(selectionStart)插入一个span B,失去焦点时删除span B
- 获取光标位置时就获取span B的位置(getBoundingClientRect),没有span B则获取span A的位置
- span A、B宽度都为0
递归组件必须设置
name
和v-for
等条件让vue可以判断,否则会无限级渲染用户手动点击游览器前进后退,hash模式下路由守卫可以监听路径变化,但是不能进行异步拦截(自定义弹窗),解决方案如下:
- 使用history模式(需要考虑该模式下资源重定向问题)
- 用原生confirm拦截js运行(无法自定义弹窗样式)
Node.js
npm
速度过慢老卡在fetchMetaData,使用淘宝镜像:配置永久替换镜像
1
npm config set registry https://registry.npm.taobao.org
安装使用cnpm
更新新版脚手架时删除老版本导致
npm
缓存错误,使用npm cache clean --force
后再安装,出现npm err 4048
,解决方式:1
2
3//下面指令使,npm会去校验一些缓存依赖的完整和有效性
//接着下载直接成功
npm cache verify脚手架创建vue3项目运行时,报错找不到vue-loader-v16,猜测由于npm版本过低,导致脚手架或依赖安装的有问题,需要更新npm,由于是nodejs带的,需要更新node版本。
使用nvm安装最新版node后执行
npm
指令时报错找不到npm-cli.js。原因是npm虽然在nvm安装node过程中解压,但未成功将解压后的npm文件夹放到对应版本node的node_modules中。在npv use
时会将选定版本目录下node_modules映射到C:\Program Files\nodejs\node_modules,所以使用npm时会找不到文件解决方式:
在node安装完成开始安装npm时nvm文件夹下会出现temp文件夹,复制出temp中的npm压缩包。在安装完成后将压缩包解压,重命名为npm,并放到对应版本node的node_modules中。再进行
nvm use
进行映射
微信小程序
hexo
将本地博客源代码上传到git时,由于之前下载主题时用的git clone
,将主题作者的git信息一起保留下来,导致提交时检测到主题文件有额外的本地库,主题文件未能成功添加。
将themes目录下对应的主题文件夹.git
删除即可
地图
百度地图
最近将公司项目中的思极地图所有逻辑改为用百度地图,总结坑点如下:
百度地图对事件进行了封装,若希望如点击事件等取消冒泡等操作,要通过
e.domEvent.stopPropagation()
思极地图可以将文本标注(如线路名称/距离)在线条上且跟随地图缩放灵活变化,而百度地图只能用label动态计算并标注,且文本不方便跟随线条方向倾斜。
需要设置文本标注白色轮廓,一开始用
box-shadow
设置轮廓总是不清晰,找半天原来box-shadow
可以支持多个阴影:1
2//由`,`隔开的每项表示一个阴影,用4个阴影建立4个方向上的轮廓
text-shadow: '1px 0 #fff,0 1px #fff,1px 0 #fff,0 -1px #fff'使用导航搜索(
BMap.DrivingRoute
)时需要用setSearchCompleteCallback
每次在搜索回调中动态添加数据,结果绘制的线条总跟一开始存放的标注信息不一致,猜测由于搜索回调是异步返回,在返回回调之前又进行了下一次搜索修改了回调的参数。最后使用async await
完美解决:用promise
封装,每次await
回调完成后再进行下一次search
撒点的弹窗样式高度定制化,infoWindow不能满足需求,需要引入并使用
infoBox
需要点击一个撒点,弹出另一个撒点的弹窗。由于使用
vue-baidu-map
,在click事件内才能获取到marker实例,需要手动new BMap.Marker
创建位置相同的marker,创建新弹窗将之前弹窗清除。
移动端
- 在移动端混合app和h5中,如果页面使用到了input等弹出键盘元素,键盘弹出时会造成页面挤压,绝对定位的元素位置会瞬间上升。
- 可以使用媒体查询监听高度修改或隐藏元素
- 最好为页面容器设置
min-height
就能避免挤压
element-ui
使用
el-row
布局时,默认的混合模式使用display: table
布局,在特定情况下(如游览器缩放且行末的el-select选择内容后)内容会出现奇怪的错乱。可以更换el-row
布局方式解决:1
2
3
4.flex-row.el-row {
display: flex;
flex-wrap: wrap;
}
其他
设置
iframe
内滚动条的样式,而::-webkit-scrollbar
等滚动条伪元素通过js获取不到,最好是定义一个style
标签插入到iframe
页面的head
中去为富文本添加
placeholder
:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26//控制placeholder显示
iframeBody.on('blur', () => {
const html = layedit.getContent(editIndex)
//正则判断,粘贴内容进去删除内容可能剩下p和br标签
if (!html.replace(/<\/?(p|br).*?>/g, '')) iframeBody.html(placoholderNode)
}).on('focus', () => {
placoholderNode.remove()
}).on('DOMNodeInserted', () => {
//点击工具菜单插入内容不会触发focus,此时也要清除placeholder
//插入placeholder时也会触发此事件,再删除会导致一插入placeholder就被删除,加入判断: 存在html中placeholder内容但不等于placeholder
const html = layedit.getContent(editIndex)
if (html.indexOf(placeholderHtml) > -1 && html !== placeholderHtml) placoholderNode.remove()
})
//点击发送按钮
$('.btn-send').on('click', () => {
// layedit.getContent(editIndex) //获取html
// layedit.getText(editIndex) // 获取纯文本
const html = layedit.getContent(editIndex)
const text = layedit.getText(editIndex)
//内容为空或为placeholder则不发送
if (!html.replace(/<\/?(p|br).*?>/g, '') || html == placeholderHtml) return
console.log('发送', html)
})新了解了DOMNodeInserted和DOMNodeRemoved元素插入和移除内容事件,但在项目中会与手动添加的plceholder逻辑冲突,需要如上判断
另外粘贴内容进去富文本,再删除内容可能剩下p和br标签
Chrome等游览器有一个很奇葩的bug,一个绝对定位的、边框宽度
1px
的input
框,在使用transform: translateY(-50%, -50%)
后边框变粗。将其改为transform: translateY(-50.1%, -50.1%)
则恢复正常,猜测原因如下:元素高度乘50%产生了小数导致计算不准确。
使用flex布局时,左边固定,右边
flex: 1
并设置超出隐藏,但是右边超出隐藏不生效。由于右边自适应,超出时会挤压左边空间造成超出隐藏失效,因此需要给左边设置flex-shrink: 0
禁止收缩。近期项目依赖的
browserslist
升级到了4.21.0版本,由于是依赖所依赖的包只用^
限制到了4.x,打包时提示没有loader去加载cache-loader、thread-loader、babel-loader、ts-loader来支持?.
是因为
.browserslistrc
设置了not dead
,从4.21开始,ie11被列入了dead
范畴,不再提供对?.
操作的polyfill,但是当前版本的babel-preset-env并未兼容。- 升级一下node版本,让更新版安装的依赖支持本次改动
- 在package.json中限制browserslist到之前版本:
"browserslist": "~4.20.2"
.browserslistrc
添加ie 11
或去掉not dead
- 本文作者: MR-QXJ
- 本文链接: https://mr-qxj.github.io/2021/09/18/其他/踩坑/
- 版权声明: 本博客所有文章除特别声明外,均采用 MIT 许可协议。转载请注明出处!