Vue的编码技巧与规范使用详解


Posted in Javascript onAugust 28, 2019

当我们完成项目的构建,进入开发阶段的时候,除了你需要了解框架本身的知识点外,我们还需要提前掌握一些项目的编码技巧与规范,在根源上解决之后因编码缺陷而导致的项目维护困难、性能下降等常见问题,为项目多人开发提供编码的一致性。

本文将罗列项目中常用的一些编码技巧与规范来帮助大家提升代码质量,并会结合代码片段加强大家的理解与认知。当然不是所有实例都是针对 Vue.js 开发的,有些同样也适用于其他前端项目。

实例

1. 使用对象代替 if 及 switch

在很多情况下,我们经常会遇到循环判断执行赋值操作的场景,一般我们都会使用 if 及 switch 的条件判断,如果符合则执行赋值,不符合则进入下个判断,比如:

let name = 'lisi';
let age = 18;

if (name === 'zhangsan') {
 age = 21;
} else if (name === 'lisi') {
 age = 18;
} else if (name === 'wangwu') {
 age = 12;
}

// 或者
switch(name) {
 case 'zhangsan':
  age = 21;
  break
 case 'lisi':
  age = 18;
  break
 case 'wangwu':
  age = 12;
  break
}

这样的写法不仅冗余,而且代码执行效率不高,我们可以使用对象的形式简写:

let name = 'lisi';
let obj = {
 zhangsan: 21,
 lisi: 18,
 wangwu: 12
};

let age = obj[name] || 18;

以上这种技巧适用于循环判断一次赋值的情况,如果判断过后有较多处理逻辑的还需要使用 if 或 switch 等方法。

2. 使用 Array.from 快速生成数组

一般我们生成一个有规律的数组会使用循环插入的方法,比如使用时间选择插件时,我们可能需要将小时数存放在数组中:

let hours = [];

for (let i = 0; i < 24; i++) {
 hours.push(i + '时');
}

如果使用 Array.from 我们可以简写为:

let hours = Array.from({ length: 24 }, (value, index) => index + '时');

3. 使用 router.beforeEach 来处理跳转前逻辑

在某些情况下,我们需要在路由跳转前处理一些特定的业务逻辑,比如修改路由跳转、设置 title 等,代码如下:

import Vue from 'vue'
import Router from 'vue-router'

Vue.use(Router)

// 首页
const Home = (resolve => {
 require.ensure(['../views/home.vue'], () => {
  resolve(require('../views/home.vue'))
 })
})

let base = `${process.env.BASE_URL}`;

let router = new Router({
 mode: 'history',
 base: base,
 routes: [
  {
   path: '/',
   name: 'home',
   component: Home,
   meta: { title: '首页' }
  },
 ]
})

router.beforeEach((to, from, next) => {
 let title = to.meta && to.meta.title;
 
 if (title) {
  document.title = title; // 设置页面 title
 }
 
 if (to.name === 'home') {
 
  // 拦截并跳转至 page2 单页,$openRouter 方法在第 5 节中封装
  Vue.$openRouter({
   name: 'page2'
  });
 }
 
 next();
})

export default router

注意最后需要调用 next() 方法执行路由跳转。

4. 使用 v-if 来优化页面加载

在 Vue 页面中,一些模块可能需要用户主动触发才会显示,比如弹框组件等这样的子组件,那么我们可以使用 v-if 来进行按需渲染,没必要一进页面就渲染所有模块。比如:

<template>
 <div @click="showModuleB = true"></div>
 <module-b v-if="isShowModuleB"></module-b>
</template>

<script>
import moduleB from 'components/moduleB'
export default {
 data() {
  return {
   isShowModuleB: false
  } 
 },
 components: {
  moduleB
 }
}
</script>

这样当 isShowModuleB 为 false 的时候便不会加载该模块下的代码,包括一些耗时的接口调用。当然 v-if 主要适用于代码量较多、用户点击不是很频繁的模块的显示隐藏,同时如果涉及到权限问题的代码都需要使用 v-if,而不是 v-show。

5. 路由跳转尽量使用 name 而不是 path

我们前期配置的路由路径后期难免会进行修改,如果我们页面跳转的地方全是使用的 path,那么我们需要修改所有涉及该 path 的页面,这样不利于项目的维护。而相对于 path,name 使用起来就方便多了,因为其具有唯一性,即使我们修改了 path,还可以使用原来的 name 值进行跳转。

this.$router.push({ 
 name: 'page1'
});

// 而不是
this.$router.push({ 
 path: 'page1'
});

6. 使用 key 来优化 v-for 循环

v-for 是 Vue 提供的基于源数据多次渲染元素或模板块的指令。正因为是数据驱动,所以在修改列表数据的时候,Vue 内部会根据 key 值去判断某个值是否被修改,其会重新渲染修改后的值,否则复用之前的元素。

这里如果数据中存在唯一表示 id,则推荐使用 id 作为 key,如果没有则可以使用数组的下标 index 作为 key。因为如果在数组中间插入值,其之后的 index 会发生改变,即使数据没变 Vue 也会进行重新渲染,所以最好的办法是使用数组中不会变化且唯一的那一项作为 key 值。例如:

<template>
 <ul>
  <li v-for="(item, index) in arr" :key="item.id">{{ item.data }}</li>
 </ul>
</template>

<script>
export default {
 data() {
  return {
   arr: [
    {
     id: 1,
     data: 'a'
    },
    {
     id: 2,
     data: 'b'
    },
    {
     id: 3,
     data: 'c'
    }
   ]
  }
 }
}
</script>

7. 使用 computed 代替 watch

很多时候页面会出现 watch 的滥用而导致一系列问题的产生,而通常更好的办法是使用 computed 属性,首先需要区别它们有什么区别:

  • watch:当监测的属性变化时会自动执行对应的回调函数
  • computed:计算的属性只有在它的相关依赖发生改变时才会重新求值

其实它们在功能上还是有所区别的,但是有时候可以实现同样的效果,而 computed 会更胜一筹,比如:

<template>
 <div>
  <input type="text" v-model="firstName">
  <input type="text" v-model="lastName">
  <span>{{ fullName }}</span>
  <span>{{ fullName2 }}</span>
 </div>
</template>

<script>
export default {
 data() {
  reurn {
   firstName: '',
   lastName: '',
   fullName2: ''
  }
 },
 
 // 使用 computed
 computed: {
  fullName() {
   return this.firstName + ' ' + this.lastName
  }
 },
 
 // 使用 watch
 watch: {
  firstName: function(newVal, oldVal) {
   this.fullName2 = newVal + ' ' + this.lastName;
  },
  lastName: function(newVal, oldVal) {
   this.fullName2 = this.firstName + ' ' + newVal;
  },
 }
}
</script>

上方我们通过对比可以看到,在处理多数据联动的情况下,使用 computed 会更加合理一点。

Vue的编码技巧与规范使用详解

computed 监测的是依赖值,依赖值不变的情况下其会直接读取缓存进行复用,变化的情况下才会重新计算;而 watch 监测的是属性值, 只要属性值发生变化,其都会触发执行回调函数来执行一系列操作。

8. 统一管理缓存变量

在项目中或多或少会使用浏览器缓存,比如 sessionStorage 和 localStorage,当一个项目中存在很多这样的缓存存取情况的时候就会变得难以维护和管理,因为其就像全局变量一样散落在项目的各个地方,这时候我们应该将这些变量统一管理起来,放到一个或多个文件中去,比如:

/* types.js */

export const USER_NAME = 'userName';
export const TOKEN = 'token';

在需要存取的时候,直接引用:

import { USER_NAME, TOKEN } from '../types.js'

sessionStorage[USER_NAME] = '张三';
localStorage[TOKEN] = 'xxx';

使用这种方法的好处在于一旦我们需要修改变量名,直接修改管理文件中的值即可,无需修改使用它的页面,同时这也可以避免命名冲突等问题的出现,这类似于 vuex 中 mutations 变量的管理。

9. 使用 setTimeout 代替 setInterval

一般情况下我们在项目里不建议使用 setInterval,因为其会存在代码的执行间隔比预期小以及 “丢帧” 的现象,原因在于其本身的实现逻辑。很多人会认为 setInterval 中第二个时间参数的作用是经过该毫秒数执行回调方法,其实不然,其真正的作用是经过该毫秒数将回调方法放置到队列中去,但是如果队列中存在正在执行的方法,其会等待之前的方法完毕再执行,如果存在还未执行的代码实例,其不会插入到队列中去,也就产生了 “丢帧”。

而 setTimeout 并不会出现这样的现象,因为每一次调用都会产生了一个新定时器,同时在前一个定时器代码执行完之前,不会向队列插入新的定时器代码。

// 该定时器实际会在 3s 后立即触发下一次回调
setInterval(() => {
 // 执行完这里的代码需要 2s
}, 1000);

// 使用 setTimeout 改写,4秒后触发下一次回调
let doSometing = () => {
 // 执行完这里的代码需要 2s
 
 setTimeout(doSometing, 1000);
}

doSometing();

延伸阅读:对于“不用setInterval,用setTimeout”的理解

10. 不要使用 for in 循环来遍历数组

大家应该都知道 for in 循环是用于遍历对象的,但它可以用来遍历数组吗?答案是可以的,因为数组在某种意义上也是对象,但是如果用其遍历数组会存在一些隐患:其会遍历数组原型链上的属性。

let arr = [1, 2];

for (let key in arr) {
 console.log(arr[key]); // 会正常打印 1, 2
}

// 但是如果在 Array 原型链上添加一个方法
Array.prototype.test = function() {};

for (let key in arr) {
 console.log(arr[key]); // 此时会打印 1, 2, ƒ () {}
}

因为我们不能保证项目代码中不会对数组原型链进行操作,也不能保证引入的第三方库不对其进行操作,所以不要使用 for in 循环来遍历数组。

结语

本文罗列了 10 个项目开发中常见的编码技巧与规范,其实技巧和规范之间本身就是相辅相成的,所以没有分别进行罗列。当然实际的项目开发中存在着很多这样的例子需要大家自己去归纳和整理,比如使用 name 来命名你的组件等。如果你有不错的点子,也可以分享在下方的评论区域中供大家学习。

拓展阅读:前端各类规范集合

思考 & 作业

  • 可以使用哪些技巧来实现数组的循环遍历、去重等?
  • 在 Vue 项目中如何使用 ESLint 来规范 JS 代码的编写?
  • .vue 单文件组件中如何进行代码的格式化?

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
如何取得中文输入的真实长度?
Jun 24 Javascript
javascript 复杂的嵌套环境中输出单引号和双引号
May 26 Javascript
一个很酷的拖动层的js类,兼容IE及Firefox
Jun 23 Javascript
JavaScript字符串插入、删除、替换函数使用示例
Jul 25 Javascript
firefox浏览器不支持innerText的解决方法
Aug 07 Javascript
js实现日期级联效果
Jan 23 Javascript
Jquery实现控件的隐藏和显示实例
Feb 08 Javascript
JavaScript设计模式之策略模式实例
Oct 10 Javascript
使用JavaScript实现ajax的实例代码
May 11 Javascript
一个非常好用的文字滚动的案例,鼠标悬浮可暂停[两种方案任选]
Dec 01 Javascript
原生js实现日期选择插件
May 21 Javascript
vue使用axios实现excel文件下载的功能
Jul 16 Javascript
JS开发自己的类库实例分析
Aug 28 #Javascript
详解Vue 换肤方案验证
Aug 28 #Javascript
Vue项目实现换肤功能的一种方案分析
Aug 28 #Javascript
js遍历详解(forEach, map, for, for...in, for...of)
Aug 28 #Javascript
Angular6使用forRoot() 注册单一实例服务问题
Aug 27 #Javascript
jQuery - AJAX load() 实例用法详解
Aug 27 #jQuery
JS实现提示框跟随鼠标移动
Aug 27 #Javascript
You might like
超强分页类2.0发布,支持自定义风格,默认4种显示模式
2007/01/02 PHP
php下关于Cannot use a scalar value as an array的解决办法
2010/08/08 PHP
ThinkPHP之A方法实例讲解
2014/06/20 PHP
php使用wordwrap格式化文本段落的方法
2015/03/17 PHP
PHPWind9.0手动屏蔽验证码解决后台关闭验证码但是依然显示的问题
2016/08/12 PHP
PHP基于rabbitmq操作类的生产者和消费者功能示例
2018/06/16 PHP
PHP实现基本留言板功能原理与步骤详解
2020/03/26 PHP
JavaScript 学习笔记(六)
2009/12/31 Javascript
微博@符号的用户名提示效果。(想@到谁?)
2010/11/05 Javascript
关于js拖拽上传 [一个拖拽上传修改头像的流程]
2011/07/13 Javascript
兼容IE、firefox以及chrome的js获取时间(getFullYear)
2014/07/04 Javascript
js获取当前日期前七天的方法
2015/02/28 Javascript
快速将Vue项目升级到webpack3的方法步骤
2017/09/14 Javascript
angularjs中判断ng-repeat是否迭代完的实例
2018/09/12 Javascript
Vue 实现复制功能,不需要任何结构内容直接复制方式
2019/11/09 Javascript
[01:34]2014DOTA2 TI预选赛预选赛 选手比赛房大揭秘!
2014/05/20 DOTA
[53:18]Spirit vs Liquid Supermajor小组赛A组 BO3 第三场 6.2
2018/06/03 DOTA
[01:45:05]VGJ.T vs Newbee Supermajor 败者组 BO3 第二场 6.6
2018/06/07 DOTA
学习python 之编写简单乘法运算题
2016/02/27 Python
python 通过logging写入日志到文件和控制台的实例
2018/04/28 Python
python 信息同时输出到控制台与文件的实例讲解
2018/05/11 Python
python定时检测无响应进程并重启的实例代码
2019/04/22 Python
Python使用ffmpy将amr格式的音频转化为mp3格式的例子
2019/08/08 Python
介绍一下linux的文件系统
2012/03/20 面试题
工业设计专业个人求职信范文
2013/12/28 职场文书
中医临床专业自我鉴定范文
2014/01/15 职场文书
人力资源经理的岗位职责范本
2014/02/28 职场文书
师德师风个人反思
2014/04/28 职场文书
升旗仪式演讲稿
2014/05/08 职场文书
敬老模范事迹
2014/05/21 职场文书
爱护公共设施演讲稿
2014/09/13 职场文书
成都人事代理协议书
2014/10/25 职场文书
地方白酒代理协议书
2014/10/25 职场文书
早恋主题班会
2015/08/14 职场文书
长辈生日祝福语大全(72句)
2019/08/09 职场文书
sql注入教程之类型以及提交注入
2021/08/02 MySQL