本文主要包含以下知识点:
- Vue 基本介绍
- Vue 的安装
- 快速入门案例
- 生命周期
- Vue 与 jQuery 对比
Vue 基本介绍
Vue 是一套用于构建用户界面的渐进式框架。
与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。其核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。
另一方面,当与单文件组件和 Vue 生态系统支持的库结合使用时,Vue 也完全能够为复杂的单页应用程序提供驱动。
注意:由于 Vue 使用 getter/setter 等 ECMAScript 5 特性,所以兼容到 Internet Explorer 9。
框架和库的区别?
-
框架字面上理解为架子,会基于自身的特点为用户提供一整套的解决方案,倾向于创造一套需要你来遵守的规则和范例,你可以基于这套架子快速实现应用,但前提是你必须按照它的规则来写。
例如:thinkphp 框架,必须要求你按照它的命名规则、代码组织结构来写。
-
库是代码集合成的一个产品,供程序员调用,例如:jquery 库,只需要引入使用它的功能就可以了,至于你的应用怎样架构,项目目录怎样组织它完全由你自己决定。
渐进式框架
明白了框架和库的区别之后,这里还涉及到一个新词,渐进式框架。那什么是渐进式框架呢?
正如上图所示:
- 如果只使用 Vue 最基础的声明式渲染的功能,则完全可以把 Vue 当做一个模板引擎来使用
- 如果想以组件化开发方式进行开发,则可以进一步使用 Vue 里面的组件系统
- 如果要制作 SPA(单页应用),则可以使用 Vue 里面的客户端路由功能
- 如果组件越来越多,需要共享一些数据,则可以使用 Vue 里的状态管理
- 如果想在团队里执行统一的开发流程或规范,则使用构建工具
Vue 的官网为:https://cn.vuejs.org/
从 Vue 的官网中,我们可以看到官方对 Vue 特点的介绍,易用、灵活以及高效。
这些特点,我们都会在 Vue 的学习中逐步的体会到。
在 Vue 官网中,还提供了非常完善的学习文档和 API 查询手册。你可以跟着官网所提供的教程,一步一步系统地进行 Vue 的学习。
本套教程内容也是基于 Vue 官网教程内容所编写的。
Vue 的安装
在官网中,介绍了好几种 Vue 安装的方式。
但是对于初学者来讲,最简单的方式就是直接通过 CDN 进行引用。
如下:
<!-- 开发环境版本,包含了有帮助的命令行警告 -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
或者:
<!-- 生产环境版本,优化了尺寸和速度 -->
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
在基础语法的学习中,我们将采用这种简易的安装方式。
快速入门案例
接下来,让我们来看一个 Vue 快速入门的案例,在桌面创建 index.html,书写如下的代码:
// index.html
<body>
<div id="app">
<!-- Hello Vue! -->
{{ message }}
</div>
<script src="https://unpkg.com/vue/dist/vue.min.js"></script>
<script>
new Vue({
el: '#app',
data: {
message: 'Hello Vue!'
}
})
</script>
</body>
效果:
模板插值
上面有提到,如果只使用 Vue 最基础的声明式渲染的功能,则完全可以把 Vue 当做一个模板引擎来使用,也就是采用模板语法把数据渲染进 DOM。
Vue 使用双大括号语法来进行文本插值,下面的 message 相当于一个变量或占位符,最终会表示为真正的文本内容。
...
<div id="app">
{{ message }}
</div>
...
构造器
每个 Vue 应用都是通过构造函数 Vue 来创建一个 Vue 的根实例。
...
new Vue({
// 选项
})
...
实例化 Vue 时,需传入一个选项对象,它可以包含数据、模板、挂载元素、方法、生命周期等选项。
在上面的例子中,我们传入了 el 来挂载元素,data 来进行数据的绑定。
new Vue({
// 挂载元素
el: '#app',
// 数据
data: {
message: 'Hello Vue!'
}
});
参数 el,是 element 的缩写,用于提供一个在页面上已存在的 DOM 元素作为 Vue 实例的挂载目标。
参数值有 2 种类型,包括 string 和 HTMLElement。el:’#app’ 表示挂载目标是 id 为 app 的元素,也可写为 el:document.getElementById(‘app’)
参数 data 表示 Vue 实例的数据对象。上例中,data:{message:‘Hello Vue!’} 表示变量 message 所代表的真实值为 Hello Vue!
数据绑定
看起来上面的例子跟简单渲染一个字符串模板非常类似,但是 Vue 在背后做了大量工作。现在数据和 DOM 已经被绑定在一起,所有的元素都是响应式的。
我们将上面的代码稍作修改,将 Vue 的实例赋值给一个变量,然后动态的改变 data 的值,可以看到 DOM 元素也得到了动态的更新。如下:
// index.html
<body>
<div id="app">
<!-- Hello Vue! -->
{{ message }}
</div>
<script src="https://unpkg.com/vue/dist/vue.min.js"></script>
<script>
// 将 Vue 的实例保存下来 , 方便在控制台改变 data 数据
const vm = new Vue({
el: '#app',
data: {
message: 'Hello Vue!'
}
})
</script>
</body>
在浏览器的控制台中动态修改 vm.message 的值,可以看到 DOM 元素也会相应的进行更新。
当一个 Vue 实例被创建时,该实例会代理 data 对象中能找到的所有的属性。如下:
// index.html
<body>
<div id="app">
<!-- Hello Vue! -->
{{ message }}
</div>
<script src="https://unpkg.com/vue/dist/vue.min.js"></script>
<script>
const data = {
message: 'Hello Vue!'
}
const vm = new Vue({
el: '#app',
data: data
});
console.log(vm.message); // Hello Vue!
console.log(vm.message === data.message); // true
// 设置属性也会影响到原始数据
vm.message = 'xiejie';
console.log(data.message); // xiejie
// 反之亦然
data.message = 'yajing'
console.log(vm.message); // yajing
</script>
</body>
除了数据属性,Vue 实例还暴露了一些有用的实例属性与方法。它们都有前缀 $,以便与用户定义的属性区分开来。
例如 $el,代表被挂载的元素。
示例如下:
// index.html
<body>
<div id="app">
<!-- Hello Vue! -->
{{ message }}
</div>
<script src="https://unpkg.com/vue/dist/vue.min.js"></script>
<script>
const data = {
message: 'Hello Vue!'
}
const vm = new Vue({
el: '#app',
data: data
});
console.log(vm.$el); // <div id="app"> Hello Vue! </div>
console.log(vm.$el === document.getElementById('app')); // true
</script>
</body>
再例如 $watch,这也是 Vue 实例所提供的一个方法,用于监听数据的变化。
示例如下:
// index.html
<body>
<div id="app">
{{ message }}
</div>
<script src="https://unpkg.com/vue/dist/vue.min.js"></script>
<script>
const data = {
message: 'Hello Vue!'
}
const vm = new Vue({
el: '#app',
data: data
});
// 监听 message 数据,当 message 数据发生变化时,调用此函数
vm.$watch('message', function (newValue, oldValue) {
console.log(`更新前的值为${oldValue}`);
console.log(`更新后的值为${newValue}`);
})
</script>
</body>
效果:
有些时候,我们不需要数据实时的渲染到页面上,这个时候,可以使用 Object.freeze 方法,该方法会阻止修改现有的属性,也意味着响应系统无法再追踪变化。如下:
// index.html
<body>
<div id="app">
<!-- Hello Vue! -->
{{ message }}
</div>
<script src="https://unpkg.com/vue/dist/vue.min.js"></script>
<script>
const data = {
message: 'Hello Vue!'
}
// 阻止修改现有的属性 , 响应系统无法再追踪变化
Object.freeze(data);
const vm = new Vue({
el: '#app',
data: data
});
</script>
</body>
效果:
生命周期
每个 Vue 实例在被创建时都要经过一系列的初始化过程。例如,需要设置数据监听、编译模板、将实例挂载到 DOM 并在数据变化时更新 DOM 等。
在这个过程的同时也会运行一些叫做生命周期钩子的函数,这给开发者在不同阶段添加自己的代码创造了机会。
例如:
// index.html
<body>
<div id="app">
{{ a }}
<div>
<button @click="destory">销毁</button>
</div>
</div>
<script src="https://unpkg.com/vue/dist/vue.min.js"></script>
<script>
const app = new Vue({
el: '#app',
data: { a: 1 },
// 创建 Vue 实例的时候触发
created: function () {
console.log('a is: ' + this.a)
},
// Vue 实例被销毁的时候触发
destroyed: function () {
console.log('this is a test');
},
methods: {
destory: function () {
app.$destroy(); // 销毁 Vue 实例
}
}
})
</script>
</body>
效果:
下图是官网中给出的一个 Vue 实例从创建到销毁所经历的完整生命周期图,如下:
下面针对上图中 Vue 实例整个生命周期的各阶段,进行一个详细的说明。如下:
- beforeCreate:在实例开始初始化时同步调用。此时数据观测、事件等都尚未初始化。
- created:在实例创建之后调用。此时已完成数据观测、事件方法,但尚未开始 DOM 编译,即未挂载到 document 中。
- beforeMount:在 mounted 之前运行。
- mounted:在编译结束时调用。此时所有指令已生效,数据变化已能触发 DOM 更新,但不保证 $el 已插入文档。
- beforeUpdate:在实例挂载之后,再次更新实例(例如更新 data)时会调用该方法,此时尚未更新 DOM 结构。
- updated:在实例挂载之后,再次更新实例并更新完 DOM 结构后调用。
- beforeDestroy:在开始销毁实例时调用,此刻实例仍然有效。
- destroyed:在实例被销毁之后调用。此时所有绑定和实例指令都已经解绑,子实例也被销毁。
- activated:需要配合动态组件 keep-live 属性使用。在动态组件初始化渲染的过程中调用该方法。
- deactivated:需要配合动态组件 keep-live 属性使用。在动态组件初始化移出的过程中调用该方法。
通过下面的例子,我们可以更加清楚地了解 Vue 实例整个生命周期各阶段的运行机制。
示例代码如下:
// index.html
<body>
<div id="app">
<!-- this is a test -->
{{ message }}
</div>
<script src="https://unpkg.com/vue/dist/vue.min.js"></script>
<script>
var app = new Vue({
el: '#app',
data: {
message: "this is a test"
},
beforeCreate: function () {
console.group('beforeCreate 创建前状态===============》');
console.log("%c%s", "color:red", "el : " + this.$el); // undefined
console.log("%c%s", "color:red", "data : " + this.$data); // undefined
console.log("%c%s", "color:red", "message: " + this.message); // undefined
},
created: function () {
console.group('created 创建完毕状态===============》');
console.log("%c%s", "color:red", "el : " + this.$el); // undefined
console.log("%c%s", "color:red", "data : " + this.$data); // 已被初始化
console.log("%c%s", "color:red", "message: " + this.message); // 已被初始化
},
beforeMount: function () {
console.group('beforeMount 挂载前状态===============》');
console.log("%c%s", "color:red", "el : " + (this.$el)); // 已被初始化
console.log(this.$el);
console.log("%c%s", "color:red", "data : " + this.$data); // 已被初始化
console.log("%c%s", "color:red", "message: " + this.message); // 已被初始化
},
mounted: function () {
console.group('mounted 挂载结束状态===============》');
console.log("%c%s", "color:red", "el : " + this.$el); // 已被初始化
console.log(this.$el);
console.log("%c%s", "color:red", "data : " + this.$data); // 已被初始化
console.log("%c%s", "color:red", "message: " + this.message); // 已被初始化
},
beforeUpdate: function () {
console.group('beforeUpdate 更新前状态===============》');
console.log("%c%s", "color:red", "el : " + this.$el);
console.log(this.$el);
console.log("%c%s", "color:red", "data : " + this.$data);
console.log("%c%s", "color:red", "message: " + this.message);
},
updated: function () {
console.group('updated 更新完成状态===============》');
console.log("%c%s", "color:red", "el : " + this.$el);
console.log(this.$el);
console.log("%c%s", "color:red", "data : " + this.$data);
console.log("%c%s", "color:red", "message: " + this.message);
},
beforeDestroy: function () {
console.group('beforeDestroy 销毁前状态===============》');
console.log("%c%s", "color:red", "el : " + this.$el);
console.log(this.$el);
console.log("%c%s", "color:red", "data : " + this.$data);
console.log("%c%s", "color:red", "message: " + this.message);
},
destroyed: function () {
console.group('destroyed 销毁完成状态===============》');
console.log("%c%s", "color:red", "el : " + this.$el);
console.log(this.$el);
console.log("%c%s", "color:red", "data : " + this.$data);
console.log("%c%s", "color:red", "message: " + this.message)
}
})
</script>
</body>
效果:
随着我们对 Vue 的不断学习和使用,Vue 实例的生命周期参考价值会越来越高。
Vue 与 jQuery 对比
在本小节的最后,我想将 Vue 和之前很有名的 jQuery 进行一个小小的对比。
在 jQuery 年代,当我们从服务器拿回所需的数据之后,需要手动的进行数据更新。
如下图所示:
而 Vue 最大的特点在于数据与 DOM 元素进行了绑定,可以进行自动的更新,编码时只需要维护前端的数据即可。
如下图所示:
通过上面 2 张图的对比,可以一目了然的看到 Vue 的优点。
以前从后端拿回来数据之后,还要手动的去进行 DOM 的更新。但是现在不需要了,由于 Vue 将前端数据和 DOM 元素进行了绑定,只要维护好前端数据,DOM 元素自然就更新了。
总结
-
Vue 是一套用于构建用户界面的渐进式框架。
-
Vue 中的数据和 DOM 元素进行了绑定,从而实现数据一旦改变,DOM 元素就会重新渲染。
-
每个 Vue 实例从创建到销毁都要经过一系列过程,这个被称之为 Vue 实例的生命周期。
-
在 jQuery 年代,当我们从服务器拿回所需的数据之后,需要手动的进行数据更新,但是使用 Vue 可以实现从服务器拿回数据后,DOM 元素自动重新渲染。