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 相关文章推荐
任意位置显示html菜单
Feb 01 Javascript
在网页中使用document.write时遭遇的奇怪问题
Aug 24 Javascript
jquery提交form表单时禁止重复提交的方法
Feb 13 Javascript
很全面的JavaScript常用功能汇总集合
Jan 22 Javascript
AngularJS路由切换实现方法分析
Mar 17 Javascript
史上最全JavaScript数组去重的十种方法(推荐)
Aug 17 Javascript
使用Angular 6创建各种动画效果的方法
Oct 10 Javascript
mpvue全局引入sass文件的方法步骤
Mar 06 Javascript
微信小程序云开发修改云数据库中的数据方法
May 18 Javascript
《javascript设计模式》学习笔记三:Javascript面向对象程序设计单例模式原理与实现方法分析
Apr 07 Javascript
详解Vue3中对VDOM的改进
Apr 23 Javascript
vue中三级导航的菜单权限控制
Mar 31 Vue.js
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
php上传文件的增强函数
2010/07/21 PHP
Laravel中使用自己编写类库的3种方法
2015/02/10 PHP
laravel学习教程之关联模型
2016/07/30 PHP
Laravel中如何轻松容易的输出完整的SQL语句
2020/07/26 PHP
新浪刚打开页面出来的全屏广告代码
2007/04/02 Javascript
JQuery 1.6发布 性能提升,同时包含大量破坏性变更
2011/05/10 Javascript
createElement与createDocumentFragment的点点区别小结
2011/12/19 Javascript
JavaScript 基础篇之运算符、语句(二)
2012/04/07 Javascript
ubuntu下安装nodejs以及升级的办法
2015/05/08 NodeJs
Bootstrap中点击按钮后变灰并显示加载中实例代码
2016/09/23 Javascript
js 事件的传播机制(实例讲解)
2017/07/20 Javascript
Angular模板表单校验方法详解
2017/08/11 Javascript
Node.js创建HTTP文件服务器的使用示例
2018/05/11 Javascript
微信小程序点击列表跳转到对应详情页过程解析
2019/09/26 Javascript
VUE:vuex 用户登录信息的数据写入与获取方式
2019/11/11 Javascript
vue实现页面切换滑动效果
2020/06/29 Javascript
[01:25:33]完美世界DOTA2联赛PWL S3 INK ICE vs Magma 第二场 12.20
2020/12/23 DOTA
总结网络IO模型与select模型的Python实例讲解
2016/06/27 Python
TensorFlow用expand_dim()来增加维度的方法
2018/07/26 Python
pycharm的console输入实现换行的方法
2019/01/16 Python
python与字符编码问题
2019/05/24 Python
python中id函数运行方式
2020/07/03 Python
利用python进行文件操作
2020/12/04 Python
Python3.9.1中使用match方法详解
2021/02/08 Python
CSS3+js实现简单的时钟特效
2015/03/18 HTML / CSS
简单html5代码获取地理位置
2014/03/31 HTML / CSS
html5通过postMessage进行跨域通信的方法
2017/12/04 HTML / CSS
英格兰橄榄球商店:England Rugby Store
2016/12/17 全球购物
sort命令的作用和用法
2013/08/25 面试题
《学会合作》教学反思
2014/04/12 职场文书
春节联欢会策划方案
2014/05/16 职场文书
2014年度党员自我评议
2014/09/13 职场文书
法人单位适用的授权委托书
2014/09/19 职场文书
十八大标语口号
2014/10/09 职场文书
2014年银行信贷员工作总结
2014/12/08 职场文书
2015年语文教学工作总结
2015/05/25 职场文书