ElementUI Form resetFields

改名字很傷神發表於2018-06-08

前言

在一次結合v-if/v-elseresetFields結合使用reset之後值不正常,看完原始碼提了issue,然後被告知答案原來就在vue文件裡,打臉打臉,因此記錄一次不看文件,並且出問題不第一時間找文件的教訓。

結論

  1. 凡事先從文件下手,用element-ui不是光看element-ui的文件,還要看vue文件
  2. Form元件resetFieldsdata值沒什麼關係,只跟Form-Item建立時的初始值有關。
  3. 使用v-if/v-else時,要先確定元件是需要重新生成(用 key 管理可複用的元素),還是可以直接替換(新元件會使用舊元件的初始值,事實上這裡新舊是同一個元件更改了屬性)。
  4. 只有含有prop屬性,並且當前存在的元件才會reset
  5. 如果Form元件不是一開始就建立,可以用nextTick等待Form/Form-Item第一次建立完再resetFields。(這個其實跟元件沒多大關係)

事故現場

https://jsfiddle.net/s5ar1un3…

上面程式碼切換元件後,執行resetFields重置值,結果重置的值為別的元件繫結的初始值。

事故原因

Vue 會盡可能高效地渲染元素,通常會複用已有元素而不是從頭開始渲染。

也就是說使用v-if/v-else時,雖然看似是多個元件切換,但實際上是1個元件切換了自身的屬性。但問題的關鍵是,切換了vue的屬性,element-ui新增的屬性比如初始值並沒有換。

解決

https://jsfiddle.net/s5ar1un3…

Vue 為你提供了一種方式來表達“這兩個元素是完全獨立的,不要複用它們”。只需新增一個具有唯一值的 key 屬性即可。

在事故現場上加上key值繫結。用 key 管理可複用的元素

resetFields過程

form.vue

created() {
      this.$on(`el.form.addField`, (field) => {
        if (field) {
          this.fields.push(field);
        }
      }
      
      this.$on(`el.form.removeField`, (field) => {
        if (field.prop) {
          this.fields.splice(this.fields.indexOf(field), 1);
        }

      });
}

resetFields() {
        ...
        
        this.fields.forEach(field => {
          field.resetField();
        });
      },

form-item.vue

    mounted() {
        if (this.prop) {
            this.dispatch(`ElForm`, `el.form.addField`, [this]);
            ...
            
            let initialValue = this.fieldValue;
            
            ...
            
            Object.defineProperty(this, `initialValue`, {
              value: initialValue
            });
            ...
        }
    }

    beforeDestroy() {
      this.dispatch(`ElForm`, `el.form.removeField`, [this]);
    }

    resetField() {
        ...

        this.validateDisabled = true;
        if (Array.isArray(value)) {
          prop.o[prop.k] = [].concat(this.initialValue);
        } else {
          prop.o[prop.k] = this.initialValue;
        }
    }
  1. Formcreated階段建立監聽,儲存下當前Form-Item
  2. Form-Itemmounted判斷是否存在prop屬性,如果有,設定好初始值。
  3. Form元件resetFields實際上是儲存當前註冊上來的子元件Form-ItemresetField方法。
  4. Form-ItemresetField方法重新賦值為this.initialValue。(之前事故原因就是元件屬性更新initialValue值是不會變的)

參考

https://cn.vuejs.org/v2/guide…

https://github.com/ElemeFE/el…

http://element-cn.eleme.io/#/…

相關文章