参考:javascript
https://github.com/PanJiaChen/vue-element-admin/blob/master/README.zh-CN.mdcss
http://www.javashuo.com/article/p-hdwsabyi-ct.htmlhtml
一、当项目逐渐变大以后,文件与文件直接的引用关系会很复杂,这时候就须要使用alias了。前端
//webpack.base.config.js alias: { 'src': path.resolve(__dirname, '../src'), 'components': path.resolve(__dirname, '../src/components'), 'api': path.resolve(__dirname, '../src/api'), 'utils': path.resolve(__dirname, '../src/utils'), 'store': path.resolve(__dirname, '../src/store'), 'router': path.resolve(__dirname, '../src/router') } //使用xxx.js import stickTop from 'components/stickTop' import getArticle from 'api/article'
二、ESLintvue
不论是多人合做仍是我的项目,代码规范是很重要的。这样作不只能够很大程度地避免基本语法错误,也保证了代码的可读性。推荐 eslint+vscode 来写 vue。java
每次保存,vscode就能标红不符合eslint规则的地方,同时还会作一些简单的自我修正。安装步骤以下:node
1)首先在vscode里安装eslint插件react
2)点击 文件 > 首选项 > 设置 打开 VSCode 配置文件,添加以下配置。这样每次保存的时候就能够根据根目录下.eslintrc.js你配置的eslint规则来检查和作一些简单的fix。webpack
{ "files.autoSave":"off", "eslint.validate": [ "javascript", "javascriptreact", "html", { "language": "vue", "autoFix": true } ], "eslint.options": { "plugins": ["html"] }, "eslint.autoFixOnSave": true }
三、js环境变量ios
process对象是 Node 的一个全局对象,提供当前 Node 进程的信息。它能够在脚本的任意位置使用,没必要经过require命令加载。process.env属性返回一个对象,包含了当前Shell的全部环境变量。一般的作法是,新建一个环境变量NODE_ENV,用它肯定当前所处的开发阶段,生产阶段设为production,开发阶段设为develop或staging,而后在脚本中读取process.env.NODE_ENV便可。
DefinePlugin:容许你建立一个在编译时能够配置的全局常量。这可能会对开发模式和发布模式的构建容许不一样的行为很是有用。
//webpack.prod.conf.js var env = process.env.NODE_ENV === 'production' ? config.build.prodEnv : config.build.sitEnv new webpack.DefinePlugin({ 'process.env': env })
//package.json "scripts": { "dev": "node build/dev-server.js", "build:prod": "cross-env NODE_ENV=production node build/build.js", "build:sit": "cross-env NODE_ENV=sit node build/build.js" }
cross-env这个npm包使得在使用或设置环境变量时能用同一种方式适配不一样的平台(以unix方式设置环境变量,而后在windows上也能兼容运行)
三、先后端交互
1)封装 axios
//request.js import axios from 'axios' import { Indicator, MessageBox } from 'mint-ui' // 建立axios实例 const service = axios.create({ baseURL: process.env.BASE_API, // api的base_url timeout: 60000 // 请求超时时间 }) // request拦截器 service.interceptors.request.use(config => { // Do something before request is sent Indicator.open('加载中...') return config }, error => { // Do something with request error Promise.reject(error) }) // respone拦截器 service.interceptors.response.use( response => { Indicator.close() const res = response.data if (res.ReturnCode !== '000000') { if (res.ReturnMsg) { MessageBox.alert(res.ReturnMsg) } else { MessageBox.alert('系统未知错误') } return Promise.reject(res) } else { return res } }, error => { Indicator.close() MessageBox.alert('太火爆了吧,稍安勿躁,亲,再试试') return Promise.reject(error) } ) export default service
//api/xxx.js import request from '@/utils/request' // 登陆 export function userLogin(data) { return request({ url: 'login.do', method: 'post', data }) }
2)跨域问题
经常使用的方式就是 cors
全称为 Cross Origin Resource Sharing(跨域资源共享)。这种方案对于前端来讲和平时发请求写法上没有任何区别,工做量基本都在后端这里。前端也是有解决方案的,dev环境也能够经过webpack-dev-server
的proxy
来解决。【webpack的dev-server 使用了很是强大的 http-proxy-middleware 包】
a、直接使用http-proxy-middleware包
//配置js1 var proxyMiddleware = require('http-proxy-middleware'); var express = require('express'); var app = express(); Object.keys(proxyTable).forEach(function (context) { var options = proxyTable[context] if (typeof options === 'string') { options = {target: options} } app.use(proxyMiddleware(options.filter || context, options)) }); //配置js2 proxyTable: { "/tt": { target: "http://localhost:8090", changeOrigin: true } }
b、使用webpack-dev-server此npm包(webpack的devServer配置
)
//webpack.dev.config.js devServer: { proxy: config.dev.proxyTable }, //配置js proxyTable: { "/portal": { target: "http://localhost:8080" } }
3)Mock 数据
mockjs:拦截请求并代理到本地模拟数据
四、权限控制
详见http://www.javashuo.com/article/p-hjvxfzvw-km.html
作后台项目区别于作其它的项目,权限验证与安全性是很是重要的,能够说是一个后台项目一开始就必须考虑和搭建的基础核心功能。咱们所要作到的是:不一样的权限对应着不一样的路由,同时侧边栏也需根据不一样的权限,异步生成(动态根据用户的 role 算出其对应有权限的路由,经过 router.addRoutes 动态挂载这些路由)。
//permission.js const whiteList = ['/login']// 不重定向白名单 router.beforeEach((to, from, next) => { NProgress.start() // 开启Progress const token = store.state.user.token if (token) { // 判断是否有token if (to.path === '/login') { next({ path: '/' }) } else { store.dispatch('GenerateRoutes').then(() => { // 生成可访问的路由表 router.addRoutes(store.getters.addRouters) // 动态添加可访问路由表 next() }) } } else { if (whiteList.indexOf(to.path) !== -1) { // 在免登陆白名单,直接进入 next() } else { next('/login') // 不然所有重定向到登陆页! } } })
五、样式
常见的工做流程是,全局样式都写在 src/styles
目录下,每一个页面本身对应的样式都写在本身的 .vue
文件之中
1)使用scoped解决样式冲突问题(基于PostCss的,加了一个做用局的概念)
//编译前 .example { color: red; } //编译后 .example[_v-f3f3eg9] { color: red; }
2)自定义 element-ui 样式
因为element-ui的样式咱们是在全局引入的,因此你想在某个view里面覆盖它的样式就不能加scoped,但你又想只覆盖这个页面的element样式,你就可在它的父级加一个class,以用命名空间来解决问题。
.aritle-page{ //你的命名空间 .el-tag { //element-ui 元素 margin-right: 0px; } }
六、ECharts
管理后台图表也是常见的需求。ECharts支持webpack引入,图省事能够将ECharts整个引入;
不过ECharts仍是不小的,咱们大部分状况只是用到不多一部分功能,所以能够按需引入的。
// 引入 ECharts 主模块 var echarts = require('echarts/lib/echarts'); // 引入柱状图 require('echarts/lib/chart/bar'); // 引入提示框和标题组件 require('echarts/lib/component/tooltip'); require('echarts/lib/component/title');
七、使用icon图标
雪碧图,就是将多个图片合成一个图片,而后利用 css 的 background-position 定位显示不一样的 icon 图标。但这个也有一个很大的痛点,维护困难。每新增一个图标,都须要改动原始图片,还可能不当心出错影响到前面定位好的图片,并且一修改雪碧图,图片缓存就失效了,长此以往你不知道该怎么维护了。
Iconfont-阿里巴巴矢量图标库—symbol引用:这是一种全新的使用方式,应该说这才是将来的主流,也是平台目前推荐的用法。
font-size
,color
来调整样式。第一步:拷贝项目下面生成的symbol代码:
引入 ./iconfont.js
第二步:加入通用css代码(引入一次就行):
<style type="text/css"> .icon { width: 1em; height: 1em; vertical-align: -0.15em; fill: currentColor; overflow: hidden; } </style>
第三步:挑选相应图标并获取类名,应用于页面:
<svg class="icon" aria-hidden="true"> <use xlink:href="#icon-xxx"></use> </svg>
1)建立
icon-svg组件
<!--components/Icon-svg--> <template> <svg class="svg-icon" aria-hidden="true"> <use :xlink:href="iconName"></use> </svg> </template> <script> export default { name: 'icon-svg', props: { iconClass: { type: String, required: true } }, computed: { iconName() { return `#icon-${this.iconClass}` } } } </script>
//引入svg组件 import IconSvg from '@/components/IconSvg' //全局注册icon-svg Vue.component('icon-svg', IconSvg) //在代码中使用 <icon-svg icon-class="password" />
2)使用 svg-sprite优化
a、优化缘由:如今全部的 svg-sprite
都是经过 iconfont 的 iconfont.js
生成的
svg-sprite
。iconfont
整合到一块儿呢?目前只能将其也上传到 iconfont
和原有的图标放在一个项目库中,以后再从新下载,很繁琐。b、在 vue-cli
的基础上进行改造,加入 svg-sprite-loader(能够将多个 svg 打包成
svg-sprite
)
vue-cli
默认状况下会使用
url-loader
对svg进行处理,会将它放在
/img
目录下,因此这时候咱们引入
svg-sprite-loader
会引起一些冲突(解决方案有两种,最简单的就是你能够将 test 的 svg 去掉,这样就不会对svg作处理了,固然这样作是很不友善的:你不能保证你全部的 svg 都是用来当作 icon的,有些真的可能只是用来当作图片资源的;不能确保你使用的一些第三方类库会使用到 svg)。最安全合理的作法是使用 webpack 的 exclude 和 include ,让
svg-sprite-loader
只处理你指定文件夹下面的 svg,
url-loaer
只处理除此文件夹以外的全部svg。
//webpack.base.config.js { test: /\.svg$/, loader: 'svg-sprite-loader', include: [resolve('src/icons')], options: { symbolId: 'icon-[name]' } }, { test: /\.(png|jpe?g|gif|svg)(\?.*)?$/, loader: 'url-loader', exclude: [resolve('src/icons')], options: { limit: 10000, name: utils.assetsPath('img/[name].[hash:7].[ext]') } }
c、自动导入
咱们建立一个专门放置图标 icon 的文件夹如:@/src/icons,将全部 icon 放在这个文件夹下。以后咱们就要使用到 webpack 的 require.context。require.context有三个参数(directory:说明须要检索的目录;useSubdirectories:是否检索子目录;regExp: 匹配文件的正则表达式)
//src/icons/index.js const requireAll = requireContext => requireContext.keys().map(requireContext) const svgs = require.context('./svgs', false, /\.svg$/)
//去svgs文件夹(不包含子目录)下面的找全部文件名以 结尾的文件
requireAll(svgs).svg
3)进一步优化本身的svg-移除无用信息
iconfont 网站导出的 svg 内容已经算蛮精简的了,但你会发现其实仍是与不少无用的信息,形成了没必要要的冗余。好在 svg-sprite-loader也考虑到了这点,它目前只会获取 svg 中 path 的内容,而其它的信息一律不会获取。但任何你在 path 中产生的冗余信息它就不会作处理了,如注释什么的。这时候咱们就要使用另外一个很好用的东西了-- svgo:由于SVG文件,尤为从各类变假期导出的SVG,一般包含大量的无用信息,例如编辑器源信息,注释,所以默认或者非最优值以及其余一些不会影响渲染结果的元素能够移除或转换。