登录
    Technology changes quickly but people's minds change slowly.

前端-svg使用小总结

技术宅 破玉 2414次浏览 0个评论

起因

最近前端在调整大屏,需要把一个弧线的边框调整为多边形框,告诉我说不能做,需要UI切图做边框,我们用的DataV做的,这些人也不知道看看文档,就感觉自己实现不了,无奈,只能我这个后端出手看看了。

修改方法

官网上明确写着“边框均由SVG元素绘制,体积轻量不失真,它们的使用极为方便。”我们扒拉下源码看看
https://github.com/DataV-Team/DataV/blob/master/src/components/borderBox12/src/main.vue
看了下主要代码如下,但是我看不懂

<path
        v-if="width && height"
        :fill="backgroundColor"
        stroke-width="2"
        :stroke="mergedColor[0]"
        :d="`
          M15 5 L ${width - 15} 5 Q ${width - 5} 5, ${width - 5} 15
          L ${width - 5} ${height - 15} Q ${width - 5} ${height - 5}, ${width - 15} ${height - 5}
          L 15, ${height - 5} Q 5 ${height - 5} 5 ${height - 15} L 5 15
          Q 5 5 15 5
        `"
      />

      <path
        stroke-width="2"
        fill="transparent"
        stroke-linecap="round"
        :filter="`url(#${filterId})`"
        :stroke="mergedColor[1]"
        :d="`M 20 5 L 15 5 Q 5 5 5 15 L 5 20`"
      />

      <path
        stroke-width="2"
        fill="transparent"
        stroke-linecap="round"
        :filter="`url(#${filterId})`"
        :stroke="mergedColor[1]"
        :d="`M ${width - 20} 5 L ${width - 15} 5 Q ${width - 5} 5 ${width - 5} 15 L ${width - 5} 20`"
      />

      <path
        stroke-width="2"
        fill="transparent"
        stroke-linecap="round"
        :filter="`url(#${filterId})`"
        :stroke="mergedColor[1]"
        :d="`
          M ${width - 20} ${height - 5} L ${width - 15} ${height - 5}
          Q ${width - 5} ${height - 5} ${width - 5} ${height - 15}
          L ${width - 5} ${height - 20}
        `"
      />

      <path
        stroke-width="2"
        fill="transparent"
        stroke-linecap="round"
        :filter="`url(#${filterId})`"
        :stroke="mergedColor[1]"
        :d="`
          M 20 ${height - 5} L 15 ${height - 5}
          Q 5 ${height - 5} 5 ${height - 15}
          L 5 ${height - 20}
        `"
      />

于是我们再扒拉下 svg 的原理和方法
https://developer.mozilla.org/zh-CN/docs/Web/SVG

可缩放矢量图形(Scalable Vector Graphics,SVG),是一种用于描述二维的矢量图形,基于 XML 的标记语言。作为一个基于文本的开放网络标准,SVG能够优雅而简洁地渲染不同大小的图形,并和CSS,DOM,JavaScript和SMIL等其他网络标准无缝衔接。本质上,SVG 相对于图像,就好比 HTML 相对于文本。

SVG 图像及其相关行为被定义于 XML 文本文件之中,这意味着可以对它们进行搜索、索引、编写脚本以及压缩。此外,这也意味着可以使用任何文本编辑器和绘图软件来创建和编辑它们。

和传统的点阵图像模式,像JPEG和PNG不同,SVG格式提供的是矢量图,这意味着它的图像能够被无限放大而不失真或降低质量,并且可以方便地修改内容。

尽快的解决问题,主要看这一章 https://developer.mozilla.org/zh-CN/docs/Web/SVG/Tutorial/Paths
path只需要设定很少的点,就可以创建平滑流畅的线条(比如曲线),源码中就是用path绘制的,我们就按照这个方法修改下,把弧线改成斜线就行了吧
最终改写组件如下:

<template>
  <div class="dv-border-box-12" :ref="ref">
    <svg class="dv-border-svg-container" :width="width" :height="height">
      <defs>
        <filter :id="filterId" height="150%" width="150%" x="-25%" y="-25%">
          <feMorphology operator="dilate" radius="1" in="SourceAlpha" result="thicken" />
          <feGaussianBlur in="thicken" stdDeviation="2" result="blurred" />
          <feFlood :flood-color="fade(mergedColor[1] || defaultColor[1], 70)" result="glowColor">
            <animate
              attributeName="flood-color"
              :values="`
                ${fade(mergedColor[1] || defaultColor[1], 70)};
                ${fade(mergedColor[1] || defaultColor[1], 30)};
                ${fade(mergedColor[1] || defaultColor[1], 70)};
              `"
              dur="3s"
              begin="0s"
              repeatCount="indefinite"
            />
          </feFlood>
          <feComposite in="glowColor" in2="blurred" operator="in" result="softGlowColored" />
          <feMerge>
            <feMergeNode in="softGlowColored"/>
            <feMergeNode in="SourceGraphic"/>
          </feMerge>
        </filter>
      </defs>

      <path
        v-if="width && height"
        :fill="backgroundColor"
        stroke-width="2"
        :stroke="mergedColor[0]"
        :d="`
          M15 5 L ${width - 15} 5 L ${width - 5}  15
          L ${width - 5} ${height - 15} L ${width - 15}  ${height - 5}
          L 15, ${height - 5} L 5 ${height - 15} L 5 15
          L 5 15
        `"
      />

      <path
        stroke-width="2"
        fill="transparent"
        stroke-linecap="round"
        :filter="`url(#${filterId})`"
        :stroke="mergedColor[1]"
        :d="`M 20 5 L 15 5 L 5 15 L 5 20`"
      />

      <path
        stroke-width="2"
        fill="transparent"
        stroke-linecap="round"
        :filter="`url(#${filterId})`"
        :stroke="mergedColor[1]"
        :d="`M ${width - 20} 5 L ${width - 15} 5 L ${width - 5}  15 L ${width - 5} 20`"
      />

      <path
        stroke-width="2"
        fill="transparent"
        stroke-linecap="round"
        :filter="`url(#${filterId})`"
        :stroke="mergedColor[1]"
        :d="`
          M ${width - 20} ${height - 5} L ${width - 15} ${height - 5}
          L ${width - 5}  ${height - 15}
          L ${width - 5} ${height - 20}
        `"
      />

      <path
        stroke-width="2"
        fill="transparent"
        stroke-linecap="round"
        :filter="`url(#${filterId})`"
        :stroke="mergedColor[1]"
        :d="`
          M 20 ${height - 5} L 15 ${height - 5}
          L 5  ${height - 15}
          L 5 ${height - 20}
        `"
      />
    </svg>

    <div class="border-box-content">
      <slot></slot>
    </div>
  </div>
</template>

<script>
import autoResize from '@jiaminghi/data-view/lib/mixin/autoResize'
import { uuid } from '@jiaminghi/data-view/lib/util/index'
import { deepMerge } from '@jiaminghi/charts/lib/util/index'
import { deepClone } from '@jiaminghi/c-render/lib/plugin/util'
import { fade } from '@jiaminghi/color'
export default {
  name: 'DvBorderBoxMagic',
  mixins: [autoResize],
  props: {
    color: {
      type: Array,
      default: () => ([])
    },
    backgroundColor: {
      type: String,
      default: 'transparent'
    }
  },
  data () {
    const id = uuid()
    return {
      ref: 'border-box-12',
      filterId: `borderr-box-12-filterId-${id}`,
      defaultColor: ['#1C57C2', '#00FFFF'],
      mergedColor: []
    }
  },
  watch: {
    color () {
      const { mergeColor } = this
      mergeColor()
    }
  },
  methods: {
    mergeColor () {
      const { color, defaultColor } = this
      this.mergedColor = deepMerge(deepClone(defaultColor, true), color || [])
    },
    fade
  },
  mounted () {
    const { mergeColor } = this
    mergeColor()
  }
}
</script>

<style lang="less">
.dv-border-box-12 {
  position: relative;
  width: 100%;
  height: 100%;
  .dv-border-svg-container {
    position: absolute;
    width: 100%;
    height: 100%;
    top: 0px;
    left: 0px;
  }
  .border-box-content {
    position: relative;
    width: 100%;
    height: 100%;
  }
}
</style>

另外看了一个老哥的文章,感觉svg很强大,可以后续学习看看吧
最近用几行 SVG 重构了一个之前用 Canvas 写了很多的动画,这里是一篇 SVG 的小分享~https://www.v2ex.com/t/792457#reply19


华裳绕指柔, 版权所有丨如未注明 , 均为原创|转载请注明前端-svg使用小总结
喜欢 (3)
发表我的评论
取消评论
表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址