之前,我发了一些关于HeyUI组件库的一些文章,有些人建议我把开发中遇到的问题共享出来,这一篇算是一个尝试,看大家反馈,会有更多的开发知识共享。
首先,这一篇,说的是vue开发中的“深坑”,并不是有一些文章写的“vue安装失败,模块找不到,或者vue-router如何定义”等等基础错误。
然后,这一篇需要阅读者对vue有着基本的了解,并且使用过,如果你对vue还不懂,建议先收藏,以后再看。
HeyUI
如果对我们组件库不熟悉的小伙伴可以参见我们官网:
heyui.top
或者围观我们的github:
github.com/heyui/heyui
这一篇主要说的是vue使用中遇到的常见并且很难解决的错误,有可能系统没有报错,但是我们就是找不到原因。
问题一、数据修改了,但是界面仍然没有更新
<template>
<div id="app">
<p>a:{{value.a}}</p>
<p><button @click="changeValueA">change a value</button></p>
<p><button @click="changeValueToughA">change a value use $set</button></p>
<p>b:{{value.b}}</p>
<p><button @click="changeValueB">change b value</button></p>
<p><button @click="changeValue">change value</button></p>
</div>
</template>
<script>
new Vue({
el: '#app',
data: {
value: {
b: 1
}
},
methods: {
changeValueA() {
this.value.a = new Date().getTime();
},
changeValueToughA() {
this.$set(this.value, "a", new Date().getTime())
},
changeValueB() {
this.value.b = new Date().getTime();
},
changeValue() {
this.value = {
a: 1,
b: 2
};
}
}
})
</script>
如上图所示,执行结果是:
- 直接点击
change a value
是无效的。 - <span style="color: red">先点击
change a value
无效后,再点击change a value use $set
也会无效。</span> - 点击
change a value use $set
有效,并且点击过后,点击change a value
又有效了 - 点击
change value
后,点击change a value
又有效了 - 点击
change b value
一直有效
大家应该注意以下事项
- 由于在
data
下直接定义的对象,添加属性是不会监听的,比如说value.a
在data中其实未定义,你只有通过$set
的方式通知vue才能够完成属性赋值并更新视图。 - 如果对定义的对象直接进行属性添加,会导致
$set
也会失效。 - 如果本身data下面的对象的属性已经定义了,对于对象属性的变更是能够被监听的,比如说
value.b
,你可以直接通过修改b的值来更新视图。 - 最后一个
changeValue
方法,是对vue data下的直接属性进行修改,是能够被整个监听到,并且更新属于value
下所有子属性的视图。
在线demo: https://codepen.io/vvpvvp/pen/XYvxMg?editors=1010
这个主要问题是,我们开发很少用到$set,所以也很少遇到问题,但是新手成员经常干这种事,还一脸懵逼的问题,是不是vue有问题了?
继续,关于如何优化自己的代码,防止出现这种问题,往下看开发注意事项👇👇👇
开发注意事项:
1、data在定义的时候,一定要把相关的数据定义全了。 因为data代表着整个模块的处理逻辑,你在下面使用$set,代码可读性非常不好,更不要说,多了很多莫名其妙的bug。
2、业务对象使用数据模型定义
new Vue({
el: '#app',
data: {
page: {
page: 1,
size: 10
},
loading: false,
person: {}
},
})
如上图所示,一些常规的属性,我们可以定义好,但是类似person
这种业务属性,有可能几十个字段,我们不可能全部定义出来吧。
方法: 我们用的是js-model
来定义业务数据模型,需要定义业务对象的时候,类似Person.parse({})
就可以很好的解决问题了。
大家可以读我写的这一篇文章: 创建前端数据模型,vue开发必备
Basic.js
import Model from "js-model";
let Person = new Model({
"id": 0,
"description": "",
"tags": [ 0 ],
"companyId": "",
"rate": {
type: Number,
default: 0.8
},
"salary": Number
});
export default Basic;
import Basic from './Person.js'
let basic = Person.parse({});
basic:
{
"id": null,
"source": null,
"description": null,
"tags": [],
"companyId": null,
"rate": 0.8, // use default value
"salary": null
}
实际应用:
new Vue({
el: '#app',
data: {
page: {
page: 1,
size: 10
},
loading: false,
person: Person.parse({})
},
})
<span style="font-size: 30px;">👍</span>
这个问题,先点到为止了,我们再继续往下看。
问题二、v-for循环一定要加key
这个问题折磨了我很久,因为我真的不想加key。
但是在系统开发中,不加key是会死的,而且死的很难看,就算这样,我们公司的代码中,还是有大量没有加key的处理,其实纯粹展示没有太大问题,只是一堆warning很不爽。
我提过一些看起来很不合理的bug,但是尤作者都是以没有加key反驳,所以我现在只能乖乖的加key了。
尤作者回复我的一些摘录:
The last<test-b>
belongs to the same parent with the v-for list, but is un-keyed - this makes the list "partially-keyed" and can lead to unexpected behavior.You are using the index as the key... which is the same as no key at all. You should give each of your data objects a unique id so that they can be keyed properly.
我们来总结一下尤作者的回答:
1、如果 belongs to the same parent 同一种组件属于同一个parent,如果不加key,lead to unexpected behavior 将会产生无法预测的行为
<template>
<div>
<ComA></ComA>
<ComA></ComA>
</div>
</template>
注意:所以,以上情况,也属于需要加key的范畴,更不要说是v-for了,不过一般情况下是不会出现问题的,如果你遇到未知的一些展示错误,一般加个key就可以解决(我们之前就遇到过,在渲染一个特别复杂的数据的时候,就是展示不出来,因为结构复杂,以为是代码的问题,调了整整一天,后期发现代码没有问题,加个key就解决了)。
2、You are using the index as the key... which is the same as no key at all
你使用index作为key,其实和没有使用key是一样的
<template>
<div>
<ComA v-for="(item, index) of list" :key="index"></ComA>
</div>
</template>
注意:以上情况,其实和没有加key是一样的,key必须是根据你的数据对象相关的唯一值,就是如果你不想出现bug,可以用生成的id来替代,但是,这样修改数据的时候,整个list都会重新渲染,感人....
当然,还是建议使用数据中的id来定义key值,最方便也最安全。
在线demo: https://codepen.io/vvpvvp/pen/oZKpgE
操作步骤:
- 点击添加*3
- 点击第一行click Me!,变成clicked
- 点击第二行click Me!,变成clicked
- 点击删除第一行
发现clicked保留,最后一行的click Me!被删除
如果你为v-for使用时间戳加个key,问题就会解决。
问题三、v-for循环中,如果有数据编辑,一定要使用对象数组
其实这个问题是属于上面一个问题的衍生。
之前我们有一个数据列表,需要编辑,一开始定义的就是[String]
,可是v-for是需要key的吧,你只能使用String的数据作为key。
<template>
<div id="app">
<div v-for="(item,index) of list" :key="item">
<p>{{item}}</p>
<input type="text" v-model="item">
<button @click="remove(index)">delete</button>
</div>
<button @click="add()">add</button>
</div>
</template>
<script>
new Vue({
el: '#app',
data: {
list: []
},
methods: {
add: function() {
this.list.push("string");
},
remove: function(index) {
this.list.splice(index, 1);
}
}
})
</script>
too young too native
同事问我,为什么input一编辑就blur了,呵呵呵.......
你能想象吗?你改动了一个值,然后你自己被重新渲染了。
但是,我刚刚写了新版本的demo,发现没有这个问题了。
因为新版本直接error了,这样也好,告诉了大家怎么来修改代码,不会让大家一脸懵,input一编辑就blur,你知道是为什么吗?
不过,现在也还是有问题的,就是v-model已经不起作用了,希望大家能注意到error中的说明。
后记
本期的总结就到这里了,后续还有其他的总结
- vue2.0 directive如何使用
- vue v-model 实现机制
最后
希望大家多多支持我们的组件库
HeyUI,🎉UI Toolkit for Web, Vue2.0
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。