9月底,接手了一个项目,主要是完成流程单元回路管网的监控。考虑到开发现状,第一版开发采用了HTML、CSS、ECharts、JQuery、SVG(使用工具Visual Graph绘制管道网络图,导出svg文件备用)、.Net、Oracle技术完成。主要完成监控数据的展示、监控切换与跳转。例如:报警类信息、监控指标详细信息的展示;切换、选择、超链接等交互功能。由于目前了解到的管道图数量已接近百张,划分展示层级后,梳理确定了各层级具体业务功能,进行了第二版按层级业务功能划分的代码重构工作。第三版,采用vue框架实现对代码的重构。
确定代码重构内容,包括了以下两点:1.对svg的调用。2.业务功能重构。
一.对svg的调用
vue中调用svg可以分为2类:“不使用插件”和“使用插件”。
1.“不使用插件”:
1.1 可以直接在模板<template>...</template>内添加svg。
1.2(推荐)或者创建一个svg组件。可以定义一个svg,也可以定义多个svg(此时使用<symbol id="xxx">...</symbol>划分各个svg。调用时必须使用<svg><use xlink:href="#xxx"></use></svg>,并且在使用此调用语句的组件内导入这个svg组件。这里推荐在App.js内全局导入此svg组件)。由于这个svg组件内定义了多个svg,会被一次性加载。数量多时会影响界面响应速度,也不便于维护svg。因此推荐使用插件“svg-sprite-loader”或“vue2-svg-icon”,动态调用所需svg,提高用户体验的同时也便于对svg文件进行管理。
2.“使用插件”(推荐):
2.1 使用svg-sprite-loader时:
1)安装插件:安装svg-sprite-loader插件后,最好同时安装插件svg-baker-runtime(这是一个svg-sprite-loader需要的依赖,而npm没有自动安装,最头疼的是没...有...报...错!!!白白在此花了很多脑细胞。百度了N多文章,终于找到一位小伙伴的博客,得以解决。)
//package.json内可以查看相关插件
...
"devDependencies": {
...
"svg-baker-runtime": "^1.4.0",
"svg-sprite-loader": "^4.1.3",
...
}
...
webpack.base.conf.js内,需要配置svg文件采用何种规则编译。
...
{
test: /\.svg$/,
include:[
path.resolve(__dirname,'../src/icons')
],
loader: 'svg-sprite-loader',
options:{
//symbolId:'icon-[name]'
}
},
{
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000,
name: utils.assetsPath('img/[name].[hash:7].[ext]')
},
exclude:[
path.resolve(__dirname,'../src/icons')
]
},
...
2)js控制动态调用svg文件:接下来创建一个目录src/icons,内部存放svg文件及自动调用所需svg文件的index.js文件。
index.js内部引入了步骤 3)中定义的“组件vue”,并全局注册了这个组件vue,便于调用的时候直接使用<svg-icon>标签。
import Vue from 'vue'
import SvgIcon from '../components/SvgIcon.vue'
/* require.context("./test", false, /.test.js$/);
这行代码就会去 test 文件夹(不包含子目录) 下面的找所有文件名以 .test.js 结尾的文件能被 require 的文件。
更直白的说就是 我们可以通过正则匹配引入相应的文件模块。
require.context有三个参数:
directory:说明需要检索的目录
useSubdirectories:是否检索子目录
regExp: 匹配文件的正则表达式 */
//全局注册
Vue.component('svg-icon', SvgIcon)
const requireAll = requireContext => requireContext.keys().map(requireContext)
const req = require.context('./svg', false, /\.svg$/)
requireAll(req)
svg文件也有一定的格式要求,使用工具Visual Graph绘制导出的svg图,需要规范代码内容。
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg t="1503993891882" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="7986" xmlns:xlink="http://www.w3.org/1999/xlink" width="64" height="64">
<!--<defs>-->
<!--<style type="text/css"></style>-->
<!--</defs>-->
<path d="M504.951 511.98c93.49 0 169.28-74.002 169.28-165.26 0-91.276-75.79-165.248-169.28-165.248-93.486 0-169.287 73.972-169.279 165.248-0.001 91.258 75.793 165.26 169.28 165.26z m77.6 55.098H441.466c-120.767 0-218.678 95.564-218.678 213.45V794.3c0 48.183 97.911 48.229 218.678 48.229H582.55c120.754 0 218.66-1.78 218.66-48.229v-13.77c0-117.887-97.898-213.45-218.66-213.45z" p-id="7987">
</path>
</svg>
3)用于显示svg的“组件vue”:src/components下创建用于封装调用的svg文件的“组件vue”。例如SvgIcon.vue
<template>
<svg :class="svgClass" aria-hidden="true" >
<use :xlink:href="iconName"></use>
</svg>
</template>
<script>
export default{
name:"svg-icon",
props:{
iconClass: { type: String, required: true },
className: { type: String }
},
computed: {
iconName() {
return `#icon-${this.iconClass}`;//或者`#${this.iconClass}`
},
svgClass() {
if (this.className) {
return "svg-icon " + this.className;
} else {
return "svg-icon";
}
}
}
}
</script>
<style scoped>
.svg-icon {
width: 1em;
height: 1em;
vertical-align: -0.15em;
fill: currentColor;
overflow: hidden;
}
</style>
4)main.js配置:
导入步骤 2)中创建的icons目录下的全部文件。也可以写成import '@/icons'。
import Vue from 'vue'
import App from './App'
import router from './router'
import './icons'
// import Icon from 'vue2-svg-icon/Icon'
// Vue.component('icon',Icon);
/* eslint-disable no-new */
new Vue({
el: '#app',
router,
render: h => h(App)
})
5)页面组件调用svg组件。
<svg-icon>标签表示调用步骤 3)中定义的SvgIcon.vue组件。icon-class的值(可以使用页面组件获取的业务数据替换)传递给props的iconClass,得到动态计算属性iconName的值,得以调用步骤2)中src/icons内对应的svg文件。:w和:h的值会自动编译成1em,也可以使用绑定样式。
<template>
<svg-icon icon-class="01" :w="100" :h="100"></svg-icon>
<svg-icon icon-class="02" :w="100" :h="100"></svg-icon>
<svg-icon icon-class="04" :w="100" :h="100"></svg-icon>
<!--<svg-icon icon-class="04" :style="{width:1000+'px',height:500+'px'}"></svg-icon>-->
</template>
也可以参考小伙伴的博客。
2.2 使用vue2-svg-icon时:
1)安装插件:安装vue2-svg-icon插件。
//package.json内可以查看相关插件
...
"devDependencies": {
...
"vue2-svg-icon": "^1.3.2",
...
}
...
2)svg文件管理:将svg文件放到src/assets/svg内。(不要放错了)
3)main.js配置:引入了步骤 1)中定义的“组件vue”,并全局注册了这个组件vue,便于调用的时候直接使用<icon>标签。
import Vue from 'vue'
import App from './App'
import router from './router'
//import './icons'
import Icon from 'vue2-svg-icon/Icon'
Vue.component('icon',Icon);
/* eslint-disable no-new */
new Vue({
el: '#app',
router,
render: h => h(App)
})
4)页面组件调用svg组件。
<icon>标签表示调用步骤 2)中的插件vue2-svg-icon/Icon.vue组件。name的值(可以使用页面组件获取的业务数据替换)调用步骤2)中src/assets/svg内对应的svg文件。
<template>
<icon name="01" :w="100" :h="100"></icon>
</template>
可以参考小伙伴的博客 。
二.业务功能重构
主要介绍自适应与svg图形缩放(未完待续)