前言
自总结完了上篇前端工程化的思想,并在vue全家桶的项目加以实践,趁热给大家总结一篇如何更有效率与质量地开发vue项目,以及其中踩过的一个个坑。。。 基于vue-cli的自定义模板(Custom Templates)
小伙伴们的vue项目应该都是用vue-cli初始化出来的,但是vue-cli只是满足了基础配置和功能,如果你有额外的配置需求或者要迎合团队的业务配置,每新建个项目都得重新安装额外配置,比如说vuex,sass,封装axios,以及相关的文件夹。为了解决上述问题,vue-cli出了一个自定义模板功能,你fork官方的模板下来然后进行修改,然后用 vue-cli 来调用。具体调用的场景有以下两种
代码语言:javascript复制直接拉取git源:
当你修改了模板并上传了repo上,可执行以下命令行来初始化
vue init username/repo my-project
拉取本地的模板:
当你clone了官方模板在本地修改,可执行以下命令行来初始化
vue init ~/fs/path/to-custom-template my-project
还可以编写meta.*(js,json)来选择安装哪些配置~
如果大家懒得去编写vuex,sass的配置,封装axios的话,可以来通过我配置完的脚手架来初始化完项目~
代码语言:javascript复制vue init duosanglee/vuejs-custom-template
这个模板在repo里 ps:我的这个模板的代码风格是基于standard的 引入sass全局变量,mixin,function等
首先我们考虑下以下场景:当使用rem开发移动端的时候,你定义了一个方法pxToRem的方法来实现px对rem的转换,然后在工程里为每个.vue文件@import 'public.scss',得import很多很多很多次,万一public.scss路径变了的话。。。哭都来不及。 这时候sass-resources-loader就来拯救我们了,他可以省去重复性的引入,还支持LESS,POSTCSS等 具体用法如下:
代码语言:javascript复制npm install -D sass-resources-loader
首先得找到项目里的build文件夹,找到util.js
添加一下代码
function resolveResouce(name) {
return path.resolve(__dirname, '../src/style/' name);
}
function generateSassResourceLoader() {
var loaders = [
cssLoader,
// 'postcss-loader',
'sass-loader',
{
loader: 'sass-resources-loader',
options: {
// it need a absolute path
resources: [resolveResouce('common.scss')]
}
}
];
if (options.extract) {
return ExtractTextPlugin.extract({
use: loaders,
fallback: 'vue-style-loader'
})
} else {
return ['vue-style-loader'].concat(loaders)
}
}
然后还是在当前文件里找到
return {
css: generateLoaders(),
postcss: generateLoaders(),
less: generateLoaders('less'),
sass: generateLoaders('sass', { indentedSyntax: true }),
scss: generateLoaders('sass'),
stylus: generateLoaders('stylus'),
styl: generateLoaders('stylus')
}
替换成
return {
css: generateLoaders(),
postcss: generateLoaders(),
less: generateLoaders('less'),
sass: generateSassResourceLoader(),
scss: generateSassResourceLoader(),
stylus: generateLoaders('stylus'),
styl: generateLoaders('stylus')
}
这样就可以在项目里使用sass全局变量,mixin,function了~~
在线 Mock 平台 easy-mock
现在讲都是前后端分离,前后端并行开发来提高开发效率,通过一个api文档来协作,所以一个好的mock工具对于提高效率也至关重要~ 这里极力推荐easy-mock工具,支持团队协作编辑,生成模拟数据的在线 mock 服务,还支持导入swagger文档等功能,界面如下 clipboard.png 定义全局变量
在项目会有需要使用全局变量的需求,来处理一些频繁的操作,大家都应该会绑定到window对象上,但是这种方式不适合服务端渲染,因为服务端没有 window 对象, 是 undefined, 当试图去访问属性时会报错.我总结了两个靠谱的方法
代码语言:javascript复制代理到Vue的原型对象
由于所有的组件都会从 Vue 的原型对象上继承它们的方法, 因此我们只要
Object.defineProperty(Vue.prototype, '$xxx', { value: xxx });
就可以在所有组件/实例中通过 this.$xxx: 的方式访问插件了~而不需要定义全局变量或者手动的引入了~
至于为什么要用Object.defineProperty这个方法,是因为通过Object.defineProperty绑定的属性是只读的,以防一起开发项目的协(zhu)作(dui)者(you)去重写或者覆盖该方法的值。
vuex大法
vuex的出现就是vue为了集中式存储管理应用的所有组件的状态,所以说全局变量和方法都可以放到vuex当中~具体用法就不加阐述了,大家可仔细阅读vuex文档
组件设计
大家都知道组件化的思想就是分治,几乎任意类型的应用程序界面,都可以抽象为一个组件树,那我们该按照什么规则把应用抽象成组件,来应对复杂多变的业务需求呢。 我们从通信、黑箱,继承这几个角度来看看
- 通信: vue的父子组件通信机制是props down,events up,尽量保持松耦合,一直保持单向数据流的特点,并加以强约束。需要注意的时候,尽可能减少跨组件通信,例如使用$parent,$root。
- 继承: 当两个组件存在些许的共性,又存在足够的差异性的时候,就可以用到vue的继承---mixin,他允许你封装一块在应用的其他组件中都可以使用的函数。如果使用姿势正确,他们不会改变函数作用域外部的任何东西。而且mixin还有各种高阶用法,大家可自行查询(我也不会)。
- 黑箱: 组件的黑箱状态既只暴露易变的接口和方法,渲染给入的数据,组件内部封装不变的逻辑。
- 设计模式原则: 运用设计模式原则,比如单一职责原则,将组件拆分抽离成更细粒度,保证高内聚性;再如接口隔离原则,采用稳定的服务端接口,将变化模块分离,使得组件得以解耦;里氏替换原则、依赖倒置原则等等。。
目录结构
-- src
代码语言:javascript复制-- assets # 私有资源
-- common # 通用组件
-- components # 业务组件
-- api.js # 请求文件
-- config # 环境变量配置
-- env.js # 环境变量文件
-- http.js # 封装axios文件
-- pages # 页面维度
-- pageA # 页面A
-- pageA.vue # 页面A单文件
-- pageA-components # 页面A下的一个组件
-- children # 子页面
-- router # 路由
-- index.js # 路由入口
-- routes.js # 路由配置信息
-- store # vuex
-- modules # vuex模块
-- index.js # vuex入口
-- utils # js通用方法
-- app.vue # 顶层单文件
-- main.js # 入口
大家可以从目录结构中看出我整个项目分割的思维 首先我把组件分为通用组件和业务组件两大类。
- 通用组件是与业务耦合低,是有简单状态或者无状态的,数据几乎全部依赖于输入,它只负责渲染给入的数据。比如按钮是一个组件,可能有一个参数决定了它的尺寸,一个参数决定了它是否可以点击,但是点击这个按钮之后会发生什么,就不是按钮这个组件需要知道的事情了。
- 业务组件是与业务耦合高,可以由多个通用组件和其他的业务组件组成,会拥有一些方法,用来修改持有的数据,对内来看,它自己持有一些数据和方法,用来决定内容的渲染,对外又是一个简单的props接受数据。可以理解为组件树的非叶子节点,通过自身数据变化,进而操纵子组件的内容。
然后config文件夹放置了环境变量文件env.js和封装http库文件http.js
env.js
http.js
然后我把路由里的routes.js和api.js请求文件都单独抽离了出来。
自动生成雪碧图
前端项目中自动生成雪碧图节省了我们很多的时间,我们只要把图片扔到文件夹里,webpack-spritesmith就能按照我们设定的规则自动合成css-sprite,安装配置如下:
代码语言:javascript复制var SpritesmithPlugin = require('webpack-spritesmith');
...
module.exports = {
...
plugins: [
new SpritesmithPlugin({
src: {
cwd: './src/assets/sp/',
glob: '*.png'
},
target: {
image: './src/assets/sprite/sprite.png',
css: './src/assets/sprite/sprite.css'
},
apiOptions: {
cssImageRef: './sprite.png'
},
spritesmithOptions: {
algorithm: 'top-down',
padding: 100
}
})
]
}
自动修复eslint格式错误
这个功能的建立在小伙伴的开发工具是vscode情况下~ 首先在vscode扩展里面安装vscode的eslint插件,然后settings.json里添加如下配置
代码语言:javascript复制"eslint.validate": [
"javascript",
"javascriptreact",
{
"language": "html",
"autoFix": true
},
{
"language": "vue",
"autoFix": true
}
],
"eslint.autoFixOnSave": true,
然后会在save文件的时候eslint插件自动根据项目下的.eslintrc来设置代码格式~ sf不支持播放gif..具体效果大家只能自行查看
跨域
在浏览vue-cli的官方文档时候发现了vue-cli自带了API proxy,解决了在项目中后端联调的时候的跨域问题。具体安装配置如下: 首先我们找到config文件下的index.js,再找到dev对象下的proxyTable属性,然后把以下代码添加进去
代码语言:javascript复制proxyTable: {
'/api': {
target: '网站名',
pathRewrite: {
'^/api': ''
}
}
}
然后重启本地服务器,这样你发送的/api/a就会代理发送到"网站名/a"了~
开发利器emmet
之所以称emmet为前端开发利器是因为他可以根据我们所输入的缩写来得到相应的内容,大大节省我们的开发html和css的时间,例:
输入ul>li*2>span 按下扩展键
- <span></span>
- <span></span>
输入m0-a-0-0 posa bgc 按下扩展键
代码语言:javascript复制margin: 0 auto 0 0;
position: absolute;
background-color: #fff;
更多方法请看官方文档emmet
这篇文章到此就已经结束了~感谢大家能够关注此文章~如果这篇文章能帮助到大家的话,麻烦请帮我点个赞~~~