改版

235 阅读4分钟

目录结构

├── build                      // 构建相关  
|
├── src                        // 源代码
│   ├── api                    // 所有请求
│   ├── assets                 // 主题、字体等静态资源
│   ├── components             // 全局公用组件
│   ├── icons                  // 项目所有 svg icons
│   ├── router                 // 路由
│   ├── store                  // 全局 store管理
│   ├── styles                 // 全局样式
│   ├── utils                  // 全局公用方法
│   ├── views                   // view
│   ├── App.vue                // 入口页面
│   └── main.js                // 入口 加载组件 初始化等
│   
├── .babelrc                   // babel-loader 配置
├── eslintrc.js                // eslint 配置项
├── .gitignore                 // git 忽略项
├── favicon.ico                // favicon图标
├── index.html                 // html模板
├── package-lock.json          // 1、锁定安装时的包的版本号,需要上传到git,保证大家的依赖包一致。
|                              // 2、package-lock.json是在npm install时候生成一份文件,用来记录当前状态下实际安装的各个npm
├── package.json               // package.json
└── vue.config.js              // vue.config.js是一个可选的配置文件,如果项目的 (和 package.json 同级的) 根目录中存在这个文件,那么它会被 @vue/cli-service 自动加载。

关于vue-cli、@vue/cli安装node包

在package.json文件中
安装devDependencies下的依赖时,使用命令:npm install XXX -D (等同于--save-dev)
安装dependencies下的依赖时,使用命令:npm install XXX -S (等同于--save)

组件拆分

一、引入SvgIcon组件

前言:我们在components文件下创建SvgIcon组件,在src/下创建icons文件夹,icons下创建svg文件放置网站使用的所有svg图标,创建index.js用于引入components下的SvgIcon组件,创建svgo.yml用于svg压缩处理优化功能。

① svg压缩处理优化功能,是基于svgo实现(参考:Svgo是如何压缩处理svg无用信息的),首先我们安装svgo和svg-sprite-loader

1、安装svgo
npm install svgo -D
2、安装svg-sprite-loader
npm install svg-sprite-loader -D

我们很多网上下载或者 Sketch/Ps等设计软件 导出的 svg 会有很多冗余无用的信息,大大的增加了 svg 的尺寸,我们可以使用 svgo 对它进行优化。比如下图是有 Sketch 导出的一个 svg。

利用svgo对svg内容进行压缩,我们可以执行npm run svgo

// 在package.json scripts上加入svgo
"svgo": "svgo -f src/icons/svg --config=src/icons/svgo.yml"

执行后,svg成功的压缩,下图所示。

无用的信息都被处理掉了。

更多详细的配置 可以在 /scr/icons/svgo.yml中进行配置。


② svg-sprite-loader的工作原理是: 利用svg的symbol元素,将每个icon包括在symbol中,通过use元素使用该symbol。

如果您对此不了解,可以阅读张鑫旭老师的这篇文章

这里简单一点的解释就是,最终你的svg icon会变成下面这个样子的 svg 雪碧图:

<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="__SVG_SPRITE_NODE__">
    <symbol class="icon" viewBox="0 0 1024 1024" id="icon名">{{省略的icon path}}</symbol>
    <symbol class="icon" viewBox="0 0 1024 1024" id="icon名">{{省略的icon path}}</symbol>
</svg>

你的每一个icon都对应着一个symbol元素。然后在你的html中,引入这样的svg, 随后通过use在任何你需要icon的地方指向symbol:

<use xlink:href="#symbolId"></use>

这个过程中,我们可以把symbol理解为sketch中内置的图形,当你需要使用的时候,把这个形状”拖拽”到你的画板中就行了。而use就是这个过程中的”拖拽”行为。


③ 配置vue.config.js文件(参考:vue cli3.0使用svg全过程

webpack 配置,在Vue.config.js加入处理 svg 的 loader

const path = require('path')
function resolve (dir) {
  return path.join(__dirname, '.', dir)
}
module.exports = {
  chainWebpack: config => {
    config.module.rules.delete('svg') // 重点:删除默认配置中处理svg,
    // const svgRule = config.module.rule('svg')
    // svgRule.uses.clear()
    config.module
      .rule('svg-sprite-loader')
      .test(/\.svg$/)
      .include
      .add(resolve('src/icons')) // 处理svg目录
      .end()
      .use('svg-sprite-loader')
      .loader('svg-sprite-loader')
      .options({
        symbolId: 'icon-[name]'
      })
  },
}

④ 开始写SvgIcon组件

<template>
  <div v-if="isExternal" :style="styleExternalIcon" class="svg-external-icon svg-icon" v-on="$listeners" />
  <svg v-else :class="svgClass" aria-hidden="true" v-on="$listeners">
    <use :href="iconName" />
  </svg>
</template>

<script>
// doc: https://panjiachen.github.io/vue-element-admin-site/feature/component/svg-icon.html#usage
import { isExternal } from '@/utils/validate'

export default {
  name: 'SvgIcon',
  props: {
    iconClass: {
      type: String,
      required: true
    },
    className: {
      type: String,
      default: ''
    }
  },
  computed: {
    isExternal() {
      return isExternal(this.iconClass)
    },
    iconName() {
      return `#icon-${this.iconClass}`
    },
    svgClass() {
      if (this.className) {
        return 'svg-icon ' + this.className
      } else {
        return 'svg-icon'
      }
    },
    styleExternalIcon() {
      return {
        mask: `url(${this.iconClass}) no-repeat 50% 50%`,
        '-webkit-mask': `url(${this.iconClass}) no-repeat 50% 50%`
      }
    }
  }
}
</script>

<style scoped>
.svg-icon {
  width: 1em;
  height: 1em;
  vertical-align: -0.15em;
  fill: currentColor;
  overflow: hidden;
}

.svg-external-icon {
  background-color: currentColor;
  mask-size: cover!important;
  display: inline-block;
}
</style>

⑤ 全局注册svg-icon组件

import Vue from 'vue'
// svg component
import SvgIcon from '@/components/SvgIcon'

/**
 * Vue.component(全局注册名字叫'svg-icon'的组件)register globally
 * 比如:全局注册后,我们就可以在login里写svg-icon
 */
Vue.component('svg-icon', SvgIcon)

/**
 * webpack之动态导入文件,require.context(webpack下的引入某文件夹下所有文件的方法)
 * 我们需要一次性的引入svg文件夹下的所有的svg文件,那么此时就可以使用require.context()来完成
 * 不只局限引入svg文件,同样可以引入文件夹下所有的js文件
 * Detail see: https://webpack.js.org/guides/dependency-management/#require-context
 */
const req = require.context('./svg', false, /\.svg$/)
const requireAll = requireContext => requireContext.keys().map(requireContext)
requireAll(req)