脚手架构建
// 1.安装 vue-cli 脚手架构建工具
npm install --global vue-cli
// 2.构建于 webpack 模板的一个新项目,填写相关项目信息
vue init webpack my-project
// 3.安装项目依赖
npm install
项目目录
按如下文件目录搭建项目框架
src 主要源码目录
|-- assets 静态资源,统一管理
|-- components 公用组件,全局组件
|-- javascript JS相关操作处理
|-- ajax axios封装的请求拦截
|-- filters 全局过滤器
|-- utils 全局封装的工具类
|-- datas 模拟数据,临时存放
|-- router 路由,统一管理
|-- store vuex, 统一管理
|-- views 视图目录
|-- order 视图模块名
|-- |-- orderList.vue 模块入口页面
|-- |-- orderDetail.vue 模块入口页面
|-- |-- components 模块通用组件文件夹
UI 框架选择
- PC 端:依次推荐使用 antDesign, iView
- 移动端:依次推荐使用 vant,vux
css 预处理器
推荐使用 less,scss , 可在 common.css 设置全局样式,如
- 常用样式设置原子类名
- 主题颜色, UI 设计规范等样式
全局组件公共样式
.colorTheme {
color: #40a9ff !important;
}
.fl {
float: left;
}
.fr {
float: right;
}
.clearfix:after {
clear: both;
content: '';
display: block;
width: 0;
height: 0;
visibility: hidden;
}
移动端适配
以蓝湖 750px 设计稿。
- 使用 rem 适配,代码书写 px,用 px2rem-loader 将 px 转化为 rem。
const px2remLoader = {
loader: 'px2rem-loader',
options: {
remUnit: 100 //1rem=多少像素 这里的设计稿是750px。
}
}
拆分路由
在 Vue 项目中使用路由,相信大家都已经很熟悉怎么使用了,要新增一个页面的话,需要到路由配置中配置该页面的信息。
但是如果页面越来越多的话,那么如何让我们的路由更简洁呢?
根据不同的业务模块进行路由拆分,在每个子模块导出一个路由配置数组,如 userCard.js 导出会员卡模块的路由,order.js 导出订单模块的路由
在路由根目录在 index.js 中导入所有子模块const routes = [
{
path: '/userCardList',
component: function(resolve) {
require(['@/view/userCard/userCardList'], resolve)
}
},
{
path: '/userCardEdit',
component: function(resolve) {
require(['@/view/userCard/userCardEdit'], resolve)
}
}
]
axios 请求封装import Vue from 'vue'
import Router from 'vue-router'
import userCard from '.userCard'
import order from './order'
let routes = [...userCard, ...order]
Vue.use(Router)
export default new Router({
mode: 'hash',
routes: routes
})
设置请求拦截和响应拦截
封装 get 和 post 请求方法const PRODUCT_URL = 'https://test-o2o-store-all.iauto360.cn'
const MOCK_URL = 'http://39.104.49.240:19090'
let http = axios.create({
baseURL: process.env.NODE_ENV === 'production' ? PRODUCT_URL : MOCK_URL
})
// 请求拦截器
http.interceptors.request.use(
config => {
// 设置token,Content-Type
var token = sessionStorage.getItem('UserLoginToken')
config.headers['token'] = token
config.headers['Content-Type'] = 'application/json;charset=UTF-8'
// 请求显示loading效果
if (config.loading === true) {
vm.$loading.show()
}
return config
},
error => {
vm.$loading.hide()
return Promise.reject(error)
}
)
// 响应拦截器
http.interceptors.response.use(
res => {
vm.$loading.hide()
// token失效,重新登录
if (res.data.code === 401) {
// 重新登录
}
return res
},
error => {
vm.$loading.hide()
return Promise.reject(error)
}
)
把 get,post 方法挂载到 vue 实例上。function get(url, data, lodaing) {
return new Promise((resolve, reject) => {
http.get(url)
.then(
response => {
resolve(response)
},
err => {
reject(err)
}
)
.catch(error => {
reject(error)
})
})
}
function post(url, data, loading) {
return new Promise((resolve, reject) => {
http.post(url, data, { loading: loading })
.then(
response => {
resolve(response)
},
err => {
reject(err)
}
)
.catch(error => {
reject(error)
})
})
}
export { get, post }
工具类函数封装// main.js
import { get, post } from './js/ajax'
Vue.prototype.$http = { get, post }
添加方法到 vue 实例的原型链上
在 main.js 通过 vue.use()注册export default {
install (Vue, options) {
Vue.prototype.util = {
method1(val) {
...
},
method2 (val) {
...
},
}
}
命名规范import utils from './js/utils'
Vue.use(utils)
——让团队当中其他人看你的代码能一目了然
- 文件夹和文件命名以业务或者模块名字为主,驼峰式命名。
- 组件命名遵循以下原则,使用驼峰命名(
carLib
)进行组件声明,使用短横线分隔命名(<car-lib></car-lib>
)进行使用。 - 当项目中需要自定义比较多的基础组件的时候,比如一些 button,input,icon,建议以一个统一的前缀如 Base 开头,这样做的目的是为了方便查找。
- method 方法命名使用驼峰式,动词+名词,如 getData, submitForm
- 变量命遵循语义化原则,使用驼峰式。
编码规范
vue 风格推荐
Prop 定义应该尽量详细。
使用 v-for 必须加上 key 值// bad
props: ['status']
// good
props: {
status: String
}
// better
props: {
status: {
type: String,
required: true,
validator: function (value) {
return ['syncing','synced','version-conflict','error'].indexOf(value) !== -1
}
}
}
不要把 v-if 和 v-for 同时用在同一个元素上。<!-- bad -->
<ul>
<li v-for="todo in todos">{{ todo.text }}</li>
</ul>
<!-- good -->
<ul>
<li v-for="todo in todos" :key="todo.id">{{ todo.text }}</li>
</ul>
组件的 data 必须是一个函数<!-- bad -->
<ul>
<li v-for="user in users" v-if="shouldShowUsers" :key="user.id">{{ user.name }}</li>
</ul>
<!-- good -->
<ul v-if="shouldShowUsers">
<li v-for="user in users" :key="user.id">{{ user.name }}</li>
</ul>
组件模板应该只包含简单的表达式,复杂的表达式则应该重构为计算属性或方法。// bad
Vue.component('some-comp', {
data: {
foo: 'bar'
}
})
// good
Vue.component('some-comp', {
data: function() {
return {
foo: 'bar'
}
}
})
指令缩写// bad
{{
fullName.split(' ').map(function (word) {
return word[0].toUpperCase() + word.slice(1)
}).join(' ')
}}
// good
// 在模板中
{{ normalizedFullName }}
// 复杂表达式已经移入一个计算属性
computed: {
normalizedFullName: function () {
return this.fullName.split(' ').map(function (word) {
return word[0].toUpperCase() + word.slice(1)
}).join(' ')
}
}
<!-- bad -->
<input v-bind:value="newTodoText" :placeholder="newTodoInstructions" v-on:input="onInput" />
<!-- good -->
<input :value="newTodoText" :placeholder="newTodoInstructions" @input="onInput" />
关于组件内样式
为组件样式设置作用域
若要改变第三方组件库的样式,需要加上顶级作用域。/* bad */
<style>
.btn-close {
background-color: red;
}
</style>
/* good */
<style scoped>
.button-close {
background-color: red;
}
</style>
关于组件结构/* bad */
.ivu-input {
width: 254px !important;
}
/* good */
.customerForm .ivu-input {
width: 254px !important;
}
/* .customerForm为当前组件的顶级dom */
组件结构遵循从上往下 template,script,style 的结构。
script 部分各方法成员遵循以下顺序放置。 ```protobuf<template>
<div></div>
</template>
<script>
export default {}
</script>
<style lang="scss" scoped></style>
- name
- components
- props
- data
- methods
- computed
- watch
- created
- mounted
update ``` 关于注释规范
以下情况需要加注释,以方便代码维护和他人理解公共组件使用说明
- 各组件中重要函数或者类说明
- 复杂的业务逻辑处理说明
- 特殊情况的代码处理说明,对于代码中特殊用途的变量、存在临界值、函数中使用的 hack、使用了某种算法或思路等需要进行注释描述。
- 多重 if 判断语句
其他规范
建议不再使用双引号,静态字符串使用单引号,动态字符串使用反引号衔接。
使用数组展开操作符 … 复制数组。// bad
const foo = 'jack'
const bar = foo + ',前端工程师'
// good
const foo = 'jack'
const bar = `${foo},前端工程师`
使用数组对象解构赋值// bad
const len = items.length
const itemsCopy = []
let i
for (i = 0; i < len; i += 1) {
itemsCopy[i] = items[i]
}
// good
const itemsCopy = [...items]
使用对象属性速记语法const arr = [1, 2, 3, 4]
// bad
const first = arr[0]
const second = arr[1]
// good
const [first, second] = arr
百度统计const name = 'Luke'
const age = 20
// bad
const obj = {
name: name,
age: age
}
// good
const obj = {
name,
age
}
在 index.html 添加百度统计脚本
在全局路由守卫添加需要统计的页面var _hmt =
_hmt ||
[](function() {
var hm = document.createElement('script')
hm.src = 'https://hm.baidu.com/hm.js?d1dbfd0ce8ca70cf72828b2844498250'
var s = document.getElementsByTagName('script')[0]
s.parentNode.insertBefore(hm, s)
})()
router.afterEach(to => {
if (window._hmt) {
window._hmt.push(['_trackPageview', '/#' + to.fullPath])
}
})