前言
接触 Vue 也有一段时间了,很多时候在项目里面会用,但是由于对整个 Vue 的了解比较片面,让我不得不一次又一次地含泪填坑。不过真是这样的经历,也让我对 Vue 有了很多新的认识。
为了深入地学习 Vue 2.0,就决定写一个系列的学习笔记,希望在记录自己走过的路的同时,也能和一起学的伙伴互相交流。所以,也希望看完博客的小伙伴,如果发现我的什么错误或者遗漏,也希望及时地提出来。
关于 Vue 2.0 的学习笔记是一个系列的集合,包括 Vue 基础学习、高级组件学习、插件开发和实际应用,所涵盖的知识点和技能点也是方方面面,本文主要针对 Vue 2.0 的常用方法进行了总结,不包括 Vue 是啥东西?怎么安装?这个 Vue 官网 已经说的很详细了,可以根据它的教程一步一步来。
放个 Vue 2.0 学习笔记其它部分的传送门(我会坚持都写完的 TAT):
好的,我们开始吧!
1. 生命周期
每个 Vue 实例在被创建之前都要经过一系列的初始化过程,在这个过程中,实例也会调用一些生命周期钩子 ,这就给我们提供了执行自定义逻辑的机会。
那么怎么使用这些钩子呢?我们先看一个 Vue 实例的生命周期图:
如上图所示,Vue 的生命周期一共有Create
、Mount
、Update
以及Destroy
四个步骤。而 Vue.js 也提供了八个钩子函数给我们自定义逻辑:
- beforeCreate
- created
- beforeMount
- mounted
- beforeUpdate
- updated
- beforeDestroy
- destroyed
从字面上来解释就分别是创建前后、挂载前后、更新前后以及销毁前后。
注意:Mount 比较简单的理解就是 Vue 上的
el
替代了 DOM 元素。
我们再通过一个例子来说明一下:
<template>
<div id="demo1">{{data}}</div>
</template>
<script>
export default {
data() {
return {
name: 'demo1',
a: '999',
data: 'this is data'
}
},
beforeCreate() {
console.log('beforeCreate')
},
created() {
console.log('created')
},
beforeMount() {
console.log('beforeMount')
},
mounted() {
console.log('mounted')
},
beforeUpdate() {
console.log('beforeUpdate')
},
updated() {
console.log('updated')
},
beforeDestroy() {
console.log('beforeDestroy')
},
destroyed() {
console.log('destroyed')
},
watch: {
a: function (val, oldVal) {
console.log(`new: ${val}, old: ${oldVal}`)
}
}
}
</script>
我们打开控制台就会发现,初次加载时会触发Create
和Mount
的生命周期钩子:
在控制台中修改 data 中的值,以及调用$destroy()
方法,分别会触发Update
和Destroy
的生命周期钩子:
另外值得一提的是,根据官网给出的描述:
“每个 Vue 实例都会代理其 data 对象里的所有属性。”
通俗一点说就是,data 对象是引用类型,其值是该对象的地址,所以你改变 data 中的值之后,Vue 实例中的值也会跟着改变,反过来也是同理。不过有一点在写 SPA 的时候可能不会注意到的是,把一个对象赋值给 Vue 实例以后,再给该对象增加属性,新属性并不会被原本的 Vue 实例所引用。例如:
// html
<div id="demo2"></div>
// js
const demoData = {
name: 'demo2',
a: '999',
data: 'this is data'
}
const demo = new Vue({
el: '#demo2',
data: demoData
})
demoData.b = '998'
这样并不能把新属性添加到实例里面。
把话题撤回来,使用了$destroy()
方法就会触发 Destroy 的生命周期钩子,会拆解监控,也就是解除双向绑定,值得变化不会再引起 DOM 的变化:
如上图所示,修改了 data 之后,DOM 上的值依旧没有发生变化。
2. 计算属性
计算属性被混入到 Vue 实例中,所有 getter 和 setter 的 this 上下文自动地绑定为 Vue 实例。
注意:不应该使用箭头函数来定义计算属性函数 (例如
aDouble: () => this.a * 2
)。理由是箭头函数绑定了父级作用域的上下文,所以 this 将不会按照期望指向 Vue 实例,this.a
将是 undefined。
先看 demo 的以下代码:
<template>
<div id="demo3">
<p>{{fullName}}</p>
<p>{{getFullName()}}</p>
</div>
</template>
<script>
export default {
data() {
return {
firstName: 'Larry',
lastName: 'Xiao'
}
},
methods: {
getFullName() {
console.log('method exec')
return `${this.firstName} ${this.lastName}`
}
},
computed: {
fullName: {
get() {
return `${this.firstName} ${this.lastName}`
},
set(newVal) {
let names = newVal.split(' ')
this.firstName = names[0]
this.lastName = names[names.length-1]
}
}
},
watch: {
a: function (val, oldVal) {
console.log('watch exec')
alert('firstName has changed!')
}
}
}
</script>
可以看到的是,在 computed 中的fullName
和 methods 中的getFullName()
效果是一样的。根据文档上的说法,计算属性是使用计算缓存的,当计算属性的依赖项发生变化时,计算属性才会重新计算,其他时候都是直接返回缓存中的值,而 method 总是会执行函数。
另外,计算属性默认是 get 模式,同时也可以采用 set 模式。
因此,计算属性在大多数情况都更合适,当不需要缓存的时候用 method,需要缓存的时候用计算属性 computed,有时候需要在数据变化时来响应数据变化,就需要用到 watch 方法。
3. Class 绑定
在将v-bind
用于 class 和 style 的时候,表达式的结果类型除了字符串外,还可以是对象是数组:
对象的绑定方式很简单,使用v-bind:class
就行了。
需要注意的有:
-
v-bind:class
可以和普通的 class 属性共存; -
v-bind:class
赋值的对象除了是 js 的字面量意外,也可以是 data 中所指向的对象,同时还能是 computed 计算属性中返回的对象。
关于数组绑定,可以把一个数组传递给v-bind:class,以应用一个class列表,同时也可以在数组中使用对象:v-bind:class="[{active:isActive},selectCss]"
。当然同样的道理,也可以使用计算属性。
4. 内联样式绑定
内联样式的绑定和 class 的绑定几乎没有区别,同样也是可以绑定对象和数组:v-bind:style="{color:'red';fontSize:'30px'}"
,有一点要注意的是,css 的属性名除了用驼峰法,还可以用短横分割法命名:v-bind:style="{color:'blue','font-size':'30px',}"
和v-bind:style="{color:'blue',fontSize:'30px',}"
的效果是一模一样的。当然,把v-bind:style
绑定到一个样式对象上是个更好的做法。
数组的用法和 class 的一样,最后值得一提的是:当v-bind:style
使用需要特定前缀的 css 属性时,如transform
,会自动添加前缀。并且在 chrome 浏览器下,并没有加上-webkit-
前缀。
5. 条件渲染
5.1 v-if
在 Vue 项目里面,一般在处理条件渲染的时候,都会使用v-if
来处理,而更为强大的一点在于,还有v-else
和v-else-if
来处理多种条件下的渲染问题。
由于v-if
只是一种标签里的指令,如果需要按条件渲染多个元素的时候,就需要用到<template></template>
,把多个元素放在template
里面,把v-if
指令放到template
上。
Vue 尝试尽可能高效的渲染元素,通常会复用已有元素而不是从头开始渲染。这么做除了使 Vue 更快之外还可以得到一些好处。就像这样,当允许用户在不同的登录方式之间切换:
<template v-if="loginType === 'username'">
<label>Username</label>
<input placeholder="Enter your username">
</template>
<template v-else>
<label>Email</label>
<input placeholder="Enter your email address">
</template>
在控制台切换loginType
,会显示不同的 label 和 plaaceholder,但是在切换的时候,input 的内容并不会被删除,两个模版因为使用了相同的元素,因此<input>
会被复用,仅仅只是替换了 placeholder。当然,Vue 也提供了一种方式让你自己决定是否要复用元素,所要做的就是加一个 key 属性。
5.2 v-show
另一个根据条件渲染元素的指令叫v-show
,和v-if
的区别在于v-show
做的仅仅只是切换元素的 css 中的display
属性。另外v-show
也不支持 template 语法。
5.3 v-if 和 v-show 的区别:
-
v-if
是真实的条件渲染,因为它会确保条件块在切换当中适当地销毁与重建条件块内的事件监听器和子组件。 -
v-if
也是惰性的:如果在初始渲染时条件为假,则什么也不做,在条件第一次变为真时才开始局部编译(编译会被缓存起来)。
相比之下,v-show
简单得多:元素始终被编译并保留,只是简单地基于 CSS 切换。一般来说,v-if
有更高的切换消耗,而v-show
有更高的初始渲染消耗。因此,如果需要频繁切换使用v-show
较好,如果在运行时条件不大可能改变则使用v-if
较好。
6. 列表渲染
在 Vue 的列表渲染中,主要使用v-for="item in items"
的指令来进行元素渲染。和条件渲染一样,当有多个元素需要被渲染的时候,也可以使用<template v-for=""></template>
来渲染。
而v-for
指令除了可以渲染数组以外,也能渲染对象以及整数的迭代:
- 在渲染数组时,
v-for
还支持可选的第二个参数为当前项的索引,即v-for="(item,index) in intems"
; - 而在渲染对象时,
v-for
支持第二个可选参数作为键名,第三个参数作为索引,v-for="(value,key,index) in items"
; - 进行整数迭代时:
<span v-for="x in 15">{{x}}</span>
。
为了给 Vue 一个提示,以便它能跟踪每个节点的身份,从而重用和重新排序现有元素,我们需要为每项提供一个唯一的 key 属性。理想的 key 值是每项都有唯一 id,它的工作方式类似于一个属性,所以你需要用 v-bind 来绑定动态值:
<div v-for="item in items" :key="item.id">
<!-- :key 是对于 v-bind 的一种简写方式 -->
</div>
除了这些,Vue 还包含一组观察数组的变异方法,它们也会触发视图的更新:
- push()
- pop()
- shift()
- unshift()
- splice()
- sort()
- reverse()
7. 事件处理器
事件处理器可以使用v-on
指令或者缩写@
来完成事件绑定,比如我们要绑定一个 click 事件:
<template>
<button v-on:click="add">add</button>
<span></span>
</template>
<script>
data() {
return {
count: 0
}
}
methods: {
add() {
this.count ++
}
}
</script>
有时候需要在v-on
绑定的事件中处理原生 DOM 的事件,则可以使用$event
将它传入方法:
<template>
<button v-on:click="warn('Form cannot be submitted yet.', $event)">Submit</button>
</template>
<script>
data() {
return {
}
}
methods: {
warn (message, event) {
if (event) {
event.preventDefault()
}
alert(message)
}
}
</script>
之前提到的,我们需要在方法中除了原生 DOM 事件,主要也是为了阻止冒泡方法,为了让我们可以再 method 中专注于业务逻辑,Vue 提供了一些事件修饰符:
- stop:阻止事件冒泡;
- prevent:事件触发不再重载页面;
- capture:添加事件监听器时使用事件捕获模式;
- self:只有该事件是自己本身(而不包括子元素)时才会触发回调;
- once:只触发一次。
还有一点要注意的是,事件修饰符是可以串联使用的,比如v-on:click.stop.prevent="click"
。
在监听键盘事件时,还需要监听常见的键值,Vue 允许v-on
在监听键盘事件时,添加特殊的键盘修饰符,基本的键盘修饰符有:
- .enter
- .tab
- .delete
- .esc
- .space
- .up
- .down
- .left
- .right
还有组合按键的修饰符:
- .ctrl
- .shift
- . alt
- .meta(window 系统下是 window 键,mac 下是 command 键)
8. 表单控件绑定
所谓的表单控件其实就是使用v-mode
l指令放在<input>
、<textarea>
和<select>
这些控件上实现双向绑定。如果是多选,v-model
绑定的对象一定要是个数组,同时可以通过v-bind
来为 “表单控件” 设置 value 值。
并且,还可以在v-model
中使用修饰符来进行一些常用操作:
- .lazy:在默认情况下,
v-model
在 input 事件中同步输入框的值与数据,但你可以添加一个修饰符 lazy ,从而转变为在事件中同步:
<input v-model.lazy="msg">
- .number:如果想自动将用户的输入值转为 Number 类型(如果原值的转换结果为 NaN 则返回原值),可以添加一个修饰符 number 给
v-model
来处理输入值:
<input v-model.number="age" type="number">
- .trim:如果要自动过滤用户输入的首尾空格,可以添加 trim 修饰符到
v-model
上过滤输入:
<input v-model.trim="msg">
总结
本文大概地过了一遍 Vue 2.0 的基础知识,也可能还有很多方面不够详尽,希望大佬可以多提建议。还有一点比较重要的就是,学习 Vue 2.0 的话,我个人还是建议去 Vue 官网 跟着一步一步地敲代码,博客只是一个总结概括的东西,真正理解还得自己实践。
当然,也希望这些总结可以对我自己,以及对刚接触 Vue 2.0 的小伙伴有些帮助吧!