脚手架构建

  1. // 1.安装 vue-cli 脚手架构建工具
  2. npm install --global vue-cli
  3. // 2.构建于 webpack 模板的一个新项目,填写相关项目信息
  4. vue init webpack my-project
  5. // 3.安装项目依赖
  6. npm install

项目目录

按如下文件目录搭建项目框架

  1. src 主要源码目录
  2. |-- assets 静态资源,统一管理
  3. |-- components 公用组件,全局组件
  4. |-- javascript JS相关操作处理
  5. |-- ajax axios封装的请求拦截
  6. |-- filters 全局过滤器
  7. |-- utils 全局封装的工具类
  8. |-- datas 模拟数据,临时存放
  9. |-- router 路由,统一管理
  10. |-- store vuex, 统一管理
  11. |-- views 视图目录
  12. |-- order 视图模块名
  13. |-- |-- orderList.vue 模块入口页面
  14. |-- |-- orderDetail.vue 模块入口页面
  15. |-- |-- components 模块通用组件文件夹

UI 框架选择

  • PC 端:依次推荐使用 antDesign, iView
  • 移动端:依次推荐使用 vant,vux


css 预处理器

推荐使用 less,scss , 可在 common.css 设置全局样式,如

  • 常用样式设置原子类名
  • 主题颜色, UI 设计规范等样式
  • 全局组件公共样式

    1. .colorTheme {
    2. color: #40a9ff !important;
    3. }
    4. .fl {
    5. float: left;
    6. }
    7. .fr {
    8. float: right;
    9. }
    10. .clearfix:after {
    11. clear: both;
    12. content: '';
    13. display: block;
    14. width: 0;
    15. height: 0;
    16. visibility: hidden;
    17. }

    移动端适配
  • 以蓝湖 750px 设计稿。

  • 使用 rem 适配,代码书写 px,用 px2rem-loader 将 px 转化为 rem。
    1. const px2remLoader = {
    2. loader: 'px2rem-loader',
    3. options: {
    4. remUnit: 100 //1rem=多少像素 这里的设计稿是750px。
    5. }
    6. }

    拆分路由

    在 Vue 项目中使用路由,相信大家都已经很熟悉怎么使用了,要新增一个页面的话,需要到路由配置中配置该页面的信息。
    但是如果页面越来越多的话,那么如何让我们的路由更简洁呢?
    根据不同的业务模块进行路由拆分,在每个子模块导出一个路由配置数组,如 userCard.js 导出会员卡模块的路由,order.js 导出订单模块的路由
    1. const routes = [
    2. {
    3. path: '/userCardList',
    4. component: function(resolve) {
    5. require(['@/view/userCard/userCardList'], resolve)
    6. }
    7. },
    8. {
    9. path: '/userCardEdit',
    10. component: function(resolve) {
    11. require(['@/view/userCard/userCardEdit'], resolve)
    12. }
    13. }
    14. ]
    在路由根目录在 index.js 中导入所有子模块
    1. import Vue from 'vue'
    2. import Router from 'vue-router'
    3. import userCard from '.userCard'
    4. import order from './order'
    5. let routes = [...userCard, ...order]
    6. Vue.use(Router)
    7. export default new Router({
    8. mode: 'hash',
    9. routes: routes
    10. })
    axios 请求封装
    设置请求拦截和响应拦截
    1. const PRODUCT_URL = 'https://test-o2o-store-all.iauto360.cn'
    2. const MOCK_URL = 'http://39.104.49.240:19090'
    3. let http = axios.create({
    4. baseURL: process.env.NODE_ENV === 'production' ? PRODUCT_URL : MOCK_URL
    5. })
    6. // 请求拦截器
    7. http.interceptors.request.use(
    8. config => {
    9. // 设置token,Content-Type
    10. var token = sessionStorage.getItem('UserLoginToken')
    11. config.headers['token'] = token
    12. config.headers['Content-Type'] = 'application/json;charset=UTF-8'
    13. // 请求显示loading效果
    14. if (config.loading === true) {
    15. vm.$loading.show()
    16. }
    17. return config
    18. },
    19. error => {
    20. vm.$loading.hide()
    21. return Promise.reject(error)
    22. }
    23. )
    24. // 响应拦截器
    25. http.interceptors.response.use(
    26. res => {
    27. vm.$loading.hide()
    28. // token失效,重新登录
    29. if (res.data.code === 401) {
    30. // 重新登录
    31. }
    32. return res
    33. },
    34. error => {
    35. vm.$loading.hide()
    36. return Promise.reject(error)
    37. }
    38. )
    封装 get 和 post 请求方法
    1. function get(url, data, lodaing) {
    2. return new Promise((resolve, reject) => {
    3. http.get(url)
    4. .then(
    5. response => {
    6. resolve(response)
    7. },
    8. err => {
    9. reject(err)
    10. }
    11. )
    12. .catch(error => {
    13. reject(error)
    14. })
    15. })
    16. }
    17. function post(url, data, loading) {
    18. return new Promise((resolve, reject) => {
    19. http.post(url, data, { loading: loading })
    20. .then(
    21. response => {
    22. resolve(response)
    23. },
    24. err => {
    25. reject(err)
    26. }
    27. )
    28. .catch(error => {
    29. reject(error)
    30. })
    31. })
    32. }
    33. export { get, post }
    把 get,post 方法挂载到 vue 实例上。
    1. // main.js
    2. import { get, post } from './js/ajax'
    3. Vue.prototype.$http = { get, post }
    工具类函数封装
    添加方法到 vue 实例的原型链上
    1. export default {
    2. install (Vue, options) {
    3. Vue.prototype.util = {
    4. method1(val) {
    5. ...
    6. },
    7. method2 (val) {
    8. ...
    9. },
    10. }
    11. }
    在 main.js 通过 vue.use()注册
    1. import utils from './js/utils'
    2. Vue.use(utils)
    命名规范
    ——让团队当中其他人看你的代码能一目了然
  1. 文件夹和文件命名以业务或者模块名字为主,驼峰式命名。
  2. 组件命名遵循以下原则,使用驼峰命名(carLib)进行组件声明,使用短横线分隔命名(<car-lib></car-lib>)进行使用。
  3. 当项目中需要自定义比较多的基础组件的时候,比如一些 button,input,icon,建议以一个统一的前缀如 Base 开头,这样做的目的是为了方便查找。
  4. method 方法命名使用驼峰式,动词+名词,如 getData, submitForm
  5. 变量命遵循语义化原则,使用驼峰式。

    编码规范

    vue 风格推荐
    Prop 定义应该尽量详细。
    1. // bad
    2. props: ['status']
    3. // good
    4. props: {
    5. status: String
    6. }
    7. // better
    8. props: {
    9. status: {
    10. type: String,
    11. required: true,
    12. validator: function (value) {
    13. return ['syncing','synced','version-conflict','error'].indexOf(value) !== -1
    14. }
    15. }
    16. }
    使用 v-for 必须加上 key 值
    1. <!-- bad -->
    2. <ul>
    3. <li v-for="todo in todos">{{ todo.text }}</li>
    4. </ul>
    5. <!-- good -->
    6. <ul>
    7. <li v-for="todo in todos" :key="todo.id">{{ todo.text }}</li>
    8. </ul>
    不要把 v-if 和 v-for 同时用在同一个元素上。
    1. <!-- bad -->
    2. <ul>
    3. <li v-for="user in users" v-if="shouldShowUsers" :key="user.id">{{ user.name }}</li>
    4. </ul>
    5. <!-- good -->
    6. <ul v-if="shouldShowUsers">
    7. <li v-for="user in users" :key="user.id">{{ user.name }}</li>
    8. </ul>
    组件的 data 必须是一个函数
    1. // bad
    2. Vue.component('some-comp', {
    3. data: {
    4. foo: 'bar'
    5. }
    6. })
    7. // good
    8. Vue.component('some-comp', {
    9. data: function() {
    10. return {
    11. foo: 'bar'
    12. }
    13. }
    14. })
    组件模板应该只包含简单的表达式,复杂的表达式则应该重构为计算属性或方法。
    1. // bad
    2. {{
    3. fullName.split(' ').map(function (word) {
    4. return word[0].toUpperCase() + word.slice(1)
    5. }).join(' ')
    6. }}
    7. // good
    8. // 在模板中
    9. {{ normalizedFullName }}
    10. // 复杂表达式已经移入一个计算属性
    11. computed: {
    12. normalizedFullName: function () {
    13. return this.fullName.split(' ').map(function (word) {
    14. return word[0].toUpperCase() + word.slice(1)
    15. }).join(' ')
    16. }
    17. }
    指令缩写
    1. <!-- bad -->
    2. <input v-bind:value="newTodoText" :placeholder="newTodoInstructions" v-on:input="onInput" />
    3. <!-- good -->
    4. <input :value="newTodoText" :placeholder="newTodoInstructions" @input="onInput" />

    关于组件内样式
    为组件样式设置作用域
    1. /* bad */
    2. <style>
    3. .btn-close {
    4. background-color: red;
    5. }
    6. </style>
    7. /* good */
    8. <style scoped>
    9. .button-close {
    10. background-color: red;
    11. }
    12. </style>
    若要改变第三方组件库的样式,需要加上顶级作用域。
    1. /* bad */
    2. .ivu-input {
    3. width: 254px !important;
    4. }
    5. /* good */
    6. .customerForm .ivu-input {
    7. width: 254px !important;
    8. }
    9. /* .customerForm为当前组件的顶级dom */
    关于组件结构
    组件结构遵循从上往下 template,script,style 的结构。
    1. <template>
    2. <div></div>
    3. </template>
    4. <script>
    5. export default {}
    6. </script>
    7. <style lang="scss" scoped></style>
    script 部分各方法成员遵循以下顺序放置。 ```protobuf
  • name
  • components
  • props
  • data
  • methods
  • computed
  • watch
  • created
  • mounted
  • update ``` 关于注释规范
    以下情况需要加注释,以方便代码维护和他人理解

  • 公共组件使用说明

  • 各组件中重要函数或者类说明
  • 复杂的业务逻辑处理说明
  • 特殊情况的代码处理说明,对于代码中特殊用途的变量、存在临界值、函数中使用的 hack、使用了某种算法或思路等需要进行注释描述。
  • 多重 if 判断语句
    其他规范
    建议不再使用双引号,静态字符串使用单引号,动态字符串使用反引号衔接。
    1. // bad
    2. const foo = 'jack'
    3. const bar = foo + ',前端工程师'
    4. // good
    5. const foo = 'jack'
    6. const bar = `${foo},前端工程师`
    使用数组展开操作符 … 复制数组。
    1. // bad
    2. const len = items.length
    3. const itemsCopy = []
    4. let i
    5. for (i = 0; i < len; i += 1) {
    6. itemsCopy[i] = items[i]
    7. }
    8. // good
    9. const itemsCopy = [...items]
    使用数组对象解构赋值
    1. const arr = [1, 2, 3, 4]
    2. // bad
    3. const first = arr[0]
    4. const second = arr[1]
    5. // good
    6. const [first, second] = arr
    使用对象属性速记语法
    1. const name = 'Luke'
    2. const age = 20
    3. // bad
    4. const obj = {
    5. name: name,
    6. age: age
    7. }
    8. // good
    9. const obj = {
    10. name,
    11. age
    12. }
    百度统计
    在 index.html 添加百度统计脚本
    1. var _hmt =
    2. _hmt ||
    3. [](function() {
    4. var hm = document.createElement('script')
    5. hm.src = 'https://hm.baidu.com/hm.js?d1dbfd0ce8ca70cf72828b2844498250'
    6. var s = document.getElementsByTagName('script')[0]
    7. s.parentNode.insertBefore(hm, s)
    8. })()
    在全局路由守卫添加需要统计的页面
    1. router.afterEach(to => {
    2. if (window._hmt) {
    3. window._hmt.push(['_trackPageview', '/#' + to.fullPath])
    4. }
    5. })