第二期:前端九条bug分享

本期

此次9个并不都是bug, 其中有几个小优化, 虽然一个月的时间遇到不少bug, 但并非每一个都有参考价值, 让咱们看看此次我遇到的有趣问题吧.css

1: git 报错WARNING: POSSIBLE DNS SPOOFING DETECTED!

bug现象:
一个平凡的清晨, 放下书包喝了口白开水, 习惯性的git pull了一下, 这个不速之客就出如今了命令行里面, 脑壳中居然第一反应是但愿这个bug有趣一点, 这样就能够写文章了, 这个bug是忽然出现的自己确定与个人操做无关, 当时问了下其余同事也遇到了这个问题, 可是我须要查一下如何解决它,以及它的危害与预防.前端

bug追查:
WARNING: POSSIBLE DNS SPOOFING DETECTED! 翻译成中文 警告:检测到可能的DNS欺骗!哦哦原来是"信任"方面的问题, 那我能想到的就是"身份验证方面", 有关身份我只作过全局的gitlab的帐号邮箱设置, 权限设置, 还有就是ssh的设置, 那么怎么看都是ssh嫌疑最大, 最后仍是去网上查到的解决方法.vue

bug解决方案:
删除 known_hosts 文件
一台主机上有多个Linux系统,会常常切换,那么这些系统使用同一ip,登陆过一次后就会把ssh信息记录在本地的~/.ssh/known_hsots文件中,
切换该系统后再用ssh访问这台主机就会出现冲突警告,须要手动删除修改known_hsots里面的内容。
有如下两个解决方案:node

  1. 手动删除修改known_hsots里面的内容;
  2. 修改配置文件“~/.ssh/config”,加上这两行,重启服务器。
    StrictHostKeyChecking no
    UserKnownHostsFile /dev/null

优缺点:webpack

  1. 须要每次手动删除文件内容,一些自动化脚本的没法运行(在SSH登录时失败),可是安全性高;
  2. SSH登录时会忽略known_hsots的访问,可是安全性低;

2:地图geojson 绘制地图的具体操做(附上地图的代码)

需求:
项目内须要使用地图展现资产在全球的分布, 须要绘制'全球地图',有闪烁提示有悬停展现详情, 本功能只是一个小模块, 因此不准有明显的加载感, 后端会返回给我每一个点对应的经纬度.ios

分析与准备:nginx

本次并无采用咱们公司内部孵化的地图库, 由于它并不够轻量, 最后选用的是echarts, 我也是第一次用echarts画地图.
说实话官网的例子挺很差的, 不少地方也没有说明白反正我第一次去学习的体验挺差.
地图须要画出各个国家的区域线条, 那就须要一个描述文件而这个文件通常都叫作"geojson"文件, 而这个文件又分为pc(以中心点绘制)、以经纬度绘制两种比较常见, 而本次咱们采用的是经纬度的定位, 那就须要用经纬度的geojson!! 这个很是重要, 具体的json这个网站里面挺全的, 但他都是pc绘制geojson文件库
下面是我简单作了下封装的组件
<template>
<div
  id="main"
  style="position: relative; width: 100%; height: 100%; padding: 0px; margin: 0px; border-width: 0px; cursor: default;"
/>
</template>

<script>
import echarts from 'echarts';
import geoJson from '../assets/geojson/countries.geo.json';

export default {
props: {
  mapData: Array, // 里面只有三个值, 经度, 纬度, 数量 用于打点
},
data() {
  return {
    sanData: [],
    myChart: null,
    tooltip: { // 提示框
      trigger: 'item',
      formatter: (arg) => {
        if (arg.value) {
          return `${arg.name}: ${arg.value[2]}`;
        }
        return '';
      },
    },
    geo: { // 地图的底色样式
      map: 'all',
      zoom: 1,
      top: 30,
      left: 30,
      right: 30,
      bottom: 30,
      show: true,
      roam: false,
      label: {
        normal: {
          show: false,
        },
        emphasis: {
          show: false,
        },
      },
      itemStyle: {
        normal: {
          areaColor: '#47D1FF', // 板块颜色
          borderColor: '#3B5077', // 边线
          shadowColor: 'rgba(0, 0, 0, 0.2)',
          shadowBlur: 10,
        },
        emphasis: {
          areaColor: '#2B91B7', // 悬停
        },
      },
    },
    effect: { // 闪点样式
      name: '数量',
      type: 'effectScatter',
      showEffectOn: 'render', // render emphasis
      coordinateSystem: 'geo',
      hoverAnimation: true,
      legendHoverLink: true,
      symbolSize: () => 20,
      rippleEffect: {
        brushType: 'stroke',
      },
      itemStyle: {
        normal: {
          color: '#ff8003',
        },
      },
      label: {
        normal: {
          formatter(arg) {
            return arg.value[2];
          },
          position: 'inside',
          show: true,
        },
        emphasis: {
          show: false,
        },
      },
    },
    map: { // 地图的绘制数据
      type: 'map',
      name: '工程数',
      mapType: 'world', // 自定义扩展图表类型
      geoIndex: 0,
      itemStyle: {
        normal: { label: { show: true } },
        emphasis: { label: { show: true } },
      },
    },
  };
},
methods: {
  initMap() {
    this.myChart = echarts.init(document.getElementById('main'));
    const {
      myChart, sanData, effect, tooltip, geo, map,
    } = this;
    echarts.registerMap('all', geoJson, {});
    effect.data = sanData;
    const option = {
      geo,
      tooltip,
      series: [effect, map],
    };
    myChart.setOption(option);
  },
  // 组装成地图须要的打点数据
  initDian() {
    this.mapData.forEach((item) => {
      this.sanData.push({
        name: item.country,
        value: [
          item.lng,
          item.lat,
          item.value,
        ],
      });
    });
  },
},
mounted() {
  this.initDian();
  this.initMap();
},
};
</script>
效果以下图(参考了网上你们的作法, 比官网还靠谱)

sj.png

3:样式同样的新老项目共用一个域名.

背景:
一个展转了三个团队, 维护了快三年的老vue项目, 代码简直乱到使人发指的程度, 好比请求报错了 /api/home/list/ip这样的地址报401, 那么我去查找这个地址在哪里发出的请求, 全局也没搜索到这个地址, 一个小时后我才知道 这个地址被分红了相似这种-> , const a = 'api', const b = 'home', const c = 'list', 请求的时候 axios.get(/${a}/${b}/${c}/ip), 不只如此, 这个请求还被放在的vuex里面展转反侧三个配置页面而后被各类从新命名以后不知所踪, 关键是连个文档也没有, 这个项目在我来到公司以前就已是一我的人不肯碰的存在了.git

我刚加入就接到了改造这个项目的任务
通过讨论这个项目是"救不活了", 可是咱们能够另起一个如出一辙的项目, 而后全部的新需求都放在新项目里面, 每次需求都把老项目的页面迁移过来一个, 这样一年半载以后就能够完全使用新项目代替老项目

须要解决的问题:程序员

  1. 两个项目域名相同
  2. 切换时尽可能作到用户无感
  3. 共用一套登陆系统
  4. 平稳迁移, 最终淘汰老项目

解决方案:web

  1. 老项目地址xxx/home, 新项目地址xxx/new, 这个须要后端同窗配置nginx代理, 监测到xxx后面的地址进行分配, 这样两个工程的静态资源也要作好代理的区分, 咱们须要配置好publicPath.
  2. 俩个工程的一级二级导航栏作到彻底同样, 甚至悬停出现的弹框也要作到彻底一致(视觉骗子), 还好这个项目导航方面并非很复杂.
  3. 添加一个专门的router拦截函数, 老项目: 监测到new字段就跳转到新项目, 新项目检测到home路径就跳到老项目, 这样写对于404有bug最后我说解决的办法.
  4. 后台代码也跟咱们一期一块儿重写, 这就要兼容新老后端代码.

404问题:
若是监测到new字段就跳转到新项目, 检测到home路径就跳到老项目, 这个会有bug, 好比我乱打一个xxx/jjj那么这个就会留在原地, 咱们就须要在'新老'两个项目里面都写一个'404页面', 这一点想到了那么若是是这样 xxx/new/jjj这又是一个'404页面'可是他带new字段, 那么它跳到新项目又变成了bug, 我想到的解决方案是 new这个新项目只要检测到不是本身路由表里的地址, 就把这个链接指向老项目, 老乡维护一套新项目的路由地址list, 只有在list内才会进行跳转新项目的操做, 这样bug就解决了, 可能你会有更好的方法哦能够一块儿交流.

401与303 前端 测试 后端:

这里是个交流沟通的问题
问题是这样的, 老项目接口未登陆报303, 新项目接口未登陆报401, 这个现象看起来很好办, 只要检测到 303或是401统一跳登陆页面, 可是问题来了, 这两个状态码的判断标准不同, 出现了'循环跳转'的bug.

好比说: 你在老项目里面不报303那么登陆页面就把你转到'来时的'路径, 可是这个路径若是指向新项目, 可是新型项目里面报了401, 致使新项目又跳回登陆页面, 日复一年年复一年的循环跳转.

这种问题是沟通问题

只要出现循环的跳转, 测试就会来找到咱们, 由于这看起来绝壁是前端问题啊, 你死循环管后端什么事, bug提给我无论是否是个人问题, 有时间的话我都会帮着排查与修复, 我把这个缘由搞清楚后去跟后端同窗沟通, 这个过程挺慢的, 毕竟谁也不但愿bug是本身的..., 但是这个问题到第一次上线他们也没有去解决, 线上又报循环跳转测试仍让我紧急修复, 这个虽然可以理解但也挺无语, 后来用的技巧就是把问题在群里抛出来, 用简短的话把问题说清楚, 不能"看着像前端问题就前端改", 固然了我跟后台同窗了解下303余与401的判断标准, 在前端侧也增长了一层登陆判断, 虽然没啥大用可是也能帮后端同窗解决95%的差别了, 但是剩下5%的问题我已经帮他们分析出解决方案, 但是也放在下个版本作了.

经过这些问题可以感觉到, 前端不光是写代码, 也有统筹整个项目的责任在身上, 积极整合你们也是一种锻炼

4:element表单隐藏input

故事是这样的
做者接到了一个离职者的遗留工程的新增需求,需求很简单:在一个表单中根据某一项的选择状况来决定显示与隐藏一个input,好比'类型下拉框'选择‘我的’就隐藏‘订单号’反之则显示而且为'必填', 这个需求简直简单到爆。

bug描述
当先不选择'我的', 而后再选择'我的'选项时,‘订单号的input’消失了可是报错提示信息'订单号为必填'仍是存在。

bug初步分析
element-ui自己是否有缺陷, 我用v-if控制输入框的隐藏它没有检测到。

bug初步解决
在我隐藏这个输入框后, 100毫秒的时候调用一次表单的验证方法,虽然你可以解决但这个方法给人的感受就是临时方案。

bug深刻分析
建一个vue工程把这个bug状况在纯净的新工程里面还原一次,结果并未复现, 这就说明这bug跟人家element没有关系,定位在代码自己有问题就行了,问题的元凶就在@change这个事件里面, 上一位同窗是在行间这样写的。
@change="() => { updateDesc(); updateYtsUserType(); updateMonitoring() }"
而在updateMonitoring方法里面有一个对表单的校验,这个updateMonitoring方法还有5处地方在调用,因此并不建议修改这里, 致使这一bug的缘由是@change事件与vue的数据更新机制未衔接好, vue更新一个值是要通过diff算法的, 更新数据采用三种方案,1:事件的订阅发布 2: promise 3:settimeout 逐级兼容, change事件刚好在这以前就调用了表单的验证,因此把这个检验放在下一个宏任务就不会出现这个bug了, 也不会出现错误信息一闪而逝的状况。

想起了聚焦与失焦的问题(某些移动端有bug)
以前作移动端项目有三个input, 我须要监控当前用户从某个input框里面填完再跳到某个input框的操做路径, 并作一些相应的处理,具体的业务场景我记不清了, 可是当时我发现,好比我再inputa里面输入内容后跳到inputb里面,有时候是先执行的inputb的聚焦 而后 才是inputa的失焦 而且这个时间不是固定的, 由于当时我搞了个0秒延时器并非100%奏效, 这个点你们能够注意一下。
正常因该是 a聚焦-> a失焦-> b->聚焦 pc端还挺好

5:上传打包文件的小优化, 小而美提高工做体验

这种事情我也认为属于小bug, 毕竟程序员是追求高效的, 并且减小操做步骤能够减小出错的几率。

公司项目组暂时由咱们上传到服务器,自动化正在搭建。

以前上传代码
1: 打包
yarn build
2:压缩
把打包好的dist文件压缩为zip格式
3:scp上传dist.zip文件
4:ssh链接服务器
5: 进入指定目录, unzip解压dist

如今传代码
1: 打包
yarn build
2:scp上传代码
scp -r dist/* root@1.1.1.1:/home/xxx/xxxt

反思
若是包并非特别大的话或者网络很很差, 建议使用第二种, 不以优化小而不为,不以危害小而为之。

6: Cannot assign to read only property 'exports' of object '#<Object>'

这个又是接收了一个离职同窗的老项目

bug描述
拉新项目-> 切分支-> yarn 一切正常,打开地址就报这个错.
中文意思就是这个项目里面混合使用了common的规范与es的规范, 须要我统一规范, 就比好比使用了 module.exports 也使用了 import

bug初步解决
使用插件让二者兼容就解决了
npm install babel-plugin-transform-es2015-modules-commonjs

babelrc配置
{ "plugins": ["transform-es2015-modules-commonjs"] }

思考
这个问题应该不会是个须要下载插件或者修改代码才能解决的问题, 毕竟开发了好久, 若是启动都有bug那怎么上线的, 因此问题应该就存在于流程上, 或者外部的环境上, 好比它使用了我本地的全局webpack的话那就有多是我webpack版本问题, 但查了一下package.json文件并没有这种状况,那问题就在操做流程上。

bug解决
缘由很简单, 这个是个老工程使用npm管理版本, 而我习惯性的用了yarn, 致使yarn命令并不能读取package-lock.json文件,那么我下载的版本与以前同窗使用的版本可能出现了不一样, 删掉node_modules文件夹npm i, 解决问题

反思:npm与yarn的锁文件能否用插件兼容
npm: package-lock.json
yarn:yarn.lock
能否作一个小插件把这两种文件类型与数据相互的转换, 我分别看了下这两个文件的格式以下
npm
yarn

文件类型各不相同, 还有一个问题就是这两个工具的源也有差别, 可能会出现某个插件某个版本yarn能够安装, npm里面没有等等问题, 这就致使相似的兼容插件没有大的意义了。
总结
你们仍是暂时老老实实使用过同一种包管理工具把。

7: 厉害的hover

hover思惟的局限
刚入门的时候一个老师给我讲,标签的:hover只能修改这个元素自己与这个元素内部的元素, 因此当时写一个弹出菜单的话须要把这个'标题''弹出框'写在一个div里面, hover这个div的时候弹出框block, 可是其实hover能够选择兄弟元素, 能够选择远方的兄弟元素, 能够给兄弟元素增长条件
举例子

相隔的一个兄弟元素内部的span
<div class="home">
    <div class="main">被hover的元素</div>
    <div class="content">相邻的元素</div>
    <div class="content">
      <span>远处的元素</span>
      <p>我不变色</p>
    </div>
  </div>
.main:hover +.content +.content >span {
      color: red;
    }

8:after变色变文案

需求描述
好比我如今有6种数据类型, 每种类型前面要有一个‘彩色的点’来快速代表他是什么类型以下图:
g.png

要解决的问题

  1. 这种修饰性的结构通常第一想法都是用after和before作。
  2. 圆内的文字须要动态传入
  3. 颜色能动态传入就完美了
  4. 由于这个数据可能上百条,因此不用真实dom颇有必要。
  5. 不能够用js来修改, 由于不想把简单问题弄得复杂,致使代码工程化被破坏。
  6. 模块化,最好其余地方加上一个class名就有了这个效果。

解决问题

  1. 这个要作成模块,中间的文字就要可配,我想到了attr()函数。
  2. 颜色实在没想到动态的传入方式, 只能退而求其次用scss老哥的@each助阵一下了, 还好最多只有6种配色。
  3. 一个class还不够, 须要data-*属性来配合。

上才艺,咳咳不是,是上代码

<div data-color="red"  data-title="1">动漫</div>
    <div data-color="green" data-title="2">小说</div>
    <div data-color="blue" data-title="3">狗狗</div>
*[data-color]::after {
  content: attr(data-title);
  color: white;
  align-items: center;
  display: inline-flex;
  justify-content: center;
  width: 20px;
  height: 20px;
  font-size: 12px;
  margin-left: 10px;
  border-radius: 50%;
}

@each $color in red, green, yellow, blue {
  *[data-color="#{$color}"]::after {
    background-color: $color;
  }
}

注意
attr只能在content中生效。
若是attr不是只能在content里生效就行了,咱们就能够完美解决这一问题,这方面如今也在提案中, 可是暂时没有浏览器支持。

受限于css的本性, 这里并不完美, 颜色方面仍是要传,若是你们有好的方法能够私信讨论一下。

9: 复制也颇有意思

问题描述
咱们前端工程师无时无刻都在与json打交道(或是一个大对象),好比咱们生成了一个很长的json或者是ajax获取到了一段很长的json, 咱们想要把这个json拿出来单独做为一个文件本地引入, 或者是在控制台看着累要拿到某些工具中进行解析,为了提高性能会出现不少..., 除此以外还会出现对象类型须要手动打开等状况, 说实话复制出来不是太方便

原由是一个晨会的知识分享

用鼠标复制仍是处于网民阶段, 成须要确定是利用方法

同窗a:

使用window.copy方法把数据复制到剪切板里面就能够拿到了, 对于开发环节来讲又不用在意兼容性, 这个方法我试了一下也并无长度限制挺好用的。

同窗b:

使用js直接把json数据生成在一个文件里面岂不是更方便, 听到这个的时候就是感受js不是不能够操纵用户的文件系统么。。。 有点打破个人固有认知, 可是试了一下他提供的方法, 还真不错,下面我就介绍一下这个方法与原理:上才艺

(function(console){

  console.save = function(data, filename){

  if(!data) {

  console.error('Console.save: No data')

  return;

  }

  if(!filename) filename = 'console.json'

  if(typeof data === 'object'){

  data = JSON.stringify(data, undefined, 4)

  }

  var blob = new Blob([data], {type: 'text/json'}),

  e = document.createEvent('MouseEvents'),

  a = document.createElement('a')

  a.download = filename

  a.href = window.URL.createObjectURL(blob)

  a.dataset.downloadurl = ['text/json', a.download, a.href].join(':')

  e.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null)

  a.dispatchEvent(e)

  }

})(console)

console.save({a:1})

// 这里是解释版, 每一个语句的意思都详细的解释

(function(console){
  console.save = function(data, filename){
  if(!data) { // 1:没东西没有意义, 大部分多是复制错了
      console.error('Console.save: No data')
     return;
  }
  // 2:名字确定要有个
  if(!filename) filename = 'console.json'

  if(typeof data === 'object'){ // 3:转成字符串
    // 4: JSON.stringify
    // 第一个参数:就是数据了
    // 第二个参数:指定哪些key须要处理, undefined就是都处理
    // 第三个参数: 层级之间的空格缩进数
     data = JSON.stringify(data, undefined, 4)
  }
  // 这个构造函数厉害了: Blob
  // Blob类型的对象表示不可变的相似文件对象的原始数据。
  // Blob对象是二进制数据,但它是相似文件对象的二进制数据,所以能够像操做File对象同样操做Blob对象
  // Blob 表示的不必定是JavaScript原生格式的数据(这句最关键)。File 接口基于Blob
  // 第一个参数是数组, 就是个拼接,这个本身拼也行
  // 第二个参数是配置, 这里咱们指定为json文件
  var blob = new Blob([data,data], {type: 'text/json'}),

  // 自定义一个事件
  e = document.createEvent('MouseEvents'),
  // a标签没什么好说的
  a = document.createElement('a')
  // 必须定义, 不然变成了跳转
  a.download = filename
  // URL就是定义本地路径的api, 咱们作一个上传组件 或是裁剪组件的时候, 会用这种方式展现本地的图片
  a.href = window.URL.createObjectURL(blob)
  // dataset就是获取属性的意思
  // 格式->> text/json:文件名:blob数据
  a.dataset.downloadurl = ['text/json', a.download, a.href].join(':')
  // 咱们的自定义事件配置
  e.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null)
  // 触发咱们的自定义事件
  a.dispatchEvent(e)

  }
})(console)

console.save({a:21},'来段静态文件')

虽然用处真的不大, 可是开阔了思路对将来的变成之路也是有好处的。

end

本次的分享就是这样,我深入的感觉到‘好的解决方法’不少, 最缺乏的是好的问题,欢迎交流, 祝天天进步

相关文章
相关标签/搜索