👍解说vue开发过程中的“深坑”,HeyUI组件库开发总结

3,145 阅读6分钟

之前,我发了一些关于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是无效的。
  • 先点击change a value无效后,再点击change a value use $set也会无效。
  • 点击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: codepen.io/vvpvvp/pen/…

这个主要问题是,我们开发很少用到$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({})
  },
})

👍

这个问题,先点到为止了,我们再继续往下看。

问题二、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: codepen.io/vvpvvp/pen/…

操作步骤:

  • 点击添加*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>

同事问我,为什么input一编辑就blur了,呵呵呵.......

你能想象吗?你改动了一个值,然后你自己被重新渲染了。

但是,我刚刚写了新版本的demo,发现没有这个问题了。

因为新版本直接error了,这样也好,告诉了大家怎么来修改代码,不会让大家一脸懵,input一编辑就blur,你知道是为什么吗?

不过,现在也还是有问题的,就是v-model已经不起作用了,希望大家能注意到error中的说明。

后记

本期的总结就到这里了,后续还有其他的总结

  • vue2.0 directive如何使用
  • vue v-model 实现机制

最后

希望大家多多支持我们的组件库

HeyUI,🎉UI Toolkit for Web, Vue2.0

www.heyui.top