首页 > 解决方案 > 使用 v-show 时组件会重新渲染?VueJS

问题描述

首先,我将解释我的问题以及我在做什么。我正在编写一个表示表中单行的组件。该组件首先显示有关类别的信息(其名称、描述和 ID)。我有一个编辑按钮,我可以在其中编辑每个类别的名称和描述。看起来像这样: 在此处输入图像描述

当我单击编辑按钮时,我将数据替换为输入(仅在名称和描述中),因此我能够更改值,然后将信息发送到服务器。

所以有什么问题?问题是,当我按下编辑按钮时,我更改了输入值(它与 v-model 绑定),然后我再次按下编辑按钮(所以我不想更改数据)数据实际上保持为输入是,我不希望那样。我只想要初始值。

好吧,我已经通过使用 :value 而不是 v-model 解决了这个问题(也许还有另一种方法?)。

问题是,当我保存更改然后检查输入是否正确时,它会重新渲染 DOM(当我显示错误消息时)以及最初具有输入的值,我不想要那个。这是组件的代码:

<template>
  <tr>
    <th>
      {{idCategory}}
    </th>
    <td>
      <p v-if="isEditingCategory === false">
        {{category.name}}
      </p>
      <form class="field" v-show="isEditingCategory">
        <div class="control">
          <input  class="input"
            type="text"
            :value="category.name"
            ref="categoryNameInput"
            style="width: auto;">
        </div>
        <p class="help is-danger" v-show="showHelpMessage">al menos 3 caracteres.</p>
      </form>
    </td>
    <td>
      <!-- TODO. hacer un pipe para que muestre solo los primeros 10 caracteres. -->
      <p v-if="isEditingCategory === false">
        {{ category.description }}
      </p>
      <form class="field" v-if="isEditingCategory">
        <div class="control">
          <input class="input" type="text" :value="category.description" ref="descriptionInput" style="width: auto;">
        </div>
      </form>
    </td>
    <td>
      <!-- Buttons... -->
      <button class="button is-info is-outlined" @click="onEditCategory">
      <span class="icon">
      <i class="fas fa-edit"></i>
      </span>
      </button>
      <button class="button is-success"
        @click="onSaveCategory"
        v-if="isEditingCategory">
      <span class="icon">
      <i class="far fa-save"></i>
      </span>
      </button>
    </td>
  </tr>
</template>
export default {
  data() {
    return {
      isEditingCategory: false,
      isPostingChanges: false,
      category: {
        id: this.idCategory,
        name: this.categoryName,
        description: this.categoryDescription,
        index: this.arrayIndex
      },
      showHelpMessage: false
    }
  },
  methods: {
    onSaveCategory() {
      this.showHelpMessage = false;
      const MIN_CHAR = 3;
      const categoryNameValue = this.$refs.categoryNameInput.value;
      const descriptionValue = this.$refs.descriptionInput.value;
      if (categoryNameValue.length >= MIN_CHAR) {
        console.log(categoryNameValue)
      } else {
        this.showHelpMessage = true;
      }
    },
    onEditCategory() {
      this.isEditingCategory = !this.isEditingCategory;
    }
  },
  props: ['idCategory', 'categoryName', 'categoryDescription', 'arrayIndex']
}

标签: vue.jsvuejs2vue-component

解决方案


处理这样的工作流程的一般方法是使用这些步骤

  1. 在切换到编辑模式时,将道具值复制到本地副本并使用绑定到您的表单输入v-model
  2. 点击save时,验证本地值
  3. 将值提交到您的服务器。这也是禁用输入、按钮等的好时机
  4. 成功后,使用新值向组件父级发出事件并关闭编辑模式
  5. 父级接收此事件并更新其数据。对数据的更改通过您的行组件的道具向下流动,并且值被更新

例如(只关注单个输入)

<td>
  <fieldset class="field" :disabled="isPostingChanges" v-if="isEditingCategory">
    <div class="control">
      <input class="input"
        type="text"
        v-model="categoryForm.name"
        style="width: auto;"
      >
    </div>
    <p class="help is-danger" v-show="showHelpMessage">al menos 3 caracteres.</p>
  </fieldset>
  <p v-else>
    {{ category.name }} <!--  display the prop value here -->
  </p>
</td>
export default {
  props: { category: Object }, // just pass the entire category object as a prop
  data: () => ({
    isEditingCategory: false,
    isPostingChanges: false,
    showHelpMessage: false,
    categoryForm: null
  }),
  methods: {
    onEditCategory () {
      this.isEditingCategory = !this.isEditingCategory
      if (this.isEditingCategory) {
        // assign local copies from props
        this.categoryForm = { ...this.category }
      }
    },
    async onSaveCategory () {
      // do your validation against `this.categoryForm`, then if valid...

      this.isPostingChanges = true

      // now send to your server (this is all guesswork)
      const res = await fetch(`/api/categories/${this.category.id}`, {
        method: "PUT",
        headers: { "Content-type": "application/json" },
        body: JSON.stringify(this.categoryForm)
      })
      this.isPostingChanges = false
    
      if (res.ok) {
        const updated = await res.json() // the updated values from the server
        this.isEditingCategory = false
        this.$emit("updated", updated) // emit the new values
      }
    }
  }
}

然后在你的父组件中,添加一个监听器

<row-component
  v-for="(category, index) in categories"
  :key="category.id"
  :category="category"
  @updated="updateCategory($event, index)"
/>
methods: {
  updateCategory(category, index) {
    // remove the old category and replace it with the updated one
    this.categories.splice(index, 1, category)
  }
}

推荐阅读