【svg】前端加载svg图片并更改颜色

6,695 阅读2分钟

主要记录最近做的项目前端加载svg文件并且更改颜色的需求

使用drop-shadow

drop-shadow是css的filter提供的预定义效果的函数,能够输出图像的投影

  1. 与text-shadow和box-shadow不同

text-shadow为容器中的文字提供阴影效果,box-shadow为容器边框提供阴影效果,drop-shadow可以为图片中的图像提供投影效果

  1. 参数 drop-shadow(offset-x offset-y blur color)

为了实现更改颜色的需求,我们可以利用x方向上的偏移使投影图像与原图像不重叠,利用外层容器的overflow属性和图片元素的位置偏移形成更改图片颜色的效果

   <div class="father">
       <img src="./firefox-logo.svg" class="child">
   </div>
.father {
     width: 100px;
     height: 100px;
     overflow: hidden;
 }
 .child {
     transform: translateX(100px);
     filter: drop-shadow(-100px 0px 0px #558ABB);
 }

通过以上代码我们能够获得一个纯色的与原图形状轮廓相同的图片,如下

比较

通过绑定动态css,我们可以实现动态更改图片颜色

  1. 遗憾的是,尝试过使用渐变颜色,但是好像并不支持,也可能是没有用对

使用raw-loader

因为drop-shadow并不支持我们使用渐变的颜色,我们尝试通过raw-loader加载svg源码来实现,所以此方法只支持对于svg图片的颜色修改,而drop-shadow是支持除svg格式之外的png,jpg等格式的图片颜色修改的,两者有利有弊

  1. 思路

这种方法的思路主要是根据svg文件的颜色是通过fill来进行填充的,我们可以通过css对svg中节点的fill属性进行修改,而要实现渐变颜色,则需要定义一个渐变即<linearGradient><radialGradient>并填充

  1. 项目配置 在项目中安装raw-loader依赖,并配置对svg文件使用raw-loader加载,在项目中只需要对一部分svg文件加载源文件,可做类似如下配置

    config.module
      .rule('svgicon')
      .test(/\.(svg)(\?.*)?$/)
      .include.add(path.resolve(__dirname, 'src/assets/images/svg'))
      .end()
      .use('raw-loader')
      .loader('raw-loader')
      .end();
    config.module
      .rule('svg')
      .exclude.add(path.resolve(__dirname, 'src/assets/images/svg'))
      .end()
      .use('file-loader')
      .end();
    
  2. 加载图片

    <div v-html="url" class="my-svg-icon"></div>
    
    url() {
      let icon = '';
      try {
        icon = require(`@/assets/svg/${可变名称}.svg`);
      } catch (e) {
        // 在加载图片出错时加载一张默认图片
        icon = this.defaultImg;
      }
      if (icon.default) {
        icon = icon.default;
      }
      if (icon.includes('</svg>') || icon.includes('.svg')) {
        return icon;
      }
    }
    

    至此我们完成了加载svg文件源码到我们的页面上

  3. 填充颜色 了解过svg的基础知识就知道svg元素具有属性fill,决定元素的颜色,普通纯色可以直接赋值,但是要使用渐变颜色,需先定义渐变再使用

    <svg style="width:0;height:0;position:absolute;" aria-hidden="true" focusable="false">
     <linearGradient id="linearGradient" x2="0" y2="1">
       <stop offset="0%" stop-color="#FFB546" />
       <stop offset="100%" stop-color="#FF9901" />
     </linearGradient>
    </svg>
    
    ::v-deep.my-svg-icon path {
        fill: url(#linearGradient);
     }
    

    在存在很多种渐变方案时我们可以选择把所有渐变写在一个vue文件里,并加载到使用svg的父文件中,避免多次渲染 当然也可以使用js动态生成linearGradient

    比较

2021-03-26