使用Vue开发也有一段时间了,但大都专注业务部分,知识学的比较零散,总感觉基础没打好。工作之余抽点时间认真读一下Vue官方文档,查缺补漏,温故知新。
一、 响应式数据需要注意的点:
当一个 Vue 实例被创建时,它将
data
对象中的所有的属性加入到 Vue 的响应式系统中。当这些属性的值发生改变时,视图将会产生“响应”,即匹配更新为新的值。
也就是当我们更改data里的数据,在模板中的引用也会同步更新。但是,有几个例外:
1. Object.freeze()。当数据被freeze后,就无法再更改它的值。
实际开发中没用过这条属性,感觉有点像给变量添加只读权限。
var obj = {
foo: 'bar'
}
Object.freeze(obj)
var vm = new Vue({
el: '#app',
data: obj
})
console.log(vm.foo) //bar
vm.foo = "hello"
console.log(vm.foo) //Uncaught TypeError: Cannot assign to read only property 'foo' of object '#<Object>'
2. 只有当实例被创建时 data
中存在的属性才是响应式的。如果data里没有某数据,而是通过之后方法里this.XX添加上去的,则不会响应式更新(当然在模板里使用不存在的变量就会报错了)。
var obj = {
a: 'hello'
}
var vm = new Vue({
el: '#app',
data: obj,
})
vm.a = "hello world"
console.log(obj.a) // hello world
vm.b = "hello b"
console.log(obj.b) //undefined
另外两种比较常见的操作是往对象类型里添加数据,比如添加数组中的对象,或是为对象添加新属性:
2.1当数据是数组,想往里添加新数据时
正常来说响应式无法监听到数组的改变,但是Vue底层封装过诸如 push() unshift之类的方法,可以放心大胆操作。但是有些操作,比如通过中括号添值,length删值 会无法被响应式更新(一般也不会用那么原始的方法操作数组):
<ul>
<li v-for="item in menu" :key="item.value">{{item.label}}</li>
</ul>
menu: [
{ value: '1', label: "两碗米饭" },
{ value: '2', label: "大螃蟹" },
{ value: '3', label: "西瓜" },
{ value: '4', label: "小龙虾" }
]
this.menu[4] = { value: '5', label: '冰啤' } //增加一个子项
this.menu.length = 2 //删除西瓜以后的项
解决方法是,使用一些Vue自己修改过的变异函数替代。
this.menu.splice(4, 1, { value: '5', label: '冰啤' })
this.$set(this.menu, 4, { value: '5', label: '冰啤' })
this.menu.splice(2)
ps:splice()方法可以对数组进行增删改一条龙,非常强大。
2.2 当数据是对象时,想往对象里添加属性。
同上,使用原始方法为对象添加属性,响应式是不认账的。
但是往data里已有的属性添加新值,有两种方法:
this.cooker.northFool = '啥也不会';
Object.assign(this.cooker, {
'小黄':'排骨汤'
})
这两种方法都无法响应更新,正确的操作应该是这样的:
this.cooker = Object.assign({}, this.cooker, {
'小黄':'十三香小龙虾'
})
this.$set(this.cooker,'小红','油爆大虾')
业务中碰到过一种场景,通过后台获取表单数据回显到前端页面上,但是有某个特殊值需要经过前端处理。
data:{
return{
form:{}
}}
this.$http({
url:'XX',
method:'get'
}).then(res=>this.form = res.data)
this.form.exdata = '1' //该操作是无法响应式更新的
因为Data里其实只初始化了form一个变量,所以能监听到form的变化,而无法监听到form.exdata的变化。
3. v-once指令,执行一次性地插值,当数据改变时,data里值改变,但插值处的内容不会更新。
<div v-once>{{foo}}</div>
<button @click="changeData">change it</button>
var vm = new Vue({
el: '#app',
data: {
foo:'bar'
},
methods: {
changeData() {
this.foo = "baz"
console.log(this.foo) //baz,但是模板里依旧为bar
}
}
})
二、动态绑定参数
从 2.6.0 开始,可以用方括号括起来的 JavaScript 表达式作为一个指令的参数,求得的值将会作为最终的参数来使用。
同样地,你可以使用动态参数为一个动态的事件名绑定处理函数:
<a :[attributename]="url"> go to baidu</a>
<a v-on:[eventname]="doSomething"> click to console </a>
data: {
attributename: 'href',
url: "www.baidu.com",
eventname:'click'
},
methods:{
doSomething(){
console.log("do something")
}
}
需要注意的是,绑定的参数值需要严格遵守HTML属性的命名规则,不能有空格和引号,含有大小写的属性名会被强制转换成小写(对的我就踩坑了,因为官方文档里写的就是‘attributeName’)。
<a :[attributeName]="url"> 123123123 </a>
data: {
url: "www.baidu.com",
attributeName: 'href'
}
// attributename is not defined
<a v-bind:["foo" + bar]="url"> ... </a>
编译成 'foo'="" +="" bar]="url"> ...
三、计算属性VS方法
计算属性和方法在结果上是一样的,不同的是计算属性是基于它们的响应式依赖进行缓存的。依赖的数据更新,计算属性则更新,多次访问某个计算属性不会更新,而是会立即返回之前的计算结果。每当触发重新渲染时,调用方法将总会再次执行函数。
get方法:依赖改变时,更新计算值
set方法:计算值改变时,更新其他值
四、用key管理可复用元素
Vue 会尽可能高效地渲染元素,通常会复用已有元素而不是从头开始渲染。如果要让这两个元素成为独立不复用的元素,就需要添加一个key值。
<template v-if="loginType === 'username'">
<label>Username</label>
<input placeholder="Enter your username" key="username-input">
</template>
<template v-else>
<label>Email</label>
<input placeholder="Enter your email address" key="email-input">
</template>
不添加Key,则切换v-if显示的input元素,本质上只修改了它的placeholder,如果用户在里面输入了值后再切换,值会一直显示在里面。如果是el-table,在初始化的时候会给一个resetFiled函数。