第四期:前端九条bug分享

本期

最近工作以及个人的事情都比较忙并且抽时间在学java,导致拖到现在才攒够9条合格的‘bug’, 最近一直在用服务端渲染nuxt.js还有echarts, 所以会有多处涉及这方面技术, 这次最后会分享两个最近感悟出的观点还挺有意思的。

1: 为什么列表的数据不要让后端同学返回对象, 而应该返回数组?

返回对象我们前端直接遍历有没问题啊, 可以正常显示,那是因为你没有遇到下面描述的情况
bug现象1:

我明明把3这个key定义在了第二个位置, 但是每次打印出来他都跑到了第三个位置, 那么我是不是循环出的列表就有问题了

<!DOCTYPE html>

<html lang="en">

<head>

<meta charset="UTF-8">

<meta name="viewport" content="width=device-width, initial-scale=1.0">

<title>Document</title>

</head>

<body>

<script>

let obj = {

'1':"数字1",

'3':"数字3",

'2':"数字2"

};

// 这三个都阵亡啦

console.log(Object.keys(obj)) //  ["1", "2", "3"]

console.log(Object.values(obj)) // ["数字1", "数字2", "数字3"]

console.log(Object.entries(obj))

/*

(3) [Array(2), Array(2), Array(2)]

0: (2) ["1", "数字1"]

1: (2) ["2", "数字2"]

2: (2) ["3", "数字3"]

*/

// 老方法也有这个问题

for(let item in obj){

console.log(item) // 1 2 3

}

console.log(JSON.stringify(obj)) // {"1":"数字1","2":"数字2","3":"数字3"}

console.log(obj) // {1: "数字1", 2: "数字2", 3: "数字3"}

</script>

</body>

</html>

bug现象2:
123照样被排序, 而带汉字的放到最后

     let obj = {

'1':"数字1",

'3':"数字3",

'2':"数字2",

'0汉字':'数字0'

};

console.log(Object.keys(obj)) //  ["1", "2", "3", "0汉字"]

我把0换个位置

     let obj = {

'0汉字':'数字0',

'1':"数字1",

'3':"数字3",

'2':"数字2",

};

console.log(Object.keys(obj)) //  ["1", "2", "3", "0汉字"]

bug现象3:

那我加上汉语

使用下面的代码顺序就不会有问题啦,

 let obj = {

'1汉字':"数字1",

'3汉字':"数字3",

'2汉字':"数字2"

};

bug理解:
数组也是对象, 那么对象对这种数组的形式是有一些特殊操作的,这个坑点一定要后端同学明白, 不然后期出现奇怪的bug还要转换数据形式就太苦恼了。

2:echarts的图表如何显示“无数据”, 描述了一个思维过程。

事情是这样的
我要画一张折线图, 但这个折线图有两个状态显示, 无数据的时候显示“暂无数据”, 有数据的时候正常显示数据,所以有了如下的代码。

其中list就是折线图数据的数组, 就是这个样子的[{},{},{}];

你可以分析一下下面的代码bug

<template>

<div v-if="list.length === 0" class="nodata">暂无数据</div>

<div v-else ref="main" class="line"></div>

</template>

...

mounted() {

this.initLine(); // 初始化折线图

}

initLine() {

this.myChart = echarts.init(this.$refs.main);

//...

}

bug现象1:
很明显第一次this.initLine();会报错, 因为list的初始值肯定是空数组导致没有ref等于main的dom元素, 这样当然会报错啦,所以有了下面这段代码。

使用一个变量来控制是否显示暂无数据

<template>

<div v-if="showNodata" class="nodata">暂无数据</div>

<div v-else ref="main" class="line"></div>

</template>

data(){

return {

showNodata:false

}

}

...

mounted() {

this.initLine(); // 初始化折线图

}

initLine() {

//... 比如请求拿到返回值

this.list = res.list;

this.showNodata = res.list.length === 0; // 这里要严谨一点的话, 要处理请求出错的情况, 提前把this.showNodata赋值为false,这里我就只是举例子啦。

}

bug现象2:
看起来好像没有大问题, 但是测试提出了一个诡异的问题, 在数据从有数据到无数据不断切换的时候, “暂无数据”与图表竟然一起显示了出来,如图所示。
image

bug现象3:
明明是v-if控制的dom元素,怎么会同时出现两个。。。
这类问题第一反应肯定是元素的复用问题啦, 加个key就有了如下的代码

<template>

<div v-if="showNodata" key="1" class="nodata">暂无数据</div>

<div v-else ref="main" key="2" class="line"></div>

</template>

问题真的就解决了, 但是明明俩个class 不同, 一个有ref一个没有, 那么这个元素为啥还要重复啊?
bug现象4:
带着疑问去掉了class, 同时去掉key, 竟然也可以消除bug

<template>

<div v-if="showNodata">暂无数据</div>

<div v-else ref="main"></div>

</template>

bug总结:
如果都有class的话,就会复用下面的dom, 把这个dom的class换成nodata, 但是这个dom被echarts处理过所以就导致折线图还在, 所以如果想避免这个bug那就需要其中一个dom不加class或者乖乖加个key啦。

3:commit 了不想提交的内容,但是又commit其他的数据

bug现象:
周末加班不小心把一个.zip文件commit了上去, push时报的错误信息是内容过大, 那好办我直接删除了这个文件再push, 还是包这个错误, 那我修改.gitignore文件, push仍然报这个错误这就很恼火啦。
bug追查:
通过git log查出每个commit的hash号码, 然后git show打出来看看具体的commit信息, 的确就是因为这个.zip文件出的问题, 那么我现在就是需要取消那一次commit, 但是那次提交之后我又进行了多次提交,这可怎么办。
bug解决:
git reset 出错commit的前一个hash, 运行git status你就会发现已经把.zip文件‘吐出来了’,当然这种回退并不会把我们的文件删除, 或者是把文件修改的内容回退, 所以大家可以放心使用, 要记住的是对于已经commit的文件,配置.gitignore文件是无效的。

4:为什么每次时间都会变化

bug现象:
一个风和日丽的傍晚... 我写了一个毫无花哨表单, 但是诡异的事情正在缓缓到来,背景是我们那个项目使用了nuxt.js, ui选用了Ant Design Vue, 这个表单里面使用了一个时间控件, 就是那种可以选小时与分钟的, 不可思议的是每次我提交的数据‘时间这一项都是错误’, 比如我选的下午2点,但是提交的是上午3点, 就是时间永远提交的是错的。。。
bug追查:

  1. 后台要求时间格式是 ‘23:03’这种字符串的格式
  2. 当时我没有用插件处理, 而是直接把时间串slice截断了一下, 取出小时部分
  3. 为了不影响原数据, 每次提交的时候我都会const form = JSON.parse(JSON.stringify(this.form))

由上面的内容分析了一下, 我突然想到Date对象不支持json序列化, 会不会是序列化的时候导致了变异?
想到了就赶快试一试

image

不难看出本来是18:41:19, 但是转换完毕变成了10:41:19, 前面的小时数出现了变化。

但调用toString方法就不会使其变化

这么好玩的事情一定要追查下去啊, 这个10到底是什么, 他的转换规则到底是什么, 当时没有这方面的只是储备, 那么就把date对象身上的属性一个一个的试我就不行找不到

果然被找到了,如图
image

d.getUTCHours() 是什么?

getUTCHours() 方法可根据世界时 (UTC) 返回时间的小时。 也就是说他是世界时间, 而不是北京时间的小时
对世界时间有兴趣的可以看看这篇文章写的挺清楚的https://www.cnblogs.com/you-jia/p/4465690.html

为啥只有小时不同, 分钟和秒都一样

哈哈哈这个其实很好解释, 就是联合国规定每个时区之间的差异只能以小时为维度, 所以才有了这个bug的情况, 真是无用的知识又增加了感觉自己棒棒的。
如果以后大家遇到了这种bug可以大胆的吹它一顿nb啦。

5:Failed to execute 'appendChild' on 'Node': This node type does not support this method

前因后果:
在使用nuxt.js框架编写项目的时候,遇到了一些实际的问题。

  1. 部署成本的增加,服务端可能要安装pm2,node,yarn。
  2. 每次更新代码太慢了, 尤其实在联调阶段,每次更新代码要花费我5分钟左右(你可以想象遇到一个只在线上才会出现的bug我有多心累)。
  3. 莫名其妙的错误增加了学习成本, 并且这些错误可能对我们没啥提高。
  4. 每次编译速度极慢极慢,并且编译后有错误(在这里热更新就是个笑话), 开发了一个月我甚至都已经习惯用鼠标点浏览器的刷新按钮, 甚至甚至!!!!刷新一遍可能还是错误的我要手动刷新第二遍才会正确(桌子都掀了, 再摆回去)。
  5. 报错很夸张, 可能我一个代码错误它报500....我一个取值错误它就白屏。
  6. 自身代理需要在每个环境里面修改, 比如测试环境服务启在3000, 开发环境启在8080, 上线又要变。

吐槽还有很多很多, 但是我就不吐苦水了, 大家想清楚如果真的真的需要服务端渲染再选择使用它,我们项目一个后台管理系统使用它收益真的有点小。

bug现象:
在我们不堪其扰的时候, 团队终于决定使用静态包来部署, "generate":"nuxt generate",也就是这句神奇的命令, 他会生成多个html文件来达到区别于spa技术的目的,而我们部署起来方便多了, 但是开发还是很很不舒服, 就在这个时候出现了这个问题,我在开发服务器上启动的服务跑的没问题, 但是在测试服务上面的generate静态包出现了题目上的错误, 难道这个错误与打包方式还有关???

bug解决:
解决方法说来也简单, 我使用了一个<iframe>标签, 这在他生成时候就乱了套了哎, 所以我要用<no-ssr></no-ssr>标签dom结构包裹起来, 让他不要走服务端渲染程序, 这样就可以避免这个问题啦,归根结底还是这个技术本身有问题。

6:在nuxt的静态打包时,前端path被占用

bug现象:
做好的项目放在新的测试服务器上, 其中动态大屏的页面访问包nginx报403, 这时候测试与后端同学就来找我了, 质问我做了什么导致nginx出了问题....我给他们的是静态包根本没有操作服务器的代码, 那么问题已经就处在服务器环境或者后端同学代码身上啦, 虽然不是前端的工作,但正好是个学习的机会就来帮他们查一查吧。
在项目内用$router.push的方式跳过去没问题, 点击刷新页面就会404.

bug追查:
nginx报错那么一定出在路径上, 查看nginx配置文件里面是如何代理这个路径的,外部直接访问这个路径查找走到了那个代理,最后果然发现了这个路径被一个空的资源占据啦。

bug解决:

  1. 加上路径前缀也就是publicPath
  2. 前端给这个页面改名

最后为了最快时间解决,并且也是后端同学实在忙不过来了只能妥协这个版本使用第二种方式。

7:echarts的几个不常见的问题罗列

知识点罗列:

  1. 让折线图堆叠与不堆叠
    在使用折线图的时候, 有时候会涉及到多折线, 这个时候就可能需要这n条折线各自之间互补干涉,也可能让给他们成为堆叠的状态, 如图所示:

    通过设置每条线的stack属性相同达到堆叠效果, 反之亦然
    不堆叠
    堆叠

 series: [

{

name: '紧急',

type: 'line',

smooth: true,

stack: '紧急', // 不一样就不堆叠了

data: [1,2,3],

},

{

name: '高危',

type: 'line',

smooth: true,

stack: '高危',

data: [5,6,7],

},

{

name: '中危',

type: 'line',

smooth: true,

stack: '中危',

data: [8,9,10],

},

]

  1. 使横线变成虚线
    这个要求好诡异我找了半天才找到, 不分享出来都感觉对不起自己,对比如图:
    实线
    虚线

    代码如下

yAxis: {

type: 'value',

axisLabel: {

color: 'white',

fontSize: 14,

},

splitLine: { // 这个就是精髓

show: true,

lineStyle: {

color: '#d8d8d8',

type: 'dotted',

},

},

},

  1. 让地图可以根据评分变成相应的颜色

这个也是我找了半天, 官网里面说的都是inRange属性, 但是这个属性没法让我们去设置范围, 后来我找到了dataRange这个属性如图:

地图颜色

如下的方式去使用就好啦

 dataRange: {

right: "2%",

bottom: "3%",

icon: "circle",

align: "left",

splitList: [{

start: 0,

end: 0,

label: '提示',

color: "#6ead51"

},

{

start: 0,

end: 250,

label: '低温',

color: "#92b733"

},

{

start: 250,

end: 500,

label: '中温',

color: "#c4aa29"

},

{

start: 500,

end: 750,

label: '高温',

color: "#ce6c2b"

},

{

start: 750,

label: '超高温',

color: "#c92626"

}

]

},

  1. 推荐论坛地址echarts论坛

8:写一个官网的注意事项

bug现象1:

所有关键的key与词语必须让用户搜索的到:

ui组件库的官网每个实例下面,基本都有一个折叠代码的功能, 但是当我想要ctrl+f搜索的部分就在这个被遮挡住的代码块中的时候怎么办?? 那就很不方便找到了, 所以说折叠代码的同时不要让这里的dom结构消失会更舒服, 毕竟ui的官网应该以方便查询为主, 而不是官网页面的性能。
这方面element-ui做的很棒。

bug现象2:

过于简短的介绍甚至无介绍:

很多官网对于一些用法都是一句话了事, 举例子也就举其中的一段代码, 导致我们要付出更多的学习时间才能把他研究懂, 官网你都做了为什么不能附上完整的代码?与详细的介绍。
可能写这个的团队都是大神, 怕写多了没有身份。
更有甚者, vue的一个插件他在介绍里面引入了个mixin 也不说mixin里面是啥代码。。。。

bug现象3:

不怕重点词的重复

其实某个知识点你虽然说过, 但是有些时候如果解释的话术不是很多的话, 我还是建议直接在使用的位置的旁边附上解释, 不要为了找一个13个字就能说清楚的东西还要点三层连接去到你们的英文文档里面自行查阅,我承认你写的很规范很秀, 但是不太好用。

9:面向人类编程(这里只是个人的观点)

代码不但是写给我们自己的, 也是写个所有人的

  1. 把自己写的代码当一个产品输出。
  2. 把同事当客户。
  3. 不要为了看着所谓的正规而丧失代码的可读性, 有时候代码丑一些但是更实用。

过度封装

代码本身就是给人看给机器运行的, 而我们何不把写出的代码当成一个产品去设计, 让用户用着舒服用着爽。
我看过太多代码做到了所谓的“高标准”, 比如把请求全部集中起来,当我发现一个http请求出错的时候我要搜索这个http地址, 然后再全局搜这个http地址对应的方法名, 这样的两步走收益真的大么? 这只是一个小例子吧。

自己明白就行?

做开发肯定会遇到一起奇奇怪怪的需求与bug, 当我们梳理好了逻辑或是解决了怪异的问题 可否直接在相关代码的旁边完整的写上逻辑关系以及为什么这里写的比较奇怪, 干嘛每次别人梳理到这里还要来问你一次为啥这么写。

用着不爽硬坚持?

某些技术可能是你总监提出来的或者cto亲推, 但是实际使用起来就是不爽, 那么我们作为开发者也可以提出来,毕竟写代码是件开心的事。

当然时间紧任务重的话酌情

毕竟大家都会有十分十分忙的时候, 此时不必过分追求这些,都理解的哈哈哈。

end:

希望文章能够对你有收获! 本次的分享就是这样,欢迎交流, 祝每天进步

以上是 第四期:前端九条bug分享 的全部内容, 来源链接: utcz.com/a/40261.html

回到顶部