Vue.js: v-for 循环中的值未与正确的数组项保持一致

Vue.js: A value in a v-for loop is not staying with the correct array items

我正在尝试创建一个简单的应用程序来为服务部门申请车钥匙。显然代码可以写得更好,但这是我使用 Vue.js 的第三天。在代码的第一个 p 标记中调用的时间函数每分钟更新一次以记录经过的时间。我遇到的问题是当我请求一个新键时,时间函数没有按预期跟随数组项。例如,如果没有其他请求,我提交的第一个请求可以完美运行。但是,当我提交新请求时,从我的第一个请求到第二个请求的经过时间。我确信它可能与粘合在一起的代码有关,但我已经尝试了我能想到的一切。任何帮助将不胜感激。

<template>
    <div class="row">
        <div class="card col-md-6" v-for="(key, index) in keys" :key="index">
          <div class="card-body">
            <h5 class="card-title">Service Tag: {{ key.service_tag }}</h5>
            <p class="card-text"> {{time}} {{key.reqTimestamp}}min</p>
            <p class="invisible">{{ start(key.reqTimestamp) }}</p>
            <p class="card-text">Associates Name: {{key.requestor_name}}</p>
            <p class="card-text">Model: {{key.model}}</p>
            <p class="card-text">Color: {{key.color}}</p>
            <p class="card-text">Year: {{key.year}}</p>
            <p class="card-text">Comments: {{key.comments}}</p>
            <p class="card-text">Valet: {{key.valet}}</p>
            <input class="form-control" v-model="key.valet" placeholder="Name of the person getting the car...">
            <button
              @click="claimedKey(key.id, key.valet)"
              type="submit" 
              class="btn btn-primary"
              >Claim</button>
              <button v-if="key.valet !== 'Unclaimed'"
              @click="unclaimedKey(key.id, key.valet)"
              type="submit" 
              class="btn btn-primary"
              >Unclaim</button>
            <button class="btn btn-success" @click="complete(key.id)">Complete</button>
          </div>
      </div>
<!-- END OF CARD -->
<!-- START OF FORM -->
      <div class="row justify-content-md-center request">
        <div class="col-md-auto">
          <h1 class="display-4">Operation Tiger Teeth</h1>
          <form class="form-inline" @submit="newKey(service_tag, requestor_name, comments, model, year, color, valet, reqTimestamp)">
            <div class="form-group col-md-6">
              <label for="service_tag">Service Tag: </label>
              <input class="form-control form-control-lg" v-model="service_tag" placeholder="ex: TB1234">
            </div>
            <div class="form-group col-md-6">
              <label for="service_tag">Associates Name: </label>
              <!-- <input class="form-control form-control-lg" v-model="requestor_name" placeholder="Your name goes here..."> -->
              <div class="form-group">
                <label for="exampleFormControlSelect1">Example select</label>
                <select v-model="requestor_name" class="form-control" id="requestor_name">
                  <option>James Shiflett</option>
                  <option>Austin Hughes</option>
                </select>
              </div>
            </div>
            <div class="form-group col-md-6">
              <label for="service_tag">Model: </label>
              <input class="form-control form-control-lg" v-model="model" placeholder="What is the model of the vehicle?">
            </div>
            <div class="form-group col-md-6">
              <label for="service_tag">Color: </label>
              <input class="form-control form-control-lg" v-model="color" placeholder="What is the color of the vehicle?">
            </div>
            <div class="form-group col-md-6">
              <label for="service_tag">Year: </label>
              <input class="form-control form-control-lg" v-model="year" placeholder="What year is the car?">
            </div>
            <div class="form-group col-md-6">
              <label for="service_tag">Comments: </label>
              <input class="form-control form-control-lg" v-model="comments" placeholder="Place any additional comments here...">
            </div>
            <div class="form-group col-md-6 invisible">
              <label for="service_tag">Valet: </label>
              <input v-model="valet">
            </div>
            <div class="form-group col-md-6 invisible">
              <label for="service_tag">Timestamp: </label>
              <input v-model="reqTimestamp">
            </div>
            <div class="col-md-12">
              <button class="btn btn-outline-primary" type="submit">Request A Key</button>
            </div>
          </form>
        </div>
      </div>
    </div>
</template>

<script>
import { db } from "../main";
import { setInterval } from 'timers';
export default {
  name: "HelloWorld",
  data() {
    return {
      keys: [],
      reqTimestamp: this.newDate(),
      service_tag: "",
      requestor_name: "",
      comments: "",
      color: "",
      model: "",
      year: "",
      inputValet: true,
      valet: "Unclaimed",
      state: "started",
      startTime: '',
      currentTime: Date.now(),
      interval: null,
    };
  },
  firestore() {
    return {
      keys: db.collection("keyRequests").where("completion", "==", "Incomplete")
    };
  },
  methods: {
    newKey(service_tag, requestor_name, comments, model, year, color, valet, reqTimestamp, completion) {
      // <-- and here
      db.collection("keyRequests").add({
        service_tag,
        requestor_name,
        comments,
        color,
        model,
        year,
        valet,
        reqTimestamp,
        completion: "Incomplete",
      });
      this.service_tag = "";
      this.requestor_name = "";
      this.comments = "";
      this.color = "";
      this.model = "";
      this.year = "";
      this.reqTimestamp = this.newDate()
    },
      complete(id) {
        db.collection("keyRequests").doc(id).update({
          completion: "Complete"
        })
      },
    // deleteKey(id) {
    //   db.collection("keyRequests")
    //     .doc(id)
    //     .delete();
    claimedKey(id, valet) {
      console.log(id);
      this.inputValet = false
      db.collection("keyRequests").doc(id).update({
        valet: valet,
        claimTimestamp: new Date()
      })
    },
    moment: function () {
    return moment();
    },
    newDate () {
      var today = new Date()
      return today
    },
    updateCurrentTime: function() {
      if (this.$data.state == "started") {
          this.currentTime = Date.now();
        }
      },
      start(timestamp) {
        return this.startTime = timestamp.seconds * 1000
      }      
    },
  mounted: function () {
            this.interval = setInterval(this.updateCurrentTime, 1000);
  },
  destroyed: function() {
            clearInterval(this.interval)
  },
  computed: {
    time: function() {
      return Math.floor((this.currentTime - this.startTime) /60000);
    }
  }
  }
</script>

理想情况下,我正在寻找跟进每个请求的时间流逝。

所以模板中的问题行是:

<p class="card-text"> {{time}} {{key.reqTimestamp}}min</p>
<p class="invisible">{{ start(key.reqTimestamp) }}</p>

start的调用有side-effects,这是渲染组件的主要no-no。在这种情况下,它会更改 startTime 的值,进而导致 time 发生更改。我有点惊讶这没有触发无限渲染递归警告...

相反,我们应该只使用当前迭代项目的相关数据,您称之为 key。我会介绍一种计算经过时间的方法 key:

methods: {
  elapsedTime (key) {
    const timestamp = key.reqTimestamp;
    const startTime = timestamp.seconds * 1000;

    return Math.floor((this.currentTime - startTime) / 60000);
  }
}

您会注意到这结合了函数 starttime 的各个方面。重要的是它不会修改 this.

上的任何内容

然后您可以在您的模板中调用它:

<p class="card-text"> {{elapsedTime(key)}} {{key.reqTimestamp}}min</p>