ElementUI el-input 设置数据无法修改

        今天学生遇到一个问题,后台接口获得的数据在生成列表时,el-input绑定v-model的数据虽然能显示,但是无法输入和修改数据。

        分析原因是在定义data数据初始化时候没有把原始的属性结构定义,AJAX返回结果后直接给form添加新的属性并赋值,虽然数据能显示,但是这样添加的属性不是响应式的,如果在模板或渲染函数中使用该属性,这个新的属性将无法触发组件重新渲染。

        例如


export default {
  // 省略其他代码 ...
  data() {
    return {
      form:{
        // 没有定义checkList结构
      }
    };
  },
  methods: {
    getList() {
      
      list().then(resp=>{
          // 此处resp.data是一个对象数组,其中数组中的一个对象某个属性绑定el-input的v-model
          // 结果就是只能看不能改
          this.form.checkList = resp.data;
      })
    },
  }
 // 省略其他代码 ...
};

解决方案:

网上有一些方案,比如添加input、change之类的事件,调用强制更新this.$forceUpdate(),试过之后并没有解决问题,分析是因为本来el-input就已经是无法修改状态,input,change事件怎么触发呢?现在想想keydown倒是没试过,不知道有没有用...

<el-input @input="forceUpdate" v-model="xxx"></el-input>
...
methods:{
    forceUpdate(){
        this.$forceUpdate()
    }
}

还有什么给el-input外层的template加slot-scope,没有解决问题。

<template slot-scope="scope">

如果是非对象或数组的属性,可以用this.$set来设置数据,由于data是数组,还是无效的

this.$set(this.form, "checkList", resp.data);

最后想了想,自己写了一个递归深拷贝的方法,成功解决问题。代码应该还能再简化简化,前端能力有限没再整了,贴出代码供参考,欢迎前端大佬指教和优化

export default {
    // 省略其他代码 ...
    data() {
      return {
        form: {}
      };
    },
    methods: {
      getList() {

        list().then(resp => {
          // 此处resp.data是一个对象数组,其中一个属性绑定el-input的v-model
          // 结果只能看不能改
          // this.form.checkList = resp.data;
          // 改为调用深拷贝方法
          this.setDataTo(this.form, "checkList", resp.data);
        })
      },
      /**
        * Vue数据深拷贝
        * @param obj    被设置数据的对象
        * @param member 被复制添加到obj中的属性名
        * @param data   需被深拷贝到obj中的属性值
        */
      setDataTo(obj, member, data) {
        if (data == null) {
          return;
        }
        obj[member] = data;
        if (data instanceof Array) {  // 处理数组
          if (!obj[member]) {
            // 数据是数组,就设置为数组,元素循环设置
            obj[member] = [];
          }
          for (let index in data) {
            // 递归设置每个数组元素
            this.setDataTo(obj[member], index, data[index]);
          }
          
        } else if (typeof data == "object") { // 处理对象
          if (!obj[member]) {
            // 数据是对象,就设置为对象,属性循环设置
            obj[member] = {};
          }
          
          for (let [key, value] of Object.entries(data)) {
            // 递归设置每个属性
            this.setDataTo(obj[member], key, value)
          }
        } else {
          // 其他类型的普通字段直接设置
          this.$set(obj, member, data);
        }
      }
    }
    // 省略其他代码 ...
  };

        这个方法的好处在于能动态的设置响应式数据,也许有更优雅的方式、也可能我只是在重复造轮子,但是解决了问题也是一种收获。

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
好的,我来给您提供一个基于Vue.jsElementUI的实现代码,需要您自己根据实际情况进行修改: ```vue <template> <div> <el-dialog :visible.sync="dialogVisible" title="账单拆分"> <el-form :model="formData" :rules="rules" ref="form"> <el-form-item label="开始时间" prop="startDate"> <el-date-picker v-model="formData.startDate" type="date" placeholder="选择开始时间"></el-date-picker> </el-form-item> <el-form-item label="结束时间" prop="endDate"> <el-date-picker v-model="formData.endDate" type="date" placeholder="选择结束时间"></el-date-picker> </el-form-item> <el-form-item label="金额" prop="amount"> <el-input v-model.number="formData.amount" placeholder="请输入金额"></el-input> </el-form-item> </el-form> <div slot="footer" class="dialog-footer"> <el-button @click="dialogVisible = false">取消</el-button> <el-button type="primary" @click="onSubmit">添加</el-button> </div> </el-dialog> </div> </template> <script> export default { data() { return { dialogVisible: false, formData: { startDate: '', endDate: '', amount: '', }, rules: { startDate: [{ required: true, message: '请选择开始时间', trigger: 'blur' }], endDate: [{ required: true, message: '请选择结束时间', trigger: 'blur' }], amount: [{ required: true, message: '请输入金额', trigger: 'blur' }], }, }; }, methods: { onSubmit() { this.$refs.form.validate(valid => { if (valid) { // 校验通过,提交数据 let data = { startDate: this.formData.startDate, endDate: this.formData.endDate, amount: this.formData.amount, }; this.$emit('add-bill', data); this.dialogVisible = false; } }); }, }, }; </script> ``` 这是一个用于展示账单拆分对话框的组件,其中包含了一个表单,用于输入拆分后的账单信息。在点击添加按钮时,通过`onSubmit`方法提交数据,并进行表单校验,校验成功后将数据传递给父组件。 在你的页面中,你需要使用该组件,并实现对应的逻辑,比如: ```vue <template> <div> <el-table :data="billList"> <el-table-column prop="startDate" label="开始时间"></el-table-column> <el-table-column prop="endDate" label="结束时间"></el-table-column> <el-table-column prop="totalAmount" label="总金额"></el-table-column> <el-table-column label="操作"> <template slot-scope="{ row }"> <el-button type="text" @click="handleSplit(row)">拆分</el-button> </template> </el-table-column> </el-table> <bill-split-dialog :visible.sync="splitDialogVisible" @add-bill="handleAddBill" ></bill-split-dialog> </div> </template> <script> import BillSplitDialog from './components/BillSplitDialog.vue'; export default { components: { BillSplitDialog, }, data() { return { billList: [ { startDate: '2023-05-01', endDate: '2023-05-31', totalAmount: 1000 }, { startDate: '2023-06-01', endDate: '2023-06-30', totalAmount: 2000 }, ], splitDialogVisible: false, currentBill: null, }; }, methods: { handleSplit(bill) { this.currentBill = bill; this.splitDialogVisible = true; }, handleAddBill(data) { // 校验数据 if (data.amount > this.currentBill.totalAmount) { this.$message.error('拆分金额不能大于总金额!'); return; } let bill = { startDate: data.startDate, endDate: data.endDate, totalAmount: data.amount, }; this.currentBill.totalAmount -= data.amount; this.billList.push(bill); }, }, }; </script> ``` 在上面的代码中,我们展示了一个表格,包含了账单的开始时间、结束时间和总金额三个字段,同时还有一个操作列,用于点击拆分按钮打开对话框。当点击拆分按钮时,我们将当前的账单信息保存到`currentBill`变量中,并将`splitDialogVisible`变量设置为`true`,打开对话框。在对话框中输入完成后,通过`handleAddBill`方法接收到数据,并进行校验。如果拆分金额大于总金额,则提示用户输入有误。否则,将拆分后的账单信息保存到`billList`中,并将当前账单的总金额减去拆分金额。 最后,当所有的拆分都完成后,我们可以将`billList`传递给后端进行处理。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值