# 函数定义

动词+名词组合,驼峰拼接,体现动作和作用对象

动词 含义 用法示例
get 获取某个值 getList
set 设置某个值 setData
switch 切换某个值 switchTab

# 变量定义

标志性变量须固定前缀

前缀 含义 类型 用法示例
show dom 节点显示隐藏 Boolean v-if/v-show="showDom"
is 表示"是不是"含义的 Boolean isCheck
has 表示"有没有"含义的 Boolean hasList
able 表示"能不能"含义的 Boolean ableSubmit // true 能,false 不能
:disabled="!ableSubmit"

v-for 遍历的 list 变量

单页面若只有一个列表,直接用 mainList;若有多个列表,可自定义语义化的 list

变量名 含义 类型
mainList 主列表 Array
doctorList、deptList... 语义化列表 Array

v-for 循环代参

// 一级循环
v-for="(item, index) in xxxList"
// 二级循环:j标识
v-for="(jitem, jindex) in item.xxx"
// 三级循环:k标识
v-for="(kitem, kindex) in jitem.xxx"

# js 值为假的情况

类型 含义/使用场景
false boolean 非真即假的情况
null null 初始化一个将来可能被赋值为"对象"的变量
作为函数的返回值
undefined undefined 函数声明未赋值时的默认值
' ' string 空字符串
0 number 数值 0
NaN number 数值 NaN
// not good
if (param !== null && param !== undefined && param !== "") {
}

// good
if (param) {
}

# 生命周期书写顺序

  • mixin
  • components
  • props
  • data
  • filter
  • computed
  • watch
  • beforeCreate
  • created
  • beforeMount
  • mounted
  • beforeUpdate
  • updated
  • activated
  • deactivated
  • beforeDestroy
  • destroyed
  • errorCaptured
  • methods

# 加载中&无数据

  • 无数据变量(nodata)
参数 含义
nodata nodata = null 初始化
nodata nodata === true 无数据(true 可省略)
nodata nodata === false 有数据(一般用不上)
  • 计算列表是否无数据方法
/**
  * @description 计算列表是否无数据
  * @param {Array} list 列表
  * @return {Boolean}
  */
switchNodata (list) {
  return !list || list.length === 0
}
  • vuex/state.js 定义所需全局变量
const state = {
  isLoading: false, // 是否显示加载中遮罩层
  loadingText: "" // 加载中文字提示
};
  • 在 request/index.js 请求封装,统一控制加载中遮罩层的显示隐藏

可以通过方法调起加载中遮罩层,一般用于移动端

全局变量控制加载中控件的显示隐藏,一般用于 PC 端(不需要每个页面定义变量)

import store from '@/store'
/**
  * @param option {
      isLoading: {Boolean} 是否显示加载中,默认false
      loadingText: {String} 加载中文字提示,默认'加载中...'
      ...
    }
  * @return {Promise} 请求结果
  */
const post = (option) => {
    if (option.isLoading) {
        if(mobile) {
            wx.showLoading({
                title: option.loadingText || '加载中...'
            })
        } else {
            store.commit(this.$types.SET_IS_LOADING, true)
            store.commit(this.$types.SET_LOADING_TEXT, option.loadingText)
        }
    }
    return new Promise((resolve, reject) => {
        ...
        // 请求完成
        success: (res) => {
            if(mobile) {
                if (hasLoading) {
                    wx.hideLoading()
                }
            } else {
                store.commit(this.$types.SET_IS_LOADING, false)
            }
        }
    }
}
  • xxx.vue 具体实现
<template>
  <!-- 移动端 -->
  <empty v-if="nodata" title="无数据"></empty>
  <ul>
    <li v-for="(item, index) in mainList" :key="index"></li>
  </ul>

  <!-- PC端,element-ui自带无数据判断 -->
  <el-table
    v-loading="isLoading"
    :data="tableData"
    :empty-text="无数据"
  ></el-table>
</template>
<script>
  data() {
    return {
      nodata: null
    }
  },
  computed: {
    isLoading() {
      return this.$store.state.isLoading
    }
  },
  methods: {
    getList() {
      this.$post({
        isLoading: true,
        ...
      }).then(res => {
        this.list = res.data
        this.nodata = this.$util.switchNodata(this.list)
      })
    }
  }
</script>

# 更好的写法

# 变量声明

一个函数作用域中所有的变量声明尽量提到函数首部,用一个 var 声明,不允许出现两个连续的 var 声明。

// not good
var value = 10;
var result = value + 10;
var i;
var len;

// good
var value = 10,
  result = value + 10,
  i,
  len;

# 数组、对象

  • 使用字面值创建对象

  • 对象属性名不需要加引号

  • 对象以缩进的形式书写,不要写在一行

  • 数组、对象最后不要有逗号

  • 语句末尾不加分号

// not good
var item = new Object();

// good
var item = {};

// not good
var a = {
  b: 1
};

// good
var a = { b: 1 };

// not good
var a = {
  b: 1,
  c: 2
};

// good
var a = {
  b: 1,
  c: 2
};

# if else 改造

多层 if else 嵌套会使得代码不易理解,使用一些技巧改造 if else 帮助你写出更优雅的逻辑控制。

  • 条件是否有关联,看一个登陆验证的场景
// bad
sumbit(){
  if(hasUserName){
    if(hasPassword){
      // other code
    }
  }else{

  }
}
// good
sumbit(){
  if(!hasUserName){
    return console.log("请输入名称")
  }
  if(!hasPassword){
    return console.log("请输入密码")
  }
  // other code
}
  • 条件之间有关联时,if else 改写。来看一个登陆成功的场景,假设用户身份为 common,vip,svip
// bad
if (userLevel === 0) {
  console.log("common");
} else if (userLevel === 1) {
  console.log("vip");
} else {
  console.log("svip");
}

// good
const userLevelArr = ["common", "vip", "svip"];
console.log(userLevelArr[userLevel]);

如果的判断条件不是数字怎么办呢?

// bad
if (userLevel === "common") {
  console.log("common");
} else if (userLevel === "vip") {
  console.log("vip");
} else {
  console.log("svip");
}

// good
const userLevelObj = {
  common: "common",
  vip: "vip",
  svip: "svip"
};
console.log(userLevelObj[userLevel]);
  • if else 简写技巧
// 一般写法
if (userLevel === "common") {
  console.log("common");
}
// 简写
userLevel === "common" && console.log("common");
userLevel !== "common" || console.log("common");
  • 条件强关联使用责任链模式,例如: vip 且入网满两年的用户送流量
// bad
if (userLevel === "vip") {
  if (useAge > 2) {
    console.log("赠送流量");
  } else {
    console.log("入网不满两年");
  }
} else {
    if (useAge > 2) {
    console.log("您不是vip");
  } else {
    console.log("您不是vip且入网不满两年");
  }
}

// perfect
const rules = [
  {
    match : function(isVip,hasTowYear){
        return isVip && hasTowYear
    },
    action : function(){
        console.log("赠送流量")
    }
  },
  {
    match : function(isVip,hasTowYear){
        return !isVip && hasTowYear
    },
    action : function(){
        console.log("您不是Vip")
    }
  },
  {
    match : function(isVip,hasTowYear){
        return isVip && !hasTowYear
    },
    action : function(){
        console.log("入网不满两年")
    }
  },
  {
    match : function(isVip,hasTowYear){
        return !isVip && !hasTowYear
    },
    action : function(){
        console.log("您不是vip且入网不满两年")
    }
  }
]

// 责任链模式,当逻辑变动时只需修改对应的数组
handler(isVip,hasTowYear){
  for(let i in rules){
    rules[i].match(...arg) && rules[i].action(...arg)
  }
}

# 规范细则

  • 方法遵循单一职责原则,一个方法只做一件事情,不可把方法写的过于复杂

  • 避免 this 指向问题,方法统一用 es6 箭头函数,因为 es6 箭头函数的内部没有 this,因此函数内的 this 就是声明函数时所处上下文中的 this
    对上下文 this 的引用统一使用 self 来定义

  • 尽量用'===', '!=='代替'==', '!='

  • 异步方法尽量用 Async/await

// async方法定义
async getPatientList() {
    await this.$post({
        url: xxx,
        param: xxx
    }).then(res => {
        this.patientList = res.data.list
    })
}
// 在普通方法调用
demo1 () {
    this.getPatientList().then(() => {
        this.checkedPatient = this.patientList[0]
    })
}
// 在异步方法调用
async demo2() {
    await this.getPatientList()
    this.checkedPatient = this.patientList[0]
}
  • 无序静态列表(如个人中心我的 xxx),用循环来写,差异在 data 中去处理
data() {
    return {
        myList: [
            {
                icon: 'theicon-myrecipe',
                title: '我的处方',
                tapEvent: () => {
                    this.$router.push('/pages/buy_medicine')
                }
            },
            {
                icon: 'theicon-feedback',
                title: '帮助与反馈',
                tapEvent: () => {
                    this.$router.push('/pages/personal/help_feedback_manage')
                }
            }
        ]
    }
}
  • 返回上一页统一用 $router.back() 方法,不用 $router.go()

  • 避免重复跳转的页面(如下单),用 $router.replace 重定向跳转下一页

  • 路由懒加载

// not good
{
  path: '/index',
  name: 'index',
  component: resolve => require(['@/pages/index.vue'], resolve)
}
// good
{
  path: '/index',
  name: 'index',
  component: () => import('@/pages/index.vue')
}
  • 组件懒加载
// not good
components: {
  dialogUserinfo: resolve => {
    require(["@/components/dialogUserinfo.vue"], resolve);
  };
}

// good
components: {
  dialogUserinfo: () => import("@/components/dialogUserinfo");
}
  • 使用 es6/es7 语法请用 babel-polyfill 组件进行转译

  • 所有变量 / 函数先声明后使用

  • 尽量避免使用 eval()

更新时间: 7/17/2020, 4:28:25 PM