lulu_up

lulu_up 查看完整档案

上海编辑辽宁工程技术大学  |  电气__采矿 编辑360  |  前端爱好者 编辑 zhangzhaosong.com/ 编辑
编辑

自信自律, 终身学习.
躬身入局, 皆为吾辈.

个人动态

lulu_up 发布了文章 · 10月15日

记一次前端SVG实战知识分享会

记一次前端SVG实战知识分享会

记录了我在组内的技术分享, 有同样需求的同学可以参考一下
分享全程下来时间大约 40分钟

image

一. svg与前端工程师

1. 作为一名前端工程师不可能不与svg打交道, 如今掌握svg的基本知识是咱们的基本技能.
2. 学svg之前最好先学一学xml的基本知识, 这样可以更好的理解文件结构.
3. svg是很不错, 但是并不是任何地方都要使用, 学习不要太刻板.

本篇重点是基础知识, 希望您看完之后可以对svg做出一些简单的修改, 或者是一个小图片不用再等ui做完给我们, 我们可以自己动手制作.

二. xml简介 (不会说的太详细)

XML 被设计用来传输和存储数据, 指可扩展标记语言(_EX_tensible _M_arkup _L_anguage)
HTML 被设计用来显示数据。

这个头部标签 <?xml version="1.0" standalone="no"?>
  1. XML标准文件头
  2. 版本号是1.0
  3. standalone代表这个xml文件是独立的还是依赖与外部dtd文件的 (作用是定义 XML 文档的合法构建模块) 类似java中的接口.
现在很多配置文件还是用xml的形式比如java代码, 这些配置文件应该是用json更好.

三. svg简介

SVG 是使用 XML 来描述二维图形和绘图程序的语言。(节选自w3school)

  • SVG 指可伸缩矢量图形 (Scalable Vector Graphics)
  • SVG 用来定义用于网络的基于矢量的图形
  • SVG 使用 XML 格式定义图形
  • SVG 图像在放大或改变尺寸的情况下其图形质量不会有所损失
  • SVG 是万维网联盟的标准
  • SVG 与诸如 DOM 和 XSL 之类的 W3C 标准是一个整体
  1. 什么是矢量, 矢量图形: 面向对象的图像或绘图图像,在数学上定义为一系列由线连接的点, 一个一个的图形对象, 任意的组合.

矢量图介绍短片

  1. 不失真属于老生常谈的问题了, 其实在我看来svg图片可以被我们随便修改他的样式才是最重要的, 毕竟一个png文件不好通过代码修改他的背景色, 或是某一块的大小比例.
  2. 缺点: 在window系统里, 没有图例显示不方便查看, 在mac电脑里就有个缩略图, 没找照一张图片还要把svg全打开挨个找...

<svg width="500" height="500" version="1.1"
xmlns="http://www.w3.org/2000/svg">

  1. 定义了svg的宽高
  2. 定义了使用1.1版本svg, 就像html一样有 4与5, svg的版本也在变化.
  3. xmlns是xml namespace的缩写,也就是XML命名空间,xmlns属性可以在文档中定义一个或多个可供选择的命名空间。该属性可以放置在文档内任何元素的开始标签中。该属性的值类似于URL,它定义了一个命名空间,浏览器会将此命名空间用于该属性所在元素内的所有内容。

例如SVG< a>元素和HTML< a>如果一个被称为svg:a和另一个html:a,则可以区分该元素, 作用就是防止svg标签内的元素与html元素混乱一团.
html5中不写这句影响也不大.

兼容性如下

image

四. 基本图形

  • svg有很多基本图形如: 矩形、圆形、直线、多点成线、多边形.
  • 这些图形我们可以直接使用
<?xml version="1.0" standalone="no"?>
<!-- 1: 整体的长宽, 规则定义  -->
<svg width="500" height="500" version="1.1"
xmlns="http://www.w3.org/2000/svg">
<!-- 1:矩形 -->
<!-- x, y 左上角的位置 -->
<!-- fill: 填充的颜色 -->
<rect  width="100" height="100" style="x:20; y:20;" />

<!-- 1:圆形 -->
<!-- 2: cx,cy 圆心的坐标 -->
<!-- 3: r半径 -->
<circle cx="70" cy="220" r="50" fill="red"></circle>


<!-- 3: 直线 -->
<!-- 两个点的坐标 -->
<line x1="160" y1="80" x2="300" y2="80" style="stroke:green;stroke-width:16;"></line>

<!-- 4: 多点线 -->
<!-- 会自动把第一个点与最后一个点连接起来 -->
<!-- points:一组一组的xy坐标 -->
<polyline points="500,60 330,60 420,180"></polyline>

<!-- 5: 多边形 -->
<polygon points="470,400 450,320 410,320 410,340 410,440" style="fill:red;stroke:red;stroke-width:2"></polygon>
</svg>

如图所示:

image

  1. 这里的宽高与xy的距离你可以按px理解, 但其实这个是他的比例, 使用的时候会按这个比例等比缩放.
  2. style="stroke:green;stroke-width:16;" 定义: 如果在线内定义的是 线条的颜色为绿色, 线的宽度为16
  3. style="fill:red;stroke:red;" fill指的是填充颜色, stroke边的颜色(有时候我面试的同学说经常使用svg, 但是fill属性都不知道, 场面很尴尬.)
  4. style并不是绝对的, 比如第一个矩形我也可以写成<rect width="100" height="100" x="20" y="20" />
  5. 一起其他属性: transform="rotate(30)" 旋转角度,这里不用写deg, rx:20;ry:60; 角的弧度可以做矩形的圆角.
  6. 知道了svg无非也就是个dom那我们就可以通过获取元素的形式进行对svg内部图像的修改了, 比如获取到这个svg里面的矩形setAttribute('x', 200)让他x轴变为200

五. 视野与视框

<?xml version="1.0" standalone="no"?>

<!-- 1: 视野 -->
<!-- viewBox: 我能看到哪一部分, 当前就是左上角 -->
<!-- viewBox就算小了, 但是整体的宽高是不变的, 所以会有放大缩小效果 -->
<!-- 2: 如果viewport和viewBox的宽高比不相同。你需要自己来指定如何在SVG阅读器(如浏览器)中显示SVG图像。你可以在<svg>中使用preserveAspectRatio属性来指定。 -->
<!-- preserveAspectRatio   meet就是保持原比例不失真-->
<svg width="500" height="500" version="1.1"
xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 100" preserveAspectRatio="none meet">
<rect 
  width="200" height="200"
  style="x:20; y:20; rx:20;ry:60; fill:rgb(0,0,255);stroke-width:16;
stroke:black"/>

</svg>

1: 不设置viewBox
image

2: 设置后
image

viewBox不影响整体svg的大小与比例, 只是以多大的窗口展示这个svg图片

六. 样式分组(事情变得有趣了)

任何形式的代码都存在如何复用的问题, 我们不可能在画出一个不规则图形然后想再画一个一模一样的图形时, 重新画一遍
下面是复用"样式", 在g标签里面写上样式, 内部的标签会默认使用.

神奇的 g 标签

<?xml version="1.0" standalone="no"?>
<!-- 1: <g>标签分组了, 就有面向对象的概念了 -->
<svg width="500" height="500" version="1.1"
xmlns="http://www.w3.org/2000/svg">
<!-- 定义了整体的属性 -->
<!-- 2: 可以多层嵌套替换 -->
<g style="fill:rgb(0,0,255);stroke-width:16">
  <rect 
    width="100" height="100"
    style="x:20; y:20; rx:20;ry:60;
  stroke:black"/>

  <rect 
    width="100" height="100"
    style="x:20; y:140; rx:20;ry:60;
  stroke:black"/>
</g>
</svg>

效果如下图, 一模一样的两个图形
image

当然<g>标签也可以嵌套使用
<?xml version="1.0" standalone="no"?>
<svg width="500" height="500" version="1.1"
xmlns="http://www.w3.org/2000/svg">
<g style="fill:rgb(0,0,255);stroke-width:16">
  <rect 
    width="100" height="100"
    style="x:20; y:20; rx:20;ry:60;
  stroke:black"/>

  <rect 
    width="100" height="100"
    style="x:20; y:140; rx:20;ry:60;
  stroke:black"/>
  
  <g style="fill:red;stroke-width:16">
    <rect 
      width="100" height="100"
      style="x:20; y:260; rx:20;ry:60;
    stroke:black"/>
  </g>
</g>
</svg>

如图:
image

七. 复用

我画好的图形, 我当然可以复制一份继续使用啦

使用<use>标签进行引用图形, 并且在use标签上进行新图形的操作, 可以直接设置xy之类的东西.

<?xml version="1.0" standalone="no"?>
<svg width="500" height="500" version="1.1"
xmlns="http://www.w3.org/2000/svg">
  <g id="cc">
    <rect width="100" height="100" x="20" y="20" />
  </g>
 <use xlink:href="#cc" transform="translate(160,0)" fill="red"/>
</svg>

这里可能会出现作用域的问题, 但是放在html里面就没问题了
后面会讲问什么放在html里面会好, 已经如何解决这个问题!!!
有问题的同学可以用下面的代码

<!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>
<svg width="500" height="500" version="1.1"
xmlns="http://www.w3.org/2000/svg">
  <g id="cc">
    <rect width="100" height="100" x="20" y="20" />
  </g>
 <use xlink:href="#cc" transform="translate(160,0)" fill="red"/>
</svg>
</body>
</html>

效果如下:
image
image

玩到这里是不是有些.svg里面的代码在干什么已经能看懂小半了!!! 这就是会的越多越开心.

八. 渐变

<?xml version="1.0" standalone="no"?>

<svg width="500" height="500" version="1.1"
xmlns="http://www.w3.org/2000/svg">

  <!-- 1: 定义了一组渐变, 设置id方便引用 -->
  <defs>
      <!-- 这里指定了渐变的区域, 1-0的范围 -->
      <linearGradient id="orange_red" x1="0%" y1="0%" x2="100%" y2="0%">
      <stop offset="0%" style="stop-color:rgb(255,255,0);
      stop-opacity:1"/>
      <stop offset="100%" style="stop-color:rgb(255,0,0);
      stop-opacity:1"/>
      </linearGradient>
  </defs>
  <!-- 1: 引入相应的渐变颜色 -->
  <ellipse cx="200" cy="190" rx="85" ry="55"
  style="fill:url(#orange_red)"/>

</svg>
  1. <defs>里面定义了一组渐变规则, 因为xml只能所有都用标签标示, 你可以理解为这个定义了个类.
  2. <defs>标签里面定义的内容是不展示的
  3. <linearGradient> 线性渐变标签, <radialGradient>放射性渐变标签(这个原理都一样)
  4. <stop> 规定了n%的位置的颜色
  5. <ellipse> 是用来做椭圆的

如图所示:
image

九. 填充

<?xml version="1.0" standalone="no"?>

<svg width="500" height="500" version="1.1"
xmlns="http://www.w3.org/2000/svg">
<!-- 1: 定义填充类 -->
<defs>
<!-- 2: 内容写在这里 -->
<pattern id="cc" x="0" y="0" width="0.2" height="0.2">
   <circle cx="10" cy="10" r="10" fill="red">
   </circle>
</pattern>
</defs>
  <rect 
    width="400" height="400"
    fill="url(#cc)"
    style="x:20; y:20; rx:60;ry:60;stroke:black"/>
</svg>
  1. <pattern> 填充功能的标签
  2. 这里你可以理解为div的背景图案, 但是没有设置 background-repeat: no-repeat;

如图所示:
image

十. path的用法(可以一口气画的好长好长...)

<?xml version="1.0" standalone="no"?>

<svg width="600" height="600" version="1.1"
xmlns="http://www.w3.org/2000/svg">
<!-- 1: 把path当成一支画笔, path就是一气呵成的绘制操作 -->
<!-- 2: M 是移动的xy  m是移动的相对距离 c是curveto曲线图 -->
<!-- 3: L画直线 -->
<path d="M153 334
C153 334 151 334 151 334
C151 339 153 344 156 344
C164 344 171 339 171 334
C171 322 164 314 156 314
C142 314 131 322 131 334
C131 350 142 364 156 364
C175 364 191 350 191 334
C191 311 175 294 156 294
C131 294 111 311 111 334
C111 361 131 384 156 384
C186 384 211 361 211 334
C211 300 186 274 156 274"
style="fill:white;stroke:red;stroke-width:2"/>

</svg>
  1. <path>标签类似一气呵成的画笔, 里面会有超多绘制操作, 有了这个标签就可以很方便的封装绘制svg的编辑器了.
  2. M153 334 的意思就会在坐标为153 334的点上绘制
  • M = moveto
  • L = lineto
  • H = horizontal lineto
  • V = vertical lineto
  • C = curveto
  • S = smooth curveto
  • Q = quadratic Bézier curve
  • T = smooth quadratic Bézier curveto
  • A = elliptical Arc
  • Z = closepath

如图所示:
image

简单的也有

<?xml version="1.0" standalone="no"?>
  <svg width="600" height="600" version="1.1"
xmlns="http://www.w3.org/2000/svg">
  <path d="M150 0 L75 200 L225 200 Z" />
</svg>
  1. M150 0 绘制起始点坐标
  2. L75 200 连线到75 200
  3. L225 200 连线到255 200
  4. Z 结束绘制, 提笔.

如图所示:
image

十一. 文本输入

怎么可能少了文字的输入
<?xml version="1.0" standalone="no"?>
<svg width="500" height="500" version="1.1"
xmlns="http://www.w3.org/2000/svg">
<!-- 1: 理论上svg并不是一个专业处理文字的载体 -->
<!-- 2: style标签可以使用大部分css属性啦, 不用要px -->
<!-- 3: xy对应的是左下角的基线, 而不是完美的左下角 -->
<!-- 4: 文字的颜色也要放在fill属性里面, 这也更符合工程化 -->
<text x="200" y="200" style="font-size:26;" fill="red">蚊子蚊子1</text>
<!-- 5: 针对里面每一个字符设置距离 -->
<!-- dx dy 具体到每个文字的距离 -->
<!-- 那么我其实可以巧用svg来搞点花里胡哨的 -->
<!-- 用波浪形画个❤ -->
<!-- 再加上动画效果, 就是扭动起来的文字啦 -->
<text x="200" y="300" dx="0 20 60 " dy="0 20 40" style="font-size:26;" fill="blue">蚊子蚊子2</text>

<!-- tspan标签对文字的单独处理(含镂空!!!!) -->
<text x="200" y="100" style="font-size:40">
  <tspan fill="red">蚊子3</tspan>
  <tspan stroke="blue" fill="none">蚊子4</tspan>
  </text>
</svg>
  1. <text>标签用来表示文字
  2. dx定义每个文字之间的间距
  3. <tspan> 就是<text>里面单独处理字符的标签
  4. fill="none" 就可以产生扣动字了

如图所示:
image

十二. 路径文本(让你的文字沿着路径排列而已)

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8"/>
<title>textpath</title>
</head>
<body>
<svg xmlns='http://www.w3.org/2000/svg' width='800' height='600'>
    <path id="path1" d='M 100 200 Q 200 100 300 200 T 500 200' stroke='rgb(0,255,0)' fill='none'>
    </path>
    <text style='font-size:24px;'>
        <textpath xlink:href='#path1'>
            学来学去学来, 你还学得动吗哈哈哈!!
        </textpath>
    </text>
</svg>
</body>
</html>
  1. 上面使用的path标签赋予颜色是为了让大家看清文字走向
  2. <textpath>标签需要引用一个走向(从此以后你可以画出各种线路的文字, 是不是可以秀给女朋友看??)
  3. fill='none'很重要, 不然他会变成面积图

    去掉 fill='none':
    image

    加上 fill='none:
    image

    加上这个就可以不用在html文件中才能显示了, 也就是规定了作用域

<?xml version="1.0" standalone="no"?>
<svg width="500" height="500" version="1.1"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> 
<defs>
  <path id="my" d="M 100 200 Q 200 100 300 200 T 500 200" />
</defs>
<text x="10" y="200" style="font-size:26" fill="red">
 <textPath xlink:href="#my">
 学来学去学来, 你还学得动吗哈哈哈!!
 </textPath>  
</text>
</svg>
  1. xmlns:xlink= 属性规范了作用域
  2. 这意味着文档可访问 XLink 的属性和特性,表示前缀为xlink的元素应该由理解该规范的UA使用xlink规范来解释, 你可以理解为不与html冲突了.

十三. svg的引入(直接写svg, <embed> <object> <iframe>标签引入, 其实img也可以的 )

使用svg可不只是把svg放在html结构中

  1. 直接写在html中, 这个我上面演示过,
  2. <embed> 标签是 HTML 5 中的新标签, 标签定义嵌入的内容,也就相当于把svg结构直接插进来了。
  3. <object> 标签是 HTML 4 的标准标签,被所有较新的浏览器支持。它的缺点是不允许使用脚本, 向 HTML 代码添加一个对象, 感觉可用于服务端渲染的项目快速取得数据。
  4. iframe都快被淘汰了就别用了, 这里也不说用法了.
<!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>
  <!-- 1: 这个为啥网上没人说? -->
  ![](./2.基本图形.svg)
  <!-- 2: embed标签引入 -->
  <embed id="cc" data-original="./2.基本图形.svg" width="500" height="500"
  type="image/svg+xml"
  pluginspage="http://www.adobe.com/svg/viewer/install/" />
  <!-- 3: object -->
  <object data="./2.基本图形.svg" width="300" height="100" 
  type="image/svg+xml"
  codebase="http://www.adobe.com/svg/viewer/install/" />
</body>
</html>

十四. 做图工具

  1. SVG.js 官网
  2. Adobe Illustrator 官网
  3. 菜鸟工具

十五. 实际应用时如何破话svg的比例

还是要单独强调一下, svg有自己的比例, 但是如果你的项目需要把svg图片撑满容器的时候, 你就要在svg标签上设置preserveAspectRatio="none meet", 否则是不允许破话svg比例的.(也可直接preserveAspectRatio ="none")

end 结束

svg不是前端工程师的必修课, 同时也不是一门必须使用的技术, 不要听说svg好就强制使用,我们要知道它好在哪,怎么用更好才行.
但通过学习svg的相关知识可以使我们可以靠自己做出更多绚丽的东西, 也会扩充很多有趣的知识点, 铸造我们更好的思维与知识体系.
这次就是这样, 希望和你一起进步.

查看原文

赞 15 收藏 10 评论 3

lulu_up 回答了问题 · 10月14日

解决移动端如何监听键盘值?

1: 手机可以专门呼出纯英文的键盘
2: 可以用正则对用的输入进行校验, 给出合理提示
3: 统一在提交的时候校验一次, 弹出他输入的不合法让重新填

关注 3 回答 2

lulu_up 回答了问题 · 10月13日

解决怎样让这个遮罩层不能拖动?

换个定位方式试试 position: fixed;

关注 2 回答 1

lulu_up 回答了问题 · 10月10日

解决js时间以10分钟向上取整

其实你可以这样想, 你的目的是吧最后一位变成0:
2020-10-10 11:1x (最后的分钟是x) 也就是这x必须是0, 那么你可以试试每次获得当前毫秒然后 加1分钟然后再取的对应的分钟, 直到x为0了就输出这个时间.

关注 3 回答 3

lulu_up 回答了问题 · 10月9日

请问怎么用css做出这个边框图形

你可以自己画一个svg, 这个编辑器就可以, https://c.runoob.com/more/svg...
当然这种问题按理说交给ui画好给你就行.

关注 5 回答 4

lulu_up 回答了问题 · 10月4日

vuejs中cookie的问题

这种一般在请求方法里面, 比如后端校验失效给你返回401或者303, 你根据状态码进行登录页的跳转

关注 2 回答 1

lulu_up 回答了问题 · 9月18日

解决vue 实现扫描条形码获取数据,项目不是app,是公众号网页

是在不行可以曲线救国, 把图片传给后端, 你拿到解析好的结果进行跳转

关注 4 回答 3

lulu_up 回答了问题 · 9月16日

不同的项目,前端在请求后端接口的时候想携带同一个cookie ,如何操作呢?

同源并且cookie放在path=''下 理论上没问题的, 你遇到了什么困难?

关注 4 回答 3

lulu_up 回答了问题 · 9月13日

前端的token到底该存到哪里?

localstorage安全一点点点, 这样可以减少一些csrf攻击

关注 4 回答 3

lulu_up 回答了问题 · 9月10日

element-ui源码为什么把css抽离出来

行, 本来就不是必须的, 不要局限思维
作者团队无非看重这样做的优点而已,而且element-ui的整体代码结构在工程化上有一点点不舒服, 主要看里面的逻辑代码的,有的点还都挺巧妙的

关注 3 回答 2

lulu_up 回答了问题 · 9月3日

css 样式求教

最简单的就是放这样一张白色的图片

关注 6 回答 4

lulu_up 回答了问题 · 9月2日

解决flex布局中计算元素宽度的问题

flex:195 flex:11 flex: 9 让系统自己去算

关注 4 回答 3

lulu_up 发布了文章 · 8月24日

第四期:前端九条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:

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

查看原文

赞 15 收藏 12 评论 3

lulu_up 回答了问题 · 8月20日

解决如何将数组[1,2,3,5,6,7]改为字符串"1-3点,5-7点"形式?

给你个好理解, 直接粗暴的

 <script>
    const res = [1,2,3,4,7,8,9,11,12];
    const len = res.length;
    let i = 1, str=[], n=res[0] ;
    let arr = n + '';
    // 1: 形成一个数组["1,2,3,4", "7,8,9", "11,12"]
    while(i<len){
      if(res[i] === n+1){
       arr += ',' + res[i]
      }else{
        str.push(arr);
        arr = res[i]
      }
      if(i===len-1){
        str.push(arr + '');
      }
      n = res[i];
      i++;
    }
    // 2: 分割一下就ok了
    console.log(str)

    let endStr = '' 
    str.forEach((item)=>{
      const splititem = item.split(',');
      if(splititem.length > 1){
        endStr += `${splititem[0]}点-${splititem[splititem.length-1]}点; `
      }else{
        endStr += `${splititem[0]}点; `
      }
    })
    console.log(endStr)

  </script>

关注 4 回答 3

lulu_up 报名了系列讲座 · 8月13日

从0构建私有前端监控系统

> 新增Chrome 85版本开始支持的LCP和CLS指标采集原理和采集方法课时 **为什么要做前端监控** 前端监控是业务生产必不可少的重要技术设施,通过线上数据采集反馈形成业务闭环,能够帮助业务及时发现问题、定位问题、处理问题。出现问题时及时发现,减少业务损失。也可以帮助业务采集用户数据、分析用户画像,更精确了解业务诉求,解决客户问题。 前端监控是重要的业务数据来源,通过数据的角度分析问题,不仅能作为问题分析依据,也可以从统计学角度、行为学角度分析业务,创造更大的业务价值。本课程介绍的是一种简单高效、自主灵活的快速搭建可生产使用的前端监控体系。 **自主监控数据采集** 市面上大部分是结合开源监控做的监控系统,性能和自由度受限。本课程讲解前端监控设计架构,各个监控项采集数据的原理,手把手和你一起编写监控采集脚本,具有自主性和灵活的业务扩展能力。 **打造可视化数据分析大盘搭建** 介绍数据分析思维,讲解如何从数据角度发现、分析、定位问题。结合阿里云SLS日志服务分析监控数据,构建可视化数据分析大盘,分析业务数据。 **实时监控警告系统搭建** 从业务角度出发,基于稳定性和性能体验,构建业务大盘,根据数据情况构建稳定性和体验相关数据监控告警,基于邮件、钉钉、电话等准实时告警到业务,及时发现问题。 **必备技能,面试必问,必要知道的那些事** 前端开发和其他职业一样,总是要分出369等。技术深度和广度,从一些细节就能看出。前端监控也是从高级工程师进阶到专家级别工程师必备的技能。软实力是了解业务场景、技术价值,了解采集各个指标的方法和用处,怎么为业务服务,怎么转化成有用的生产数据。硬技能是能够从0到1,独立自主研发、搭建这么一套监控系统,能够满足业务个性化诉求,解决业务问题。 ### 讲师介绍 **扫地僧 - 高级技术专家** 前阿里、网易前端技术专家,负责流程驱动引擎、可视化搭建、前端发布、构建平台等技术能力建设,带领业务团队,负责整体业务线。 ### 课程大纲 **前端监控架构设计** - 课时1:为什么要做前端监控? - 课时2:前端监控什么数据? - 课时3:前端监控架构设计 **编写监控采集脚本** - 课时4:设计监控上报数据模型 - 课时5:开通 SLS 日志服务 - 课时6:如何通过 webTrack 上报数据 - 课时7:JS 错误和资源采集 - 课时8:接口错误采集 - 课时9:白屏错误统计方法和代码 - 课时10:页面加载时间计算方法和代码实现 - 课时11:FP/FCP/FMP/FID 时间原理介绍 - 课时12:FP/FCP/FMP/FID 时间代码实现 - 课时13:卡顿原理和采集代码实现 - 课时14:TBT 体验指标计算原理 - 课时15:PV 和自定义指标采集 - 课时16:TTI(首屏可交互时间)指标采集 - 课时17:LCP(最大区块渲染时间)计算原理和指标采集 - 课时18:CLS(页面累计位移)计算原理和指标才采集 - 课时19:TBT(首屏总阻塞时间)计算原理和指标才采集 **数据分析大盘** - 课时20:如何做数据查询和可视化 - 课时21:搭建可视化数据大盘 - 课时22:参数化数据查询与大盘构建 **数据监控告警** - 课时23:监控和告警的区别 - 课时24:设置 JS 同步增长告警 - 课时25:告警准确性问题

lulu_up 回答了问题 · 8月13日

解决input中没有设定v-bind、v-model、ref属性,是怎么获取vue中input的数据?

按class获取可以么, 或者按标签获取, 然后判断dom身上的属性进行获取

关注 3 回答 3

lulu_up 回答了问题 · 7月14日

vue react 开发环境有提示 生产环境没有提示 是如何实现的?

这种功能其实可以打包时候实现, 直接不把报错模块打包进去就好了

关注 5 回答 4

lulu_up 回答了问题 · 7月10日

vue router

晒晒代码吧, 听起来像需要给路由加个随机的key, 或者router-view写的有问题, 或者是全局的router拦截器, 这个不好猜需要看看你代码

关注 4 回答 3

lulu_up 回答了问题 · 7月6日

解决前端的未来方向

花点时间把前端钻一钻, 然后学服务端知识, 有个侧重点就会学的很有动力

关注 6 回答 4

lulu_up 回答了问题 · 7月3日

前端如何实现游戏地图定位并切换的功能

geojson画地图, 比例不会失调, 还可以分成中心点绘制与经纬度绘制, 每个区域都有相应的点击事件.

关注 3 回答 1