vue中如何引入自动引入所有svg图标

一.前提

1.要使用 svg 先安装对应的 loader

npm install svg-sprite-loader

注意:
如果按照下面配置正确发现svg依然无法显示可能s’v’g-sprite-loader的版本过高,重新指定版本下载npm i [email protected] --save-dev, 就可能正确显示svg。(vue3.0应该是没有这个问题的)

2.webpack.base.conf.js修改

 {
    
    
        test: /\.svg$/,
        loader: 'svg-sprite-loader',
        include: [resolve('src/assets/icons')],
        options: {
    
    
          symbolId: 'icon-[name]'
        }
      },
      {
    
    
        test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
        loader: 'url-loader',//给图片资源配置路径加载器,用于文件抽离
        exclude: [resolve('src/assets/icons')],
        options: {
    
    
          name: '[name][hash:5].[ext]',//设置抽离打包图片的名称--[ext]用来获取图片的后缀
          limit: 100000,//限制图片大小 <= 100kb 进行base64编码(小于100kb打包进js文件)--测试时根据图片的大小调整
          outputPath: 'image'//设置输出文件夹名称,这个文件夹会与主入口文件在同一路径下
        }
      },

二.图标少的情况:可以手动引入图标

如果只需要引入一个图标,可以手动引入这个图标

<template>
  <div class="twoPage"> 
      <svg class="svg-icon" aria-hidden="true">
        <use xlink:href="#icon-404" />
      </svg>
  </div>
</template>
<script>
import '../assets/icons/404.svg'
export default {
    
    
  data() {
    
    
    return {
    
    };
  },
};
</script>
<style lang="less">
  .svg-icon {
    
    
    width: 1em;
    height: 1em;
    vertical-align: -0.15em;
    fill: currentColor;
    overflow: hidden;
  }
</style>

三.图标多的情况:自动引入

如果引入的svg比较多,手动一个一个引入就比较麻烦,而且没必要

1.下面这个方法就是用来引入所有的文件和文件的名字,在需要的页面调用下面这两个方法就可以了

svgRequire.js

//引入文件夹中的所有.svg 结尾的文件
export function requireAllContext(){
    
    
  const req = require.context('./svg', false, /\.svg$/)
  const requireAll = requireContext => requireContext.keys().map(requireContext)
  return requireAll(req)
}



// 遍历文件夹内子目录,并且引入所有子目录的名字
export function icons(){
    
    
  const req = require.context('../../assets/icons/svg', false, /\.svg$/)
  const requireAll = requireContext => requireContext.keys()
  const re = /\.\/(.*)\.svg/
  const icons = requireAll(req).map(i => {
    
    
    return i.match(re)[1]
  })
  return icons
}

打印:所有文件内容
在这里插入图片描述
打印:所有文件名称
在这里插入图片描述

2.使用:引入上面的两个方法:

<template>
  <div class="twoPage"> 
    <div class="svgBox">
      <div class="svgItem" v-for="item in iconList" >
        <svg class="icon" aria-hidden="true">
          <use :xlink:href="'#icon-'+item"></use>
        </svg>
        <span>{
    
    {
    
    item}}</span>
      </div>
    </div>
  </div>
</template>
<script>
import {
    
    requireAllContext, icons} from '../assets/js/svgRequire'
export default {
    
    
  data() {
    
    
    return {
    
    
      iconList:[]
    };
  },
  created(){
    
    
    //引入所有svg图标内容
    requireAllContext()

    //引入所有图标的名称
    this.iconList = icons()
  },
};
</script>
<style lang="less">
.twoPage{
    
    
  height: 800px;
  .svgBox{
    
    
    width: 500px;
    height: 300px;
    overflow: auto;
    display: flex;
    justify-content: center;
    align-items: center;
    flex-wrap: wrap;
    .svgItem{
    
    
      width: 80px;
      display: flex;
      justify-content: center;
      align-items: center;
      flex-direction: column;
      svg{
    
    
        width: 20px;
        height: 20px;
      }
    }
  }
}

</style>

3.效果

在这里插入图片描述

4.input输入框回显图标和文字

<!-- 表单输入框 -->
<el-input slot="reference" v-model="addMenuForm.remark" placeholder="点击选择图标" readonly>
  <span slot="prefix" v-if="addMenuForm.remark" >
   		<svg class="svg-icon" aria-hidden="true" style="height: 41px;width: 16px;">
      		<use :xlink:href="'#icon-'+addMenuForm.remark" />
   		</svg>
   </span>
 <i slot="prefix" class="el-input__icon el-icon-search" v-else></i>
</el-input>

没选择前:
在这里插入图片描述
选择后:
在这里插入图片描述

5.整体代码:

html

                <el-form-item label="菜单图标" prop="remark">
                  <!-- 弹窗下拉 -->
                  <el-popover placement="bottom-start" width="400" trigger="click" class="menuAddSvg">
                     <!-- 表单输入框 -->
                    <el-input slot="reference" v-model="addMenuForm.remark" placeholder="点击选择图标" readonly>
                      <span slot="prefix" v-if="addMenuForm.remark" >
                        <svg class="svg-icon" aria-hidden="true" style="height: 41px;width: 16px;">
                          <use :xlink:href="'#icon-'+addMenuForm.remark" />
                        </svg>
                      </span>
                      <i slot="prefix" class="el-input__icon el-icon-search" v-else></i>
                    </el-input>

                    <!-- 下拉内容 -->
                    <div class="icon-body">
                      <el-input v-model="name" style="position: relative;" clearable placeholder="请输入图标名称" @keyup.native="keyUpSvg(name)">
                        <i slot="suffix" class="el-icon-search el-input__icon" />
                      </el-input>
                      <div class="icon-list">
                        <div v-for="(item, index) in iconList" :key="index" @click="checkSvg(item)">
                          <svg class="svg-icon" aria-hidden="true" style="height: 30px;width: 16px;">
                            <use :xlink:href="'#icon-'+item" />
                          </svg>
                          <span>{
   
   { item }}</span>
                        </div>
                      </div>
                    </div>
                   
                  </el-popover>
                </el-form-item>

js:
通过document.body.click()关闭el-popover的弹窗

        //模糊搜索选择svg
        keyUpSvg(item){
    
    
          let list = this.iconAllList.filter(icon => {
    
    
            return icon.indexOf(item)>-1
          })
          this.iconList = list
        },
        //选择svg
        checkSvg(item){
    
    
          this.addMenuForm.remark = item;
          document.body.click()
        }

    created(){
    
    
      this.iconList = icons();
      this.iconAllList = icons();//备份一个完整的数据,避免后面输入框清空,iconList为空数组后,没有完整数据       
    }

css:

.svg-icon {
    
    
  width: 1em;
  height: 1em;
  vertical-align: -0.15em;
  fill: currentColor;
  overflow: hidden;
}
.icon-body {
    
    
    width: 100%;
    padding: 10px;
    .icon-list {
    
    
      height: 200px;
      overflow-y: scroll;
      div {
    
    
        height: 30px;
        line-height: 30px;
        margin-bottom: -5px;
        cursor: pointer;
        width: 33%;
        float: left;
      }
      span {
    
    
        display: inline-block;
        vertical-align: -0.15em;
        fill: currentColor;
        overflow: hidden;
      }
    }
  }

四.优化

我也是使用的时候感觉上面的方法还是有些麻烦,有的页面如果需要两三个svg图标的时候,要么在当前页面把所有svg都引入进来,要么手动一个一个引入图标。像下面这样,就很恶心!!!!
在这里插入图片描述

所以我们需要把所有的svg引入到全局,通过main.js引入一下,那样整个项目都可以用了这些svg,随时可取用。

1.index.js文件

在这里插入图片描述
直接调用引入svg文件夹内的.svg文件,而不是写成方法,方法必须指定页面调用才在指定页面成效。

//引入文件夹中的所有.svg 结尾的文件
// export function requireAllContext(){
    
    
//   const req = require.context('./svg', false, /\.svg$/)
//   const requireAll = requireContext => requireContext.keys().map(requireContext)
//   return requireAll(req)
// }

// 1.
//上面的方法是需要在指定的页面的调用这个方法,才能获取到svg。
//下面的方法是直接调用获取svg,后面在main.js里面直接引入这个Index.js即立即调用
const req = require.context('./svg', false, /\.svg$/)
const requireAll = requireContext => requireContext.keys().map(requireContext)
requireAll(req)


// 2.遍历文件夹内子目录,并且引入所有子目录的名字
export function icons(){
    
    
  const req = require.context('../../assets/icons/svg', false, /\.svg$/)
  const requireAll = requireContext => requireContext.keys()
  const re = /\.\/(.*)\.svg/
  const icons = requireAll(req).map(i => {
    
    
    return i.match(re)[1]
  })
  return icons
}

// 3.全局挂载SvgIcon组件
import Vue from 'vue'
import SvgIcon from '@/components/SvgIcon'// svg component

Vue.component('svg-icon', SvgIcon)

2.main.js

引入icons文件夹内的index.js

import './assets/icons'

3.这样的话,需要的页面就可以直接使用也会生效,而不需要引用什么文件和svg

<svgIcon icon="component"></svgIcon>

猜你喜欢

转载自blog.csdn.net/qq_39928481/article/details/124297845
今日推荐