Vue初探
疑问点
- 之前开始学习Vue时,老是搞不清楚为什么有的时候是:
v-bind:class="dynamicClass"
,
而有的时候是:v-bind:class="{active: isActive}"
,其实是v-bind可以绑定变量、对象或数组 - 使用
v-model
可以实现双向绑定; 如用在表单控件元素上实现双向绑定,也就是说我们在表单控件上输入数据,可以实时的反应到Vue实例的data上,在data上的数据改变也可以体现在表单控件元素上。
v-model文档
注意:双向绑定在富表单的页面上很有用,但是双向绑定不利于我们对数据的掌控
Vue实例
语法:var vm = new Vue({});
说明:通过new Vue
来实例化一个Vue对象,在实例化时,可以传入:数据、模板、挂载元素、方法、生命周期钩子等选项
**注意:
- **Vue实例必须要绑定一个元素上,这个Vue实例就是为它绑定的元素服务的,它们之间建立联系,元素的变化可以通过该实例来获取,同时,通过该实例,也可以操作这个元素,实例中数据的变化可以体现在该元素上
- 当创建一个Vue实例时,如果data属性上的数据暂时不需要使用,那么也必须先添加到data上,如果在之后添加,则无效;因为Vue会在创造实例时,找到data属性上的所有数据,并将其注册到Vue的响应式系统中,所以必须在创建Vue的实例时,将data上的所有数据都添加上去。
如:
// 我们的数据对象
var data = { a: 1 }
// 该对象被加入到一个 Vue 实例中
var vm = new Vue({
data: data
})
// 对data中a的更改会体现在vm的data中
vm.a === data.a // true
data.a = 2; // 会导致 vm.a = 2
vm.a =3 // 会导致data.a = 3
vm.b = 4 // 这样是无效的,b并不能被添加到vm实例中
console.log(vm.b); // 输出 undefined
// 如果知道b会在将来使用,那么必须在创建vm实例时添加,如下:
var vm = new Vue({
data: {
a: 1,
b: '' // 将b设置为空即可
}
})
参考: Vue数据与方法
模板语法
插值
原始HTML
通过v-html
可以将html代码插入到页面中
如:
<div id="app">
<div v-html="rawhtml"></div>
<div>{{msg}}</div>
</div>
var vm = new Vue({
el: "#app",
data: {
rawhtml: "<a href='www.baidu.com'>baidu</a>",
msg: "<a href='www.baidu.com'>baidu</a>"
}
});
上面代码实际输出如下:
v-html演示说明:通过v-html可以将rawhtml作为原始html替换掉当前的div,而使用{{}}
,则表示将msg作为文本插入到所在的位置
注意: 动态的渲染html是非常危险的,很可能导致XSS攻击
特性
mustache语法不能用在html的特性上,需要使用v-bind
指令来绑定特性,如:
<div v-bind:class="dynamicClass"></div>
注意:dynamicClass
是一个变量
缩写
-
v-bind
缩写
如:<div v-bind:id="dynamicId"></div>
缩写为:<div :id="dynamicId"><div>
也就是说使用:
来代替v-bind:
-
v-on
缩写
如:<button v-on:click="reverse"></button>
缩写为:<button @click="reverse"></button>
也就是使用@
来对v-on
进行缩写
实例属性
通过 $
可以访问到实例属性
var data = {a: 1};
var app = new Vue({
el: "#app",
data: data
});
app.$data === app.data // true
app.$el === document.getElementById('app');
// 还有一些实例方法
app.$watch('a', function(newValue, oldValue) {
// 该回调函数会在a被改变后调用
});
实例生命周期
var vm = new Vue({
data: {
a: 1
},
created: function () {
// `this` 指向 vm 实例
console.log('a is: ' + this.a)
}
})
created
方法会在实例被创建时被调用
绑定数据到HTML的特性上
可以通过v-bind:
来绑定变量到HTML的特性上
注意:一般来说,HTML的特性(如:id、class、style等,其实就是html的属性)接收的是字符串,而如果我们需要绑定一个变量到HTML的特性上,那么就需要使用v-bind:
来操作
如:
// id
<p v-bind:id="dynamicId"></p>
// class
<p v-bind:class="dynamicClass"></p>
注意:上面代码中的dynamicId
和dynamicClass
都是变量
使用JS的表达式
上面说的是绑定简单的属性到HTML的特性上,同时,还可以使用JS表达式来绑定数据
注意:使用表达式时,只支持单个表达式
// 表达式里面的id是变量
<div v-bind:id="'list-' + id"> </div>
类似于下面的语句不会生效
<!-- 这是语句,不是表达式 -->
{{ var a = 1 }}
<!-- 流控制也不会生效,请使用三元表达式 -->
{{ if (ok) { return message } }}
指令
指令是带有v-
前缀的特殊属性,指令属性的值预期是单个JS表达式(v-for
指令例外)
指令的职责:指令的值改变时,将其产生的连带影响,响应式的作用于DOM中
如:
// 如果seen表达式为真,则插入文本,为假则不插入
<p v-if="seen">现在你看到我了</p>
v-on指令
通过v-on指令可以来指定监听事件
// 监听click事件
<button v-on:click="dosome"></button>
在监听的事件之后,还可以添加修饰词,例如有时候,我们需要阻止事件的默认行为
// 通过添加prevent修饰符, 提交事件不再重载页面
<a v-on:click.prevent="doSomething">
缩写
v-bind缩写
<!-- 完整语法 -->
<a v-bind:href="url"></a>
<!-- 缩写 -->
<a :href="url"></a>
v-on缩写
<!-- 完整语法 -->
<a v-on:click="doSomething"></a>
<!-- 缩写 -->
<a @click="doSomething"></a>
计算属性
计算属性其实就是在Vue实例的computed
属性上定义的一些函数;
如:
computed: {
now: function () {
return Date.now()
}
}
我们知道可以通过在Vue实例的 methods
属性上定义函数,这两者产生的结果是相同的,那么这两者有什么区别呢?
注意:这里定义了一个计算属性now
,并为其添加了函数,其本质就是将该函数用作now属性的getter
函数,当访问now时,就调用该函数
计算属性computed和methods的区别:
其最主要的区别在于:当它们进行计算求值时,如果依赖的数据没有发生改变,它们两者会进行不同的操作,computed
是基于它的依赖进行缓存的,只有在依赖的数据发生改变时,才进行重新求值;而对于methods则不管依赖的数据有没有发生改变,只要调用方法,就会重新求值,进行渲染;
注意:计算属性只有getter,如果需要设置值,那么就要自己实现setter,如下:
computed: {
fullName: {
// getter
get: function () {
return this.firstName + ' ' + this.lastName
},
// setter
set: function (newValue) {
var names = newValue.split(' ')
this.firstName = names[0]
this.lastName = names[names.length - 1]
}
}
}
观察watch
观察属性可以让我们对某些数据进行观测,当数据发生变化时,就执行相应的函数,这在异步获取数据时,很有用;
如下:
ar watchExampleVM = new Vue({
el: '#watch-example',
data: {
question: '',
answer: 'I cannot give you an answer until you ask a question!'
},
watch: {
// 如果 question 发生改变,这个函数就会运行
question: function (newQuestion) {
this.answer = 'Waiting for you to stop typing...'
this.getAnswer()
}
},
}
上面代码中,当question发生变化时,就会执行后面的函数
通过v-bind绑定class与style
绑定class
对象语法
// 表示如果isActive变量为true,则添加active类, 如果为false,则不添加
<p v-bind:class="{active: isActive}"></p>
当然,还可以添加多个:
<div class="static"
v-bind:class="{ active: isActive, 'text-danger': hasError }">
</div>
// Vue实例中的数据
data: {
isActive: true,
hasError: false
}
利用计算属性(很实用的绑定class的方式)
<div :class="classObj">数据</div>
var wm = new Vue({
data: {
isActive: false,
error: null
},
computed: {
classObj: function() {
// 返回的是一个对象
// 该计算属性依赖于isActive和error,因此,当需要更改时,只要更改isActive和error即可
return {
active: this.isActive && !this.error
'text-danger': this. error && this.error.type === 'fatal'
}
}
}
});
数组语法
还可以传递一个数组
<div v-bind:class="[activeClass, errorClass]">
// Vue实例中的data
data: {
activeClass: 'active',
errorClass: 'text-danger'
}
// 渲染后的结果
<div class="active text-danger"></div>
还可以使用三元运算符:
<div v-bind:class="[isActive ? activeClass : '', errorClass]">
//此例始终添加 errorClass ,但是只有在 isActive 是 true 时添加 activeClass
// 上面的语法可以改写为:
<div v-bind:class="[{ active: isActive }, errorClass]">
绑定内联样式
对象语法
<div v-bind:style="{ color: activeColor, fontSize: fontSize + 'px' }"></div>
// Vue实例中的data
data: {
activeColor: 'red',
fontSize: 30
}
通常,直接绑定一个样式对象更好
<div v-bind:style="styleObject"></div>
// Vue实例中的data
data: {
styleObject: {
color: 'red',
fontSize: '13px'
}
}
数组语法
v-bind:style 的数组语法可以将多个样式对象应用到一个元素上:
<div v-bind:style="[baseStyles, overridingStyles]">
条件渲染
v-show
带有v-show
指令的元素一直在DOM树中,v-show
只是简单的切换css的display: none
或display: block
注意: v-show
不支持<template>
语法,同时,也不支持v-else
v-if VS v-show
v-if
: 是真正的条件渲染,因为它会确保在切换的过程中条件块内的事件监听器和子组件适当的被销毁或重建
v-if
也是惰性的:因为如果在初始化渲染时条件不成立, 那么就什么也不会做,直到条件为真时,才会被渲染到页面上
v-show
则不同,不管条件是否为真都会被渲染到页面上,它只是简单的进行display的切换
v-if
有更高的切换开销,而v-show
则有更高的初始渲染开销,因此如果需要频繁的切换,则使用v-show
更合适;如果在运行时不需要经常切换,则使用v-if
更好
注意:当v-if
和v-show
同时使用时,v-show
的优先级更高
数组更新检测
变异方法
调用这些方法时,将会导致视图更新,方法如下:
push()
pop()
shift()
unshift()
splice()
sort()
reverser()
变异方法会改变原始数组
非变异方法
非变异方法不会改变原数组,它们会返回一个新的数组
slice()
filter()
concat()
注意事项
对数组的更改
Vue不能检测以下变动的数组:
- 当利用索引值直接设置一个项时,如:
vm.items[index] = newValue
- 当修改数组的长度时,如:
vm.items.length = newLength
当使用上面两种方式设置数组时,Vue将无法检测到,也就是说,如果在视图上不会进行相应的更新,如下:
<div id="app-11">
<li v-for="(item, index) in objects">
{{index}} - {{item.todo}}
</li>
</div>
// js
var app11 = new Vue({
el: "#app-11",
data: {
objects: [
{todo: 'a'},
{todo: 'b'},
{todo: 'c'}
]
}
});
// 如果如下更改,则不会生效
app11.objects[0] = {todo: 'change'} // Vue将无法检测到该变动,视图不会更新
// 使用以下方式,则会生效
// 方法一:使用Vue.set
Vue.set(app11.objects, 0, {todo: 'change'});
// 方法二:使用splice
app11.objects.splice(0, 1, {todo: 'change'});
// 如果需要改变数组长度,则可以使用如下方式:
app11.objects.splice(5); // 表示将长度修改为5
总结:
- 当需要利用索引设置数组中对应的一个项时,可以使用以下两种方式:
方法一:Vue.set(example.items, indexofItem, newItem)
方法二:example.items.splice(indexofItem, 1, newItem)
- 如果需要修改数组的长度,可以使用如下方法:
example.items.splice(newLength)
参考:列表渲染
对对象的更改
与数组类似,Vue也无法检测到对象属性的添加和删除