由于有一段时间没用Vue了,之前学习的时候Vue还是1.0版本,现在出了2.0版本,所以重新学习一遍Vue,并做个记录,让自己印象更深刻
一、Vue实例
1、构造器
每个Vue应用,都是通过构造函数Vue
来创建的,如:
var vm = new Vue({
// 创建选项
});
选项中,包含有:
- 数据(
data
) - 方法(
methods
) - 模板(
template
) - 挂载元素(
el
) - 生命周期钩子
可以扩展vue
的构造器,从而用预定义的选项创建可复用的组件构造器
,如:
var MyCOM = Vue.extend({
// 拓展选项
});
new MyCOM();
2、属性和方法
每个Vue的实例,都会自动将data对象
里的属性挂载到Vue的实例上,如:
var data = {
a: 1,
b: 2
}
var vm = new Vue({
data: data
});
// 那么,会有以下的情况
vm.a; // 1
vm.b; // 2
vm.a = 3;
data.a; // 3
data.b = 4;
vm.b; // 4
注意: 只有在创建时候传入的属性才是可响应
的,如果在实例创建完毕后,再添加新的属性到实例上,那么对它的变更不会触发视图的更新
为了将实例自身的属性和方法与挂载的属性方法区分开来,Vue中采用$
为前缀,来区分,如:
var data = { a: 1 }
var vm = new Vue({
el: '#app',
data: data
});
vm.$data === data; // true
vm.$el === document.getElementById('app'); // true
3、生命周期
每个Vue实例在创建完成之前,都需要经历一系列的初始化过程(配置数据观测、编译模板、挂载实例到DOM、数据变化时更新DOM),这个过程中,Vue提供了一系列的生命周期钩子
,允许我们更灵活地在生命周期中执行自定义的逻辑。如created
钩子,便是在实例被创建完成后调用:
var vm = new Vue({
data: {
a: 1
},
created: function() {
console.log('created');
}
});
// 运行后,控制台输出“created”
生命周期的完整过程,图示如:
二、模板语法
Vue使用基于HTML的模板语法,于是我们可以声明式地将DOM绑定至底层Vue实例的数据。底层实现中,Vue会将模板编译为Virtual DOM渲染函数,并自动计算最小重新渲染代价以应用。
1、插值
数据绑定常用的方式是Mustache
语法,即双大括号包围的串。如:{{message}}
。Mustache
标签会被自动替换为对应的vue实例
上的属性值,实例中的属性值一旦发生变更,Mustache
插值处的属性值也会随之更新。
如果我们希望属性值不随之更新,那么可以使用v-once
指令:
<span v-once>{{message}}</span>
2、插入HTML
默认情况下,Mustache
语法是插入纯文本的。如果希望插入HTML,那么需要使用v-html
指令,v-html
指令接受一个参数,表示要插入的html是由实例的哪个属性值指定的。如:
<div v-html="rawHTML"></div>
3、属性
对于HTML标签的属性,我们不能直接使用Mustache
语法,应该使用v-bind
指令,即以下做法是错误的:
<div id="{{idName}}"></div>
应该使用:
<div v-bind:id="idName"></div>
4、表达式
在Mustache
和v-bind
中,都可以使用合法的JavaScript表达式(注意是表达式,不是语句,如果是语句,则不会生效),如:
{{ number + 1 }}
{{ ok ? 'Yes' : 'No' }}
<div v-bind:id="'list_' + idName"></div>
像下面的这些,是语句,而不是表达式,所以不会生效:
{{ var a = 1 }}
{{ if(ok) { return message } }}
此外,模板表达式都被放在沙盒中,因此它只能访问在白名单中的全局变量(如Math
、Date
),而不能访问用户自定义的全局变量
5、指令
指令这一概念,在前文中已经出现多次。Vue中的指令,其职责是当指令中的表达式(应该为单一表达式)的值发生变化时,某些行为能够得到响应。如:
v-if="seen"
(表示根据seen属性的值显示或者隐藏)v-bind:href="url"
(表示将标签中href属性的值,和实例中的url属性绑定)v-on:click="handler"
(表示绑定事件监听函数)
指令都是以v-
开头的:
1)它可以接受参数(通过:
,如v-on:click
)
2)指令还可以接受一些修饰符,用于表示一个指令的特殊绑定方式,如v-on:click.prevent
,表示对于触发的事件,执行event.preventDefault()
6、过滤器
所谓的过滤器,就是对值进行处理的函数。过滤器可以运用在Mustache插值处
和v-bind
中,使用|
来指示。如:
<!-- Mustache -->
{{ message | ucfirst }}
<!-- 而在属性中可以这么使用 -->
<span v-bind:title="message | ucfirst"></span>
过滤器函数中,表达式总是作为函数的第一个参数的。如:
<div id="app">
{{ message | ucfirst }}
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
message: 'hello, world!'
},
filters: {
ucfirst: function(value) {
return value[0].toUpperCase() + value.substring(1)
}
}
});
</script>
过滤器是可以串联的,如:{{ message | handlerA | handlerB }}
,此外,过滤器也可以接收参数(接收的参数作为过滤器的第2~n个参数),如{{ message | handler('string', param) }}
7、缩写
1)v-bind:xxx
可以缩写为:xxx
2)v-on:xxx
可以缩写为@xxx
三、计算属性与watch
1、计算属性
Vue提供了计算属性这一功能,它能够在其依赖关系上的值发生改变的时候,自动响应并更新。同时,依赖值的计算是带有计算缓存
的,所以,计算属性具有更高的性能。
<div id="app">{{ reversedMessage }}</div>
<script>
var vm = new Vue({
el: '#app',
data: {
message: 'Hello'
},
computed: {
reversedMessage: function() {
return this.message.split('').reverse().join('');
}
}
});
</script>
这种情况下,当message
的值发生改变的时候,reversedMessage
的值也会相应地发生改变。
那么,计算属性,和methods
有什么区别,例如,我们同样可以使用以下的代码来达到同样的效果:
<div id="app">{{ reversedMessage }}</div>
<script>
var vm = new Vue({
el: '#app',
data: {
message: 'Hello'
},
methods: {
reversedMessage: function() {
return this.message.split('').reverse().join('');
}
}
});
</script>
区别在于,计算属性只有在其依赖发生改变的时候,才会重新计算,而method则每次都会重新计算。所以,当我们希望计算值进行缓存的时候,可以使用计算属性,而若不希望缓存值,则method
是一个更好的选择。
2、watch
watch是Vue提供的一种机制,它会观察和响应Vue实例上的数据变动。如:
var vm = new Vue({
el: '#app',
data: {
firstName: '',
lastName : '',
fullName : ''
},
watch: {
firstName: function() {
this.fullName = this.firstName + ' ' + this.lastName;
},
lastName: function() {
this.fullName = this.firstName + ' ' + this.lastName;
}
}
});
这种情况下,当firstName
和lastName
的值发生改变的时候,fullName
的值也就会跟着改变。但是这种情况下,使用watch
并不是最佳的选择,因为我们可以发现,firstName
和lastName
的watcher在做着类似的工作。而这种情况下,使用计算属性可能是更加的选择,如:
var vm = new Vue({
el: '#app',
data: {
firstName: '',
lastName : '',
fullName : ''
},
computed: {
fullName: function() {
return this.firstName + ' ' + this.lastName;
}
}
});
但是,也不是什么情况下,计算属性都是最佳的方案。比如我们希望通过一个异步任务来获得一个值,而获得值之前,显示一个中间值,这种情况下,计算属性是没有办法做到的,我们就只能使用watch
属性,如:
var vm = new Vue({
el: '#app',
data: {
question: '',
answer: 'No answer'
},
watch: {
question: function(newValue) {
this.answer = 'Getting Answer...';
setTimeout(() => {
this.answer = 'You got a new Value:' + newValue;
}, 1000);
}
}
})
3、setter
计算属性默认情况下,是个getter,但是我们也可以指定一个setter,示例如:
var vm = new Vue({
el: '#app',
data: {
firstName: '',
lastName : ''
},
computed: {
fullName: {
set: function(newValue) {
var names = newValue.split(' ');
this.firstName = names[0];
this.lastName = names[names.length - 1];
},
get: function() {
return this.firstName + ' ' + this.lastName;
}
}
}
});
四、Class与Style绑定
1、动态绑定一个class
<div v-bind:class="{active: isActive}"></div>
<!-- isActive为true时,编译为: -->
<div class="active"></div>
如此就会根据isActive
的值是否为true显示或者隐藏active
这个class,此外,还可以是以下的形式:
<div v-bind:class="{active: isActive, 'green': true"}></div>
<!-- isActive为true时,编译为: -->
<div class="active green"></div>
类自身的class
和v-bind:class
是共存的,如:
<div class="demo" v-bind:class="{active: isActive, 'green': true"}></div>
<!-- isActive为true时,编译为: -->
<div class="demo active green"></div>
也可以将class绑定为data
里的一个对象,如:
<div v-bind:class="classObject"></div>
data: {
classObject: {
active: true,
'is-red': true
}
}
2、数组语法
可以把一个数组传给v-bind:class
来确定一个class列表,如:
<div v-bind:class="[activeClass, errorClass]"></div>
data: {
activeClass: 'active',
errorClass: 'error'
}
3、内联样式
<div v-bind:style="{fontSize: fs, color: color}"></div>
data: {
fs: '20px',
color: '#F00'
}
编译为:
<div style="font-size: 20px; color: #F00"></div>
当然,也可以像v-bind:class
那样子,直接绑定到一个对象上,如v-bind:style="styleObject"
注意:当v-bind:style
需要使用特定前缀的CSS属性时,Vue会自动检测并添加前缀。
内联样式中,还可以使用数组来绑定多个对象,如:
<div v-bind:style="[styleObject1, styleObject2]"></div>
在Vue2.3.0起,加入了多重值功能,如:
<div v-bind:style="{ display: ['-webkit-box', '-ms-flexbox', 'flex'] }"></div>
通常情况下,会渲染被浏览器支持的数组中的最后一个值
五、条件渲染
1、v-if
、v-else-if
、v-else
Vue中可以使用条件渲染,如:
<div v-if="show"></div>
或者
<div v-if="show"></div>
<div v-else></div>
或者
<div v-if="showA"></div>
<div v-else-if="showB"></div>
<div v-else></div>
当我们要对一组元素进行条件渲染的时候,可以使用<template></template>
包围,如:
<template v-if="show">
<div>A</div>
<div>B</div>
</template>
注意: Vue会尽可能高效地进行渲染,会复用已有的元素而非从头开始渲染。所以,对于以下的例子,切换的时候将不会清除用户输入(因为复用了input组件)
<div v-if="loginType === 'username'">
Username: <input type="text" placeholder="Username" />
</div>
<div v-else>
Email: <input type="text" placeholder="Email" />
</div>
但是,当我们希望切换loginType的时候不复用组件的时候,怎么办?可以通过添加唯一值的key
来代表两个元素是完全独立的,不可复用的:
<div v-if="loginType === 'username'">
Username: <input type="text" placeholder="Username" key="username-input" />
</div>
<div v-else>
Email: <input type="text" placeholder="Email" key="email-input" />
</div>
2、v-show
v-show
也可以用来实现条件渲染,但是它不支持v-else
,它仅仅是做display
的切换。所以,v-if
是真正的条件渲染,但是v-show
不是。相比之下:
1)v-if有更高的切换开销,适合于不经常改变的条件(此外,v-if是惰性的,如果初始渲染条件为false
,则什么也不做)
2)v-show有更高的初始渲染开销,但是切换开销较小,适合频繁地切换时使用
六、列表渲染
可以使用v-for
进行列表渲染,如:
<div v-for="item in items"></div>
或者
<div v-for="(item, index) in items"></div>
或者,也支持遍历一个对象,如:
<div v-for="(value, key, index) in someObject">
<!-- // ... -->
</div>
或者使用整数迭代:
<div v-for="n in 5">{{ n }}</div>
<!-- 编译为 -->
<div>1</div>
<div>2</div>
<div>3</div>
<div>4</div>
<div>5</div>
其中,in
也可以使用of
替换。也可以像条件渲染那样子,使用<template>
来包围多个元素。
v-for
和v-if
同时使用
当v-for
和v-if
同时使用的时候,即:
<div v-for="item in items" v-if="item.show"></div>
这种情况下,v-for
的优先级是大于v-if
的
使用key
使用key,可以给Vue一个提示,以便于Vue跟踪每个节点的身份,从而重用和重新排序现有元素。如:
<div v-for="item in items" :key="item.id"></div>
数组更新检测
1、变异方法
当使用数组的push()
、pop()
、unshift()
、shift()
、splice()
、sort()
、reverse()
方法时,Vue因为做过了处理,所以会触发视图层的更新。因为这些数组方法是会对原数组产生影响的,所以称为变异方法
2、重塑方法
有些方法,如filter()
、concat()
、slice()
,不会改变原数组,而是返回一个新的数组,所以当使用非变异方法时候,对于以下的操作:
some.items = some.items.filter(function(item) {
return item.message.match(/Foo/);
});
这种情况下,用新的数组替换掉了旧的数组。但是Vue 不会丢弃现有DOM来重新渲染整个列表,Vue会尽最大可能地进行DOM元素复用
3、无法检测的情况
由于JavaScript的限制,Vue对以下行为是检测不到的:
- 使用索引值直接设置一个项时,如:
vm.items[indexOfItem] = new Value
解决方法: 使用Vue.set(example.items, indexOfItem, newValue)
,或者example.items.splice(indexOfItem, 1, newValue)
- 修改了数组的长度时,如:
vm.items.length = newLength
解决方法: 使用splice
,如examples.items.splice(newLength)
七、事件处理器
1、监听事件
例如:<div v-on:click="params"></div>
params可以是:
- 事件方法名称(定义在
methods
里的) - 合法的表达式,如
count += 1
- 内联JavaScript语句,如
say('Hello')
。注意,如果需要在内联语句中访问原生DOM事件,可以传入$event
变量,如:
<button v-on:click="fn($event)">Submit</button>
methods: {
fn: function(event) {
// ...
}
}
2、事件修饰符
为了让methods里的方法有纯粹的数据处理逻辑,可以使用事件修饰符。如:
.stop
阻止冒泡.prevent
阻止默认事件.captrue
使用捕获.self
只在元素本身发生事件时才触发回调.once
只触发一次事件v-on:keyup.keyCode
当按下的键对应为keyCode对应的键时触发回调v-on:keyup.key
直接提供按键别名(如keyup.enter,表示按enter键)
默认情况下,支持如下的按键别名:
.enter
、.tab
、.delete
、.esc
、.space
、.up
、.down
、.left
、.right
、.ctrl
、.alt
、.shift
、.meta
如果需要自定义按键别名,使用Vue.config.keyCodes
定义,如:
Vue.config.keyCodes.f1 = 112;
八、表单控件绑定
v-model
可以实现双向数据绑定,它会根据控件的类型,自动选取正确的方法来更新元素。v-model
本质上是监听用户的输入、更新数据
1、文本
<input type="text" v-model="message">
2、多行文本
<textarea v-model="textContent"></textarea>
注意,对于多行文本而言,使用插值是无效的,只能使用v-model
3、复选框
<input type="checkbox" v-model="checked" />
如果是多个多选框的话,那么将绑定到一个数组中,如
<div id="app">
<label><input type="checkbox" value="A" v-model="checkedArr"> A</label>
<label><input type="checkbox" value="B" v-model="checkedArr"> B</label>
<label><input type="checkbox" value="C" v-model="checkedArr"> C</label>
{{ checkedArr }}
</div>
4、单选按钮
<input type="radio" value="Boy" v-model="gender" />
5、单选列表
<select v-model="selected">
<option>A</option>
<option>B</option>
<option>C</option>
</select>
6、多选列表(绑定到一个数组)
<select multiple v-model="selectedArr">
<option>A</option>
<option>B</option>
<option>C</option>
</select>
注意,如果是动态选项的话,可以使用v-for
渲染,如:
<select v-model="selected">
<option v-for="opt in opts" v-bind:value="opt.value">{{ opt.text }}</option>
</select>
7、绑定value
通常情况下,v-model
绑定的是静态字符串(对于勾选框,是逻辑值),我们也可以将value绑定到Vue实例的一个动态属性上,此时就可以使用v-bind
实现,如:
<input type="checkbox" v-model="toggle" v-bind:true-value="a" v-bind:false-value="b" />
此时,会有如下情况:
vm.toggle === vm.a // 选中时
vm.toggle === vm.b // 未选中时
对于v-bind:
后接的属性值,不同的表单控件是不同的,如:
- input的checkbox,使用
true-value
和false-value
- input的radio,使用
pick
- select的情况下,使用
selected
- 其他的文本类,使用
value
修饰符:
使用如:v-model.number="age"
.lazy
限定只在change事件中同步.number
限制只能输入Number类型的数值(如果转化后为NaN,则返回原值).trim
去除首尾空格