在以前,我们写好静态的 html 后,多数的动态渲染是交给 jquery 来重写的,这样的操作无疑增加了维护的复杂性。于是,我们开始对老系统前端上使用了Vue 2.0 + Babel
的架构。
为什么说Vue比jQuery好呢?
这主要从他们的原理着手。jq主要运用 Vanilla JS
的选择器机制。通过选择器筛选整个 html 页面的 DOM,然后使用链式函数来处理数据或重新渲染。相比之下,Vue.js 2.x
引入 Virtual DOM
,比 Vue.js 1.x
的初始渲染速度提升了2-4倍,并大大降低了内存消耗。Virtual DOM
的概念最初由Google工程师提出,后在Meta的React
框架中得到大规模的运用。相比于频繁的手动去操作dom而带来性能问题,vdom很好的将dom做了一层映射关系,进而将在我们本需要直接进行dom的一系列操作,映射到了操作vdom,而vdom上定义了关于真实dom的一些关键的信息,vdom完全是用js去实现,和宿主浏览器没有任何联系,此外得益于js的执行速度,将原本需要在真实dom进行的创建节点,删除节点,添加节点等一系列复杂的dom操作全部放到vdom中进行,这样就通过操作vdom来提高直接操作的dom的效率和性能。不仅如此,它也受 MVVM
的思想的影响,支持模块化及模板等功能。开发过程在就可以将html页面重新组织为多个View Model
从而降低前端开发的重复工作的时间成本。
虽然去年Vue升级到了第3版,但考虑稳定的生产环境,还是就目前情况推荐文档较多(其他开发者的踩坑文档)的Vue2。
Babel 让 IE 也能支持ES6的编译器
在国内绝大多数的生产环境都还是2010年的Web产物居多。并不是所有的公司都能拥有如BAT这样紧随时代技术的开发人员。例如一些地方的发票系统,还有一些院校或公共设施的后台系统。当然,也有一些例外,12306据说是委派拥有BAT相似能力的公司做的——神奇的验证功能(某个清华毕业生做的)。因此,项目至少需要保留ES2015的支持。
由此,我就找到了babel这个工具。只能说外国工程师和国内的不一样(腾讯和百度各自直接开发了一个浏览器,兼容当时的IE、FF、Chrome——加个Ad就能ZQ)。
ES6 和 ES5 的特点
ES6包括以下重要特性:
ES6 特性
- 箭头:这些是由 '=>' 语法描述的函数
- 对象:对象字面量用于支持原型分配。
- Classes: ES6 类可以通过基于原型的面向对象模式轻松实现
- Destructing:它允许绑定模式,这主要基于模式匹配。
- 字符串插值
- 缺省
- 传播
- 模块加载器
- Weak set
- Map
- New Library
- Promises
- Proxies
ECMA Script 的第五版被称为 ES5 和 ECMA Script 2009。ES5 包括以下重要特性:
ES5 功能
- Strict Mode:它基本上通过应用更多检查和清理一些现有功能来帮助javascript语言更有效地执行
- Accessors :它允许用户通过使用方法来实现属性的获取和设置。
- 语法变化:
- 尾随逗号
- 多行字符串文字
- 使用保留字的属性键
- 附加功能:在 ES5 中引入了一些附加的新功能。
- 元编程:不同的原型用于相同的
- Object.getPrototypeOf()
- Object.create()
- Object.defineProperty()
- Object.keys()
- Object.seal()
- Object.freeze() etc.
- 新方法
- String.prototype.trim()
- Array.isArray()
- Array.prototype.indexOf()
- Array.prototype.map()
- 括号运算符的使用
- JSON:
- JSON.parse()
- JSON.stringify()
- 特定于 JSON 的内置对象:
- Boolean.prototype.toJSON()
- Number.prototype.toJSON()
- String.prototype.toJSON()
- 元编程:不同的原型用于相同的
相较而言两者语法:我更觉得ES6有了很多编译型语言的特性,而且语法更为简易,事实上也属于ES5和TS之间的过渡语言。最重要的是可以基于面对对象(原型)进行开发和维护。
Vue坑:
在Vue中,也存在一些坑。我就简单介绍一个常见的
Vue重新渲染
Vue重新渲染的方法其实有很多种。如 Michael Thiessen所言:
- 可怕的方式:重新加载整个页面
- 可怕的方式:使用v-if hack
- 更好的方法:使用 Vue 的内置forceUpdate方法
- 最佳方法:在组件上更换Key
可怕的方式:重新加载整个页面
相当于每次要关闭应用程序时重新启动计算机。
window.location.reload();
复制代码
可怕的方式:使用v-if hack
Vue 附带了一个指令,该指令仅在为 true 时才会呈现组件。如果为 false,则该组件将根本不存在于 DOM.
以下是我们如何设置它以使hack工作.
你可以添加template
<template>
<component v-if="renderComponent" />
</template>
复制代码
在你的方法中使用scriptnextTick
export default {
data() {
return {
renderComponent: true,
};
},
methods: {
forceRerender() {
// Remove component from the DOM
this.renderComponent = false;
this.$nextTick(() => {
// Add the component back in
this.renderComponent = true;
})
}
}
}
复制代码
这里主要是通过Vue的生命周期原理来实现的。
更好的方法:使用 Vue 的内置forceUpdate方法
如果 Vue 在事情发生变化时自动更新,我们为什么要强制更新?
原因是有时 Vue 的反应系统可能会令人困惑,我们认为Vue 会对某个属性或变量的更改做出反应,但实际上并非如此。在某些情况下,Vue的反应系统根本不会检测到任何变化。
因此,就像最后的方法一样,如果您需要它来重新渲染组件,则可能有更好的方法。
您可以通过两种不同的方式在组件实例本身上以及全局调用 :forceUpdate
// Globally
import Vue from 'vue';
Vue.forceUpdate();
// Using the component instance
export default {
methods: {
methodThatForcesUpdate() {
// ...
this.$forceUpdate(); // Notice we have to use a $ here
// ...
}
}
}
复制代码
最佳方法:在组件上更换Key
Vue中key属性的作用
最简单的做法:
<template>
<component-to-re-render :key="componentKey" />
</template>
export default {
data() {
return {
componentKey: 0
};
},
methods: {
forceRerender() {
this.componentKey += 1;
}
}
}
复制代码
每次被调用时,我们的道具都会改变。当这种情况发生时,Vue 将知道它必须销毁组件并创建一个新组件。forceRerendercomponentKey
你得到的是一个子组件,它将重新初始化自身并"重置"它的状态。
一个简单而优雅的方式来解决我们的问题!
但是,如果您确实需要重新渲染某些内容,请选择key-changing方法而不是其他任何方法。
Babel 中 this 定义为 undefined
在Babel的箭头语法中会出现this定义为undefined。遇到这种情况往往需要将自己的箭头函数改为常用的function语句就可以了。
babel编译
package.js
"dependencies": {
"babel-cli": "^6.26.0",
"babel-polyfill": "^6.26.0",
"babel-preset-env": "^1.7.0",
"babel-preset-es2015": "^6.24.1",
"babel-preset-es2015-ie": "^6.7.0"
}
复制代码
命令为:
$ ./node_modules/babel-cli/bin/babel.js --presets babel-preset-es2015-ie \
target.js -o output.js
复制代码
推荐编写bash、zsh、bat之类的脚本来实现批处理。
感谢
写作不宜,请多多支持。同时也非常感谢参考文档中的作者。
参考文档:
- Priya Pedamkar 的 Difference Between ES6 vs ES5
- Michael Thiessen 的 强制 Vue 重新渲染组件的正确方法
- 考拉比利 的 Vue中key属性的作用
- michaelnthiessen.com 的 The Key Changing Technique
- Babel replaces this with undefined