【问题标题】:Vue is not rendering v-for input fields from array after mutating the arrayVue 在改变数组后没有从数组中渲染 v-for 输入字段
【发布时间】:2019-06-28 10:21:25
【问题描述】:

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

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

这是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>

【问题讨论】:

    标签: javascript vue.js


    【解决方案1】:

    只需评论 line no 111App.vue 即可。

    // this.formData = {}
    

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

    【讨论】:

    • 是的,昨天在 Vue 社区的帮助下想通了。下面的代码也很好用this.formData.unloadingContactPersons = [ ]
    • 您可能希望接受我的答案作为正确答案。花半小时分析你的代码:D
    • 非常感谢!刚刚开始弄清楚反应性是如何工作的
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-02
    • 1970-01-01
    • 1970-01-01
    • 2021-04-16
    • 1970-01-01
    • 2019-08-12
    相关资源
    最近更新 更多