【问题标题】:Vue.js - Updated or undo pattern with child componentVue.js - 使用子组件更新或撤消模式
【发布时间】:2017-11-28 23:33:45
【问题描述】:

我在从子组件更新正确对象时遇到问题。

我的设置如下: 一个 ul 列表,其中包含我想要呈现或编辑的大部分数据。 在“li”的一部分上,有一个子组件来显示那部分数据,这是一个连接到该对象的资源列表,并且还处理新资源的推送。

我还希望用户有一个按钮来启用行的编辑模式,然后是更新和取消按钮。

我面临的问题是找出我应该编辑然后保存的对象。我现在正在做的是尝试将行中的数据复制到 mutableRow 中,然后我将其用作输入控件的模型,而当用户不处于编辑模式时会显示实际的行数据。在更新方法中,我发布到数据库并更新了行对象。

ul
  li(v-for="row in rows")
    p(v-if="!row.editing") {{ row.name }}
    input(v-else, v-model="mutableRow.name")
    resources(:row="row")
    button(v-if="!row.editing") Start edit
    template(v-else)
      button Update
      button Cancel

这是正确的方法吗?如果是,我应该如何处理发送到我的子组件的道具?我尝试通过 this.$parent.mutableRow 获取 mutableRow,我尝试使用 v-if 切换“resource(:row="row")”,如果处于编辑模式,则发送 mutableRow,但随后我结束以某种方式从组件中更改两个对象。

我可以在这里使用另一种模式吗?

【问题讨论】:

  • 我会将整个li 设为一个组件,其中editing 状态和编辑值位于组件内部。更新会发出一个事件,取消只会重置编辑值。
  • 您能否举个例子,因为我不完全理解您的意思。 :/ 你的意思是整个事情应该是一个组件吗?问题是它有很多不同的输入字段,所以有很多方法和模板,所以我试着把它做成更小的部分。
  • 你能展示你的数据是什么样的吗?一个组件内部可能应该有更小的组件。
  • 数据看起来有点如下: { name: "Test", thingy: 4, resources: [ { title: "Title", price: 5000 } ] } 你的意思是结构应该像这个: ul li(v-for="row in rows") row-component(:row="row") 并且在 row-component 中: .root-object input(v-model="row.name") 资源-component(:resources="row.resources") 问题是我找不到将道具切换为可变副本的方法。将真实数据提供给行组件会很棒,然后用副本切换它以进行更改。

标签: design-patterns vue.js components edit cancellation


【解决方案1】:

我认为您提到的“可变行”问题是通过传递rows[index] 而不是row 来解决的。无论如何,这就是使.sync 工作所需要的。

下面的示例实现了我在 cmets 中建议的内容:具有自己的数据副本和自己的编辑模式控件的单个组件。当您开始编辑时,道具数据被复制到本地数据中。当您单击更新时,将发出一个事件,并且父级(通过sync)将编辑后的数据复制到行中。如果单击取消,则不会发出任何事件,并且编辑结束。

new Vue({
  el: '#app',
  data: {
    rows: [{
      name: "Test",
      thingy: 4,
      resources: [{
        title: "Title",
        price: 5000
      }]
    }]
  },
  components: {
    rowEditor: {
      template: '#row-editor-t',
      props: ['row'],
      data() {
        return {
          editing: false,
          localRow: null
        };
      },
      methods: {
        startEditing() {
          this.editing = true;
          this.localRow = JSON.parse(JSON.stringify(this.row));
        },
        stopEditing() {
          this.editing = false;
        },
        update() {
          this.$emit('update:row', this.localRow);
          this.stopEditing();
        },
        cancel() {
          this.stopEditing();
        }
      }
    }
  }
});
<script src="//cdnjs.cloudflare.com/ajax/libs/vue/2.4.2/vue.min.js"></script>
<div id="app">
  <ul>
    <li v-for="row, index in rows" is="row-editor" :row.sync="rows[index]">
    </li>
  </ul>
</div>

<template id="row-editor-t">
  <li>
    <div v-if="editing">
      <input v-model="localRow.name">
      <div v-for="resource in localRow.resources">
        <input v-model="resource.title"><input v-model="resource.price">
      </div>
    </div>
    <div v-else>
      {{row.name}}
      <div v-for="resource in row.resources">
        {{resource.title}}: {{resource.price}}
      </div>
    </div>
    <div v-if="editing">
      <button type="button" @click="update">Update</button>
      <button type="button" @click="cancel">Cancel</button>
    </div>
    <button v-else @click="startEditing">Start edit</button>
  </li>
</template>

<!--
ul
  li(v-for=" row in rows ")
    p(v-if="!row.editing ") {{ row.name }}
    input(v-else, v-model="mutableRow.name ")
    resources(:row="row ")
    button(v-if="!row.editing ") Start edit
    template(v-else)
      button Update
      button Cancel
-->

【讨论】:

  • 完美!这个解决方案确实帮助我找到了代码中的问题。我最终将每一行分解为一个组件,然后只为整行使用一个组件,但最大的问题仍然存在。我发现我用来复制对象的“this.mutableRow = Vue.util.extend({}, this.row)”只做了一个浅拷贝,这就是为什么我最终修改了“resources”数组原始对象。现在我使用 jQuery.extend(true, {}, this.row) 来创建深层副本。不知道 jQuerys 函数或 JSON 解析技巧是否是最好的,但这有效。谢谢!
猜你喜欢
  • 2011-12-04
  • 2018-04-12
  • 2019-10-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-02-19
  • 2019-10-10
  • 2011-01-11
相关资源
最近更新 更多