javascript - 改变数组后,Vue 不渲染数组中的 v-for 输入字段

标签 javascript vue.js

Vue 组件在外部设置其值后不会重新渲染数组项。状态变化,但 v-for 元素未显示变化。

我有一个从数组中呈现项目的组件。我还有更改数组长度的按钮,效果很好:“+”添加一行,“-”删除最后一行。当我从获取方法设置数组数据时,问题就开始了。显示数据,但“+”和“-”按钮不起作用。

这是 codesanbox 的链接 https://codesandbox.io/s/q9jv524kvw

/App.vue

<template>
  <div id="app">
    <button @click="downloadTemplate">Load data</button>
    <HelloWorld :formData="formData" />
  </div>
</template>

<script>
import HelloWorld from "./components/HelloWorld";

export default {
  name: "App",
  components: {
    HelloWorld
  },
  data() {
    return {
      fakeData: {
        unloadingContactPersons: [
          {
            id: this.idGen("unloadingContactPersons"),
            value: "123"
          },
          {
            id: this.idGen("unloadingContactPersons"),
            value: "1234"
          },
          {
            id: this.idGen("unloadingContactPersons"),
            value: "12345"
          }
        ]
      },
      lengthDependentLoadings: [
        "loadingDates",
        "loadingAddresses",
        "loadingContactPersons"
      ],
      lengthDependentUnloadings: [
        "unloadingDates",
        "unloadingAddresses",
        "unloadingContactPersons"
      ],
      formData: {
        unloadingContactPersons: [
          {
            id: this.idGen("unloadingContactPersons"),
            value: ""
          }
        ]
      }
    };
  },
  methods: {
    idGen(string = "") {
      // Math.random should be unique because of its seeding algorithm.
      // Convert it to base 36 (numbers + letters), and grab the first 9 characters
      // after the decimal.
      return (
        string +
        "_" +
        Math.random()
          .toString(36)
          .substr(2, 9)
      );
    },
    addLine(id) {
      console.log("id", id);
      const parentName = id.split("_")[0];

      const dependentArray = this.lengthDependentLoadings.includes(parentName)
        ? this.lengthDependentLoadings
        : this.lengthDependentUnloadings;

      dependentArray.forEach(objName => {
        this.formData[objName]
          ? this.formData[objName].push({
              id: this.idGen(objName),
              value: ""
            })
          : null;
      });

      console.log("--length", this.formData.unloadingContactPersons.length);
    },
    removeLine(id) {
      const parentName = id.split("_")[0];

      const dependentArray = this.lengthDependentLoadings.includes(parentName)
        ? this.lengthDependentLoadings
        : this.lengthDependentUnloadings;

      dependentArray.forEach(objName => {
        this.formData[objName] ? this.formData[objName].pop() : null;
      });

      console.log("--length", this.formData.unloadingContactPersons.length);
    },

    downloadTemplate(link) {
      // fake fetch request
      const getFunctionDummy = data =>
        new Promise(resolve => setTimeout(resolve.bind(null, data), 1500));

      // data setter

      getFunctionDummy(this.fakeData).then(result => {
        // set our data according to the template data
        const templateKeys = Object.keys(result);
        const templateData = result;
        this.formData = {};

        templateKeys.forEach((key, index) => {
          let value = templateData[key];
          console.log(value);

          if (Array.isArray(value)) {
            console.log("array", value);
            this.formData[key] = value.map((item, id) => {
              console.log("---from-template", item);
              return {
                id: this.idGen(key),
                value: item.value
              };
            });
          } else {
            this.formData[key] = {
              id: this.idGen(key),
              value
            };
          }
        });
      });
    }
  },
  mounted() {
    // takes id number of item to be added
    this.$root.$on("addLine", ({ value }) => {
      console.log("---from-mounted", value);
      this.addLine(value);
    });

    // takes id number of item to be removed
    this.$root.$on("removeLine", ({ value }) => {
      this.removeLine(value);
    });
  },

  beforeDestroy() {
    this.$root.$off("addLine");
    this.$root.$off("removeLine");
  }
};
</script>

/HelloWorld.vue

<template>
  <div class="hello">
    <div class="form-item">
      <div class="form-item__label">
        <label :for="formData.unloadingContactPersons"
          >Contact person on unload:</label
        >
      </div>
      <div class="form-item__input multiline__wrapper">
        <div
          class="multiline__container"
          @mouseover="handleMouseOver(unloadingContactPerson.id);"
          v-for="unloadingContactPerson in formData.unloadingContactPersons"
          :key="unloadingContactPerson.id"
        >
          <span
            class="hover-button hover-button__remove"
            @click="removeLine(unloadingContactPerson.id);"
            ><i class="fas fa-minus-circle fa-lg"></i>-</span
          >
          <input
            class="multiline__input"
            :id="unloadingContactPerson.id"
            type="text"
            v-model="unloadingContactPerson.value"
            @input="emitFormData"
          />
          <span
            class="hover-button hover-button__add"
            @click="addLine(unloadingContactPerson.id);"
            ><i class="fas fa-plus-circle fa-lg"></i>+</span
          >
        </div>
      </div>
    </div>
  </div>
</template>

<script>
import Datepicker from "vuejs-datepicker";
import { uk } from "vuejs-datepicker/dist/locale";

export default {
  name: "SubmitForm",
  components: {
    Datepicker
  },
  props: {
    formData: Object
  },
  data: () => {
    return {
      uk,
      hoveredItemId: null
    };
  },
  methods: {
    emitFormData() {
      this.$root.$emit("submitFormData", { value: this.formData });
    },
    handleMouseOver(id) {
      this.hoveredItemId = id;
    },
    addLine(id) {
      // console.log("---add", id);
      this.$root.$emit("addLine", {
        value: id
      });
    },
    removeLine(id) {
      // console.log("---remove", id);
      this.$root.$emit("removeLine", {
        value: id
      });
    }
  }
};
</script>

最佳答案

只需注释 App.vue111 行 即可。

// this.formData = {}

问题是您直接改变了 Vue.js 无法检测到的 formData 对象。阅读更多关于 Array Change detection [List Rendering - Vue.js] 的信息

关于javascript - 改变数组后,Vue 不渲染数组中的 v-for 输入字段,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54520172/

相关文章:

unit-testing - 如何使用 '@vue/test-utils' 测试 VueRouter 的 beforeRouteEnter ?

javascript - 从指令调用时未定义Typescript Angularjs Controller 范围

javascript - 如何检查 token 过期和注销用户?

javascript - 使用 AngularJS 自定义过滤器根据另一个集合过滤一个集合

android - 使用 vue.js 和 android 的移动应用程序的区别

javascript - Vuex 计算属性不更新 v-show

javascript - 如何使用 Javascript 映射和过滤 JSON

javascript - 如何将表单值发送到服务器、数据库或电子邮件

javascript - 试图让 firebase.auth().currentUser 成为一个 promise

node.js - 如何从 Nodejs 应用程序连接到 Heroku 上的 PostgresQL?