取消后 VueJS 表单不会恢复到原始状态

VueJS Form does not revert to original after cancel

我有一个应用程序,用户可以在其中手动删除 post 中的文本和文件附件。它工作正常,用户可以删除 post 中的文本和附件,但是,问题是当用户选择“取消”按钮时——附件仍然显示已编辑的附件项目。期望的结果是附件恢复到原始列表。

有人对我如何解决这个问题有任何建议吗?

我在这里设置了一个演示:Codesandbox单击 POSTS --> POST ID --> 编辑 POST - -> 删除附件 --> 取消编辑 )

我正在使用 props 将数据传递给子组件:

Parent component named PostDetail.vue:

模板:

<section v-if="editPostFormIsVis">
      <EditPost
        :post="post"
        @update="editPostFormIsVis=false"
        @cancel="editPostFormIsVis = false"
        :attachmentsArray="attachmentsArray"
        @deleteMediaAttachment="removeItem"
      />
    </section>

脚本:

import attachments from "../../public/attachments.json";
import EditPost from "@/components/EditPost.vue";
export default {
  components: {
    EditPost
  },
  data() {
    return {
      post: {},
      editPostFormIsVis: false,
      attachmentsArray: attachments
    };
  },
  created() {
    this.getPost();
  },
  methods: {
    getPost() {
      axios
        .get(
          "https://jsonplaceholder.typicode.com/posts/" + this.$route.params.id
        )
        .then(resp => {
          this.post = resp.data;
        })
        .catch(err => {
          console.log(err);
        });
    },
    editPost() {
      this.editPostFormIsVis = true;
    },
    removeItem: function(item) {
      this.attachmentsArray.attachments.splice(item, 1);
    }
  },
  computed: {
    emailAttachmentsFileNames() {
      if (this.attachmentsArray.emailAttachments) {
        const emailAttachmentsFileNameArray = this.attachmentsArray.emailAttachments.map(
          item => {
            const tokens = item.split("/");
            return tokens[tokens.length - 1];
          }
        );
        return emailAttachmentsFileNameArray;
      } else {
        return null;
      }
    },
    attachmentsFileNames() {
      if (this.attachmentsArray.attachments) {
        const attachmentsFileNameArray = this.attachmentsArray.attachments.map(
          item => {
            const tokens = item.split("/");
            return tokens[tokens.length - 1];
          }
        );
        return attachmentsFileNameArray;
      } else {
        return null;
      }
    }
  }
};

The child component named EditPost.vue:

模板:

<ul>
          <li>Media Attachments
            <ul v-if="attachmentsFileNames && attachmentsFileNames.length">
              <li v-for="(attachmentFileName, index) in attachmentsFileNames" :key="index">
                <a href="
                    #
                  ">{{ attachmentFileName }}</a>&nbsp;
                <button
                  @click.prevent="$emit('deleteMediaAttachment', attachmentFileName)"
                >Delete me!</button>
              </li>
            </ul>
          </li>
        </ul>

脚本:

export default {
  name: "EditPost",
  props: {
    post: {
      type: Object
    },
    attachmentsArray: {
      type: Object
    }
    // filenames: {
    //   type: Array
    // }
  },
  created() {
    // clone issue without including observers and reactivity
    this.postBeforeEdit = Object.assign({}, this.post);
    this.attachmentsArrayBeforeEdit = Object.assign({}, this.attachmentsArray);
    //this.attachmentsFileNamesBeforeEdit = Object.assign({}, this.attachmentsFileNames)
  },
  methods: {
    editPost() {
      axios
        .put("https://jsonplaceholder.typicode.com/posts/" + this.post.id)
        .then(response => {
          //dosomething
          console.log("server response: ", response.status);
        })
        .then(() => {
          this.$emit("update");
        })
        .catch(err => {
          console.log(err);
        });
    },
    cancelEdit() {
      // revert UI back to original issue values if user cancels edits
      Object.assign(this.post, this.postBeforeEdit);
      Object.assign(this.attachmentsArray, this.attachmentsArrayBeforeEdit);
      // Object.assign(this.attachmentsFileNames, this.attachmentsFileNamesBeforeEdit);
      this.$emit("cancel");
    }
  },
  computed: {
    emailAttachmentsFileNames() {
      if (this.attachmentsArray.emailAttachments) {
        const emailAttachmentsFileNameArray = this.attachmentsArray.emailAttachments.map(
          item => {
            const tokens = item.split("/");
            return tokens[tokens.length - 1];
          }
        );
        return emailAttachmentsFileNameArray;
      } else {
        return null;
      }
    },
    attachmentsFileNames() {
      if (this.attachmentsArray.attachments) {
        const attachmentsFileNameArray = this.attachmentsArray.attachments.map(
          item => {
            const tokens = item.split("/");
            return tokens[tokens.length - 1];
          }
        );
        return attachmentsFileNameArray;
      } else {
        return null;
      }
    }
  }
};

知道为什么取消按钮不会将附件数组恢复为原始数组吗?

EditPost.vue 你有

cancelEdit() {
      // revert UI back to original issue values if user cancels edits
      Object.assign(this.post, this.postBeforeEdit);
      Object.assign(this.attachmentsArray, this.attachmentsArrayBeforeEdit);
      // Object.assign(this.attachmentsFileNames, this.attachmentsFileNamesBeforeEdit);
      this.$emit("cancel");
    }

Object.assign(this.post, this.postBeforeEdit); 其中 this.post 是道具。你不应该改变道具。相反,当取消事件被触发时,在父组件中重置你的 post 和 attachmentsArray 道具(这将在子组件中自动更新)。

更新: 在 EditPost 中,当他们删除一个项目 @click.prevent="$emit('deleteMediaAttachment', attachmentFileName)" 时,您会这样做,然后在父级中编辑附件状态。如果您想防止实际删除,一种方法可能是向每个附件对象添加一个 "deleted: boolean" 字段。在您的编辑方法中,您可以将字段从 false 切换为 true。在模板中,您可以将 v-if 与 v-for 结合使用,以有条件地显示基于已删除的附件。如果用户取消,您需要将这些字段切换回 true。

旁注:在 EditPost 中您引用了 this.attachmentsBeforeEdit = Object.assign({}, this.attachmentsArray); 但它没有在组件中的任何地方初始化。可能将其作为数据包含在内属性,因此您不会将其添加到生命周期挂钩中的数据。