Vue 2 中如何优雅地处理表单列表项添加与删除而不直接操作 props?

vue2做一个类似表单列表的东西,可添加删除表单项,但是目前是直接操作props,能帮我不直接操作props吗

//外部表单
export default {
  name: 'OutForm',
  template: `
  <el-form ref="outForm" class="outForm" :model="form" :inline="true" > 
    <el-form-item prop="name" label="表单名称" :rules="[{required:true}]">
      <el-input v-model="form.name"></el-input>
    </el-form-item>
    <el-form-item label="表单组">
      <NestForm ref="nestForm" :group="form.activityGroup"></NestForm>
    </el-form-item>
    <el-form-item label="表单数据为">
      {{form}}
    </el-form-item>
    <el-form-item>
      <el-button @click="handleSubmit">提交表单</el-button>
    </el-form-item>
  </el-form>
  `,
  data() {
    return {
      form: {
        name: 'zs',
        activityGroup: [
          {
            name: '活动一',
            region: '区域一',
            type: '类型一'
          },
          {
            name: '活动二',
            region: '区域二',
            type: '类型二'
          },
        ]
      }
    }
  },
  methods: {
    handleSubmit() {
      this.$refs.outForm.validate((valid) => {
        if (valid) {
          this.$message.success("提交成功")
        } else {
          this.$message.error("表单验证失败")
        }
      })
    }
  }
}
export default {
  name: "NestForm",
  template: `
    <div>
      <div v-for="(item,index) in group" :key="index" class="nestItem">
        <el-form-item :prop="'activityGroup['+index+']'+'.name'" label="名称" :rules="[{required:true,message:'请输入名称'}]">
          <el-input v-model="item.name"></el-input>
        </el-form-item>
        <el-form-item :prop="'activityGroup['+index+']'+'.region'" label="活动区域" :rules="[{required:true,message:'请输入活动区域'}]">
          <el-input el-input v-model="item.region"></el-input>
        </el-form-item>
        <el-form-item :prop="'activityGroup['+index+']'+'.type'" label="活动形式" :rules="[{required:true,message:'请输入活动形式'}]">
          <el-input v-model="item.type"></el-input>
        </el-form-item>
        <el-form-item>
          <el-button type="danger" icon="el-icon-delete" circle @click="handleDelete(index)"/>
        </el-form-item>
      </div>
      <el-button @click="handleAdd">添加活动</el-button>
    </div>
      
  `,
  props: {
    group: {
      type: Array,
      default() {
        return []
      }
    }
  },
  methods: {
    handleAdd() {
      this.group.push({
        name: '',
        region: '',
        type: ''
      })
    },
    handleDelete(index) {
      this.group.splice(index, 1)
    }
  }
}

感觉通过父组件的方法改外部值很麻烦呀,求大佬指教有啥巧妙方法

阅读 1.3k
avatarAI BotBETA

在Vue 2中,处理类似表单列表项添加与删除而不直接操作props,可以通过使用.sync修饰符或者自定义事件来避免直接修改props。这是因为props是单向数据流,不应该在子组件内部被修改。

以下是通过自定义事件来实现优雅处理表单列表项添加与删除而不直接操作props的方法:

NestForm 组件修改

export default {
  name: "NestForm",
  props: {
    group: {
      type: Array,
      default: () => []
    }
  },
  methods: {
    handleAdd() {
      this.$emit('update:group', [...this.group, {
        name: '',
        region: '',
        type: ''
      }]);
    },
    handleDelete(index) {
      const updatedGroup = [...this.group];
      updatedGroup.splice(index, 1);
      this.$emit('update:group', updatedGroup);
    }
  }
}

OutForm 组件模板修改

<template>
  <el-form ref="outForm" class="outForm" :model="form" :inline="true" > 
    <!-- ... 其他表单项 ... -->
    <el-form-item label="表单组">
      <NestForm :group="form.activityGroup" @update:group="handleUpdateGroup" />
    </el-form-item>
    <!-- ... 其他表单项 ... -->
  </el-form>
</template>

OutForm 组件方法修改

export default {
  // ... 其他部分 ...
  methods: {
    // ... 其他方法 ...
    handleUpdateGroup(newGroup) {
      this.$set(this.form, 'activityGroup', newGroup);
    },
    // ... 其他方法 ...
  }
}

在这个修改后的例子中,我们移除了NestForm组件中的group数组的直接操作,转而使用$emit来触发一个自定义事件update:group,并传递更新后的数组作为参数。在父组件OutForm中,我们监听这个自定义事件,并在事件处理函数handleUpdateGroup中更新form.activityGroup的值。

这样做的好处是:

  1. 遵循了Vue的props单向数据流原则,避免了直接修改props。
  2. 通过自定义事件,子组件可以通知父组件其内部状态的变化,并由父组件来决定如何处理这个变化。
  3. 代码更加清晰和可维护,因为所有的状态更新都集中在父组件中处理。

请注意,使用$set是为了确保Vue能够检测到数组的变化并触发视图更新。在Vue 2中,如果你直接用一个新数组替换旧数组,Vue可能不会检测到这个变化,因此需要使用$set来确保响应性。如果你使用的是Vue 3,那么就不需要$set,因为Vue 3使用Proxy来实现响应性,可以直接替换数组。

1 个回答

刚想回答发现AI回答的不错了,你可以参照下。就是用$emit来触发父组件事件。
不要在子组件里修改传入的props,违反了单向数据流的原则,出问题了也比较难排查。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
宣传栏