Vue 概述
Vue.js(读音 /vjuː/,类似于 view) 是一套构建用户界面的渐进式框架。Vue 采用自底向上增量开发的设计,核心库只关注视图层,它不仅易于上手,还便于与第三方库或既有项目整合。另一方面,当与单文件组件和 Vue 生态系统支持的库结合使用时,Vue 也完全能够为复杂的单页应用程序提供驱动
由于Vue使用getter/setter等ES5特性,所以兼容到IE9
下面来解释下,何为渐进式框架,如上图所示
如果只使用Vue最基础的声明式渲染的功能,则完全可以把Vue当做一个模板引擎来使用
如果想以组件化开发方式进行开发,则可以进一步使用Vue里面的组件系统
如果要制作SPA(单页应用),则使用Vue里面的客户端路由功能
如果组件越来越多,需要共享一些数据,则可以使用Vue里的状态管理
如果想在团队里执行统一的开发流程或规范,则使用构建工具
所以,可以根据项目的复杂度来自主选择使用Vue里面的功能
Vue.js有三种获取方式
1、官网:直接下载
开发版本:包含完整的警告和调试模式
生产版本:删除了警告,28.96kb min+gzip
2、CDN
使用https://unpkg.com/vue这个在线CDN
<script src="https://unpkg.com/vue"></script>
3、NPM
# 最新稳定版
$ npm install vue
# 获取Vue后,直接使用script标签引入即可使用
<script src="https://unpkg.com/vue"></script>
模板插值
前面介绍过,对于Vue最简单的应用就是将其当作一个模板引擎,也就是采用模板语法把数据渲染进 DOM。Vue使用双大括号语法来进行文本插值,下面的message相当于一个变量或占位符,最终会表示为真正的文本内容
<div id="app">
{{ message }}
</div>
构造器
每个Vue.js应用都是通过构造函数 Vue
创建一个 Vue 的根实例启动的,经常使用 vm
(ViewModel 的简称) 这个变量名表示Vue实例
var vm = new Vue({
// 选项
})
在实例化Vue时,需要传入一个选项对象,它可以包含数据、模板、挂载元素、方法、生命周期钩子等选项
var vm = new Vue({
el: '#app',
data: {
message: 'Hello Vue!'
}
})
上面为Vue()构造函数传入了一个对象,对象中包括el和data这两个参数
el: 参数el,是element的缩写,用于提供一个在页面上已存在的 DOM 元素作为 Vue 实例的挂载目标
参数值有两种类型,包括string | HTMLElement
上例中, el : "#app"表示挂载目标为id为"app"的元素,也可以写为 el : document.getElementById('app')
data:
参数data表示Vue实例的数据对象
上例中,data: { message: 'Hello Vue!' } 表示变量message所代表的真实值为"Hello Vue!"
简单实例
下面将Vue的模板插值和构造器结合起来,制作一个简单实例 demo1
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<div id="app">
{{ message }}
</div>
<script src="https://unpkg.com/vue"></script>
<script>
var vm = new Vue({
el: '#app',
data: {
message: 'Hello Vue!'
}
})
</script>
</body>
</html>
数据绑定
看起来上面的例子跟单单渲染一个字符串模板非常类似,但是Vue在背后做了大量工作。现在数据和 DOM 已经被绑定在一起,所有的元素都是响应式的,在控制台中修改app.message的值,可看到DOM元素相应的更新;
Vue自定义指令
默认设置的核心指令(
v-model
、v-on:
、v-bind
、@click
、v-if
v-show
、v-for
);-
自定义指令
以一个input元素自动获得焦点为例,当页面加载时,使用autofocus可以让元素将获得焦点 。但是autofocus在移动版Safari上不工作。现在注册一个使元素自动获取焦点的指令
指令注册类似于组件注册,包括全局指令和局部指令两种全局指令
使用Vue.diretive()来全局注册指令// 注册一个全局自定义指令 v-focus Vue.directive('focus', { // 当绑定元素插入到 DOM 中。 inserted: function (el) { // 聚焦元素 el.focus() } })
局部指令
也可以注册局部指令,组件或Vue构造函数中接受一个 directives 的选项var vm = new Vue({ el: '#app', directives:{ focus:{ inserted: function (el) { el.focus() } } } })
然后可以在模板中任何元素上使用新的
v-focus
属性<div id="app"> <input v-focus> </div>
<script> // 注册一个全局自定义指令 v-focus Vue.directive('focus', { // 当绑定元素插入到 DOM 中。 inserted: function (el) { // 聚焦元素 el.focus() } }) var vm = new Vue({ el: '#app', }) </script>
钩子函数
指令定义函数提供了几个钩子函数(可选)
bind
只调用一次,指令第一次绑定到元素时调用,用这个钩子函数可以定义一个在绑定时执行一次的初始化动作
inserted
被绑定元素插入父节点时调用(父节点存在即可调用,不必存在于 document 中)
update
所在组件的 VNode 更新时调用,但是可能发生在其孩子的 VNode 更新之前。指令的值可能发生了改变也可能没有。但是可以通过比较更新前后的值来忽略不必要的模板更新
componentUpdated
所在组件的 VNode 及其孩子的 VNode 全部更新时调用
unbind
只调用一次, 指令与元素解绑时调用
钩子函数参数
钩子函数被赋予了以下参数
el
指令所绑定的元素,可以用来直接操作 DOM
binding
一个对象,包含以下属性:
name: 指令名,不包括 v- 前缀。
value: 指令的绑定值, 例如: v-my-directive="1 + 1", value 的值是 2。
oldValue: 指令绑定的前一个值,仅在 update 和 componentUpdated 钩子中可用。无论值是否改变都可用。
expression: 绑定值的字符串形式。 例如 v-my-directive="1 + 1" , expression 的值是 "1 + 1"。
arg: 传给指令的参数。例如 v-my-directive:foo, arg 的值是 "foo"。
modifiers: 一个包含修饰符的对象。 例如: v-my-directive.foo.bar, 修饰符对象 modifiers 的值是 { foo: true, bar: true }。
vnode
Vue 编译生成的虚拟节点
oldVnode
上一个虚拟节点,仅在 update 和 componentUpdated 钩子中可用
注意:除了 el 之外,其它参数都是只读的,尽量不要修改他们。如果需要在钩子之间共享数据,建议通过元素的 dataset 来进行
下面是一个使用了这些参数的自定义钩子样例
<div id="app" v-demo:foo.a.b="message"></div>
<script>
Vue.directive('demo', {
bind: function (el, binding, vnode) {
var s = JSON.stringify
el.innerHTML =
'name: ' + s(binding.name) + '<br>' +
'value: ' + s(binding.value) + '<br>' +
'expression: ' + s(binding.expression) + '<br>' +
'argument: ' + s(binding.arg) + '<br>' +
'modifiers: ' + s(binding.modifiers) + '<br>' +
'vnode keys: ' + Object.keys(vnode).join(', ')
}
})
new Vue({
el: '#app',
data: {
message: 'hello!'
}
})
</script>
函数简写
大多数情况下,可能想在bind和update钩子上做重复动作,并且不想关心其它的钩子函数。可以这样写:
Vue.directive('color-swatch', function (el, binding) {
el.style.backgroundColor = binding.value
})
对象字面量
如果指令需要多个值,可以传入一个JS对象字面量。指令函数能够接受所有合法类型的JS表达式
<div v-demo="{ color: 'white', text: 'hello!' }"></div>
Vue.directive('demo', function (el, binding) {
console.log(binding.value.color) // => "white"
console.log(binding.value.text) // => "hello!"
})
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实例内部的运行机制
<div id="app">{{message}}</div>
<script>
var vm = new Vue({
el: '#app',
data:{
message:'match'
},
beforeCreate(){
console.log('beforeCreate');
},
created(){
console.log('created');
},
beforeMount(){
console.log('beforeMount');
},
mounted(){
console.log('mounted');
},
beforeUpdate(){
console.log('beforeUpdate');
},
updated(){
console.log('updated');
//组件更新后调用$destroyed函数,进行销毁
this.$destroy();
},
beforeDestroy(){
console.log('beforeDestroy');
},
destroyed(){
console.log('destroyed');
},
})
</script>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>动态组件</title>
<script src="https://unpkg.com/vue"></script>
</head>
<body>
<div id="app">
<button @click="change">切换页面</button>
<keep-alive>
<component :is="currentView" @pass-data="getData"></component>
</keep-alive>
<p>{{msg}}</p>
</div>
</body>
<script>
var vm = new Vue({
el: '#app',
data: {
index:0,
msg:'',
arr:[
{
template:`<div>我是预售电影</div>`,
activated(){
this.$emit('pass-data','主页被添加');
},
deactivated(){
this.$emit('pass-data','主页被移除');
},
},
{template:`<div>我是正在热播</div>`},
{template:`<div>我是预售电影</div>`}
]
},
computed:{
currentView(){
return this.arr[this.index];
}
},
methods:{
change(){
var len = this.arr.length;
this.index = (++this.index)% len;
},
getData(value){
this.msg = value;
setTimeout(()=>{
this.msg = '';
},500)
}
}
})
</script>
</html>