关于antd vue form表单回显的问题(vue2)(antd 1.x)

文章讲述了在使用Vue2的脚手架和antdvue1.x版本时,作者遇到动态表单回显问题,发现`watch`的`immediate`属性导致组件在数据变化前就渲染了一次,影响了首次回显。通过`this.$nextTick`和添加条件判断解决了这个问题,同时提到了其他优化建议。
摘要由CSDN通过智能技术生成

首先记录两个小点:

1、Array.prototype.find 比 Array.prototype.filter更加的节省性能,因为find是找到需要的数据就直接return,不会继续找了

2、xxx.attribute = xxx.attribute === 1 ? true : false 可以直接简化 =》 xxx.attribute = xxx.attribute === 1

ok,下面进入正题:

之前的一个问题困扰了我很久,这里说一下,我用的是vue2的脚手架,所以antd vue对应的版本是1.x,专门服务于vue2的。

问题是这样的,这个弹窗中的表单是我自己封装的一个组件,这里回显的逻辑是这样的:

<template>
  <div class="FormModalComponent">
    <a-form :form="form" @submit="handleSubmit">
      {{ datas.form_data_set }}
      <div v-for="(level1, i1) in datas.form_data" :key="i1">
        <a-form-item :label="level1.label">
          <!-- 输入框 -->
          <div v-if="level1.type == '1'">
            <a-input
              v-decorator="[
                level1.key,
                {
                  rules: [
                    {
                      required: level1.required,
                      message: level1.message,
                    },
                  ],
                },
              ]"
              :placeholder="level1.placeholder"
            />
          </div>
          <!-- 下拉框 -->
          <div v-if="level1.type == '2'">
            <a-select
              v-decorator="[
                level1.key,
                {
                  rules: [
                    { required: level1.required, message: level1.message },
                  ],
                },
              ]"
              :placeholder="level1.placeholder"
            >
              <a-select-option
                v-for="(level2, i2) in level1.options"
                :key="i2"
                :value="level2.value"
              >
                {{ level2.label }}
              </a-select-option>
            </a-select>
          </div>
          <!-- 开关 -->
          <div v-if="level1.type == '3'">
            <a-switch
              checked-children="是"
              un-checked-children="否"
              default-unchecked
              v-decorator="[
                level1.key,
                { initialValue: false, valuePropName: 'checked' },
              ]"
            />
          </div>
        </a-form-item>
      </div>
      <!-- 确认和取消按钮 -->
      <a-form-item :offsetBottom="2">
        <a-space>
          <a-button type="info" @click="cancelHandleClick">取消</a-button>
          <a-button type="primary" htmlType="submit">确认</a-button>
        </a-space>
      </a-form-item>
    </a-form>
  </div>
</template>
<script>
export default {
  props: {
    datas: {
      type: Object,
      default: () => ({}),
    },
  },
  data() {
    return {
      form: this.$form.createForm(this, { name: "dynamic_rule" }),
    };
  },
  created() {
    console.log(this.datas, "datas");
  },
  methods: {
    handleSubmit(e) {
      e.preventDefault();
      this.form.validateFields((err, fieldsValue) => {
        if (err) {
          return;
        }
        this.$emit("onSubmit", fieldsValue);
      });
    },
    cancelHandleClick() {
      this.$emit("onCancel");
    },
  },

  watch: {
    datas: {
      deep: true,
      handler(n, o) {
        if (n.visible === true) {
          let form_value = {};
          n.form_data.forEach((item) => {
            for (const key in n.form_data_set) {
              if (item.key == key) {
                form_value[key] = n.form_data_set[key];
              }
            }
          });
          const arr = Object.keys(form_value);
          if (arr.includes("reportshow")) {
            form_value.reportshow = form_value.reportshow == 1;
          }
          if (arr.includes("show")) {
            form_value.show = form_value.show == 1;
          }
          if (n.editIndex) {
            this.$nextTick(() => {
              this.form.setFieldsValue(form_value);
            });
          }
        }
        if (!n.editIndex) {
          this.form.resetFields();
        }
      },
      immediate: true,
    },
  },
};
</script>
<style lang="less" scoped>
.FormModalComponent {
  height: 11rem;
  overflow-y: auto;
}
</style>

如上,我监听了传入进来的数据,通过一系列的数据处理之后,通过this.form.setFieldsValue这个方法进行回显数据,上面是已经完善过的代码,之前一直碰到的一个问题就是,每次初始化,第一次回显总是回显失败,后续全部是成功的。经过分析,问题如下:

问题出处:

问题就出在这个immediate: true上,这个immediate属性,通过打印可以发现,它在created之前就已经执行过了,也就是说,在你的数据通过props传进来并渲染到virtual dom上之前,它就已经把最初始化的数据拿进来渲染过一次了,因此,当你通过调用接口改变数据结构的时候,改变之后的数据,并没有通过这次immediate再次渲染一次,所以第一次失效了,没有回显到表单上。

解决方式:

我的解决方式是通过this.$nextTick,加上一个editIndex是否存在的判断来辅助来解决的,这样可以强制渲染最新的数据,并且保证新增的时候不执行这一条数据。

其他方式:

这里给出几条其他的解决方式:

1、在需要渲染的弹窗上加一个v-if,条件是你需要后续更改的那条数据是否较于之前有变化,比如:一开始form_data是空,赋值后才把数据传入,那么就可以判断v-if = "form_data.length === 0"

另外,watch这个属性,尽量不要监听过大的对象,可以监听这个对象中的多个属性,可以进行优化。

  • 12
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值