数据更改时Vue.js列表未更新

时间:2018-11-02 10:07:24

标签: vue.js

我正在尝试重新整理数据列表。我给了每个li一个唯一的密钥,但是仍然没有运气!

我以前完全按照下面的方法进行过这项工作,认为我正在努力!

let app = new Vue({
  el: '#app',
  data: {
    list: [
      { value: 'item 1', id: '43234r' },
      { value: 'item 2', id: '32rsdf' },
      { value: 'item 3', id: 'fdsfsdf' },
      { value: 'item 4', id: 'sdfg543' }
    ]
  },
  methods: {
    randomise: function() {
      let input = this.list;
     
      for (let i = input.length-1; i >=0; i--) {

          let randomIndex = Math.floor(Math.random()*(i+1)); 
          let itemAtIndex = input[randomIndex]; 

          input[randomIndex] = input[i]; 
          input[i] = itemAtIndex;
      }
      this.list = input;
     
    }
  }
});
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<div id="app">
  
  <ul>
    <li v-for="item in list" :key="item.id">{{ item.value }}</li>
  </ul>
  <a href="javascript:void(0)" v-on:click="randomise()">Randomize</a>
  
</div>

编辑:

感谢您的回答,说实话,我提供的示例可能并不是我要解决的实际问题的最佳选择。我想我可能已经找到了造成此问题的原因。

我基本上使用与上述类似的逻辑,除了我基于拖放来移动对象数组,这对于普通HTML来说效果很好。

但是,我在其他地方使用了拖放组件,其中包含另一个组件,这似乎使事情分崩离析...

在将一个项目移动到其数据中时,是否在另一个组件中包含一个组件会阻止Vue重新呈现?

下面是我的DraggableBase组件,我从其扩展为:

<script>
    export default {
        data: function() {
            return {
                dragStartClass: 'drag-start',
                dragEnterClass: 'drag-enter',
                activeIndex: null
            }
        },
        methods: {

            setClass: function(dragStatus) {
                switch (dragStatus) {
                    case 0:
                        return null;
                    case 1:
                        return this.dragStartClass;
                    case 2:
                        return this.dragEnterClass;
                    case 3:
                        return this.dragStartClass + ' ' + this.dragEnterClass;
                }
            },
            onDragStart: function(event, index) {

                event.stopPropagation();

                this.activeIndex = index;
                this.data.data[index].dragCurrent = true;

                this.data.data[index].dragStatus = 3;

            },
            onDragLeave: function(event, index) {

                this.data.data[index].counter--;

                if (this.data.data[index].counter !== 0) return;

                if (this.data.data[index].dragStatus === 3) {
                    this.data.data[index].dragStatus = 1;
                    return;
                }
                this.data.data[index].dragStatus = 0;
            },
            onDragEnter: function(event, index) {

                this.data.data[index].counter++;

                if (this.data.data[index].dragCurrent) {
                    this.data.data[index].dragStatus = 3;
                    return;
                }
                this.data.data[index].dragStatus = 2;
            },
            onDragOver: function(event, index) {
                if (event.preventDefault) {
                    event.preventDefault();
                }
                event.dataTransfer.dropEffect = 'move';
                return false;
            },
            onDragEnd: function(event, index) {
                this.data.data[index].dragStatus = 0;
                this.data.data[index].dragCurrent = false;
            },
            onDrop: function(event, index) {

                if (event.stopPropagation) {
                    event.stopPropagation();
                }

                if (this.activeIndex !== index) {
                    this.data.data = this.array_move(this.data.data, this.activeIndex, index);
                }

                for (let index in this.data.data) {
                    if (!this.data.data.hasOwnProperty(index)) continue;
                    this.data.data[index].dragStatus = 0;
                    this.data.data[index].counter = 0;
                    this.data.data[index].dragCurrent = false;
                }

                return false;
            },
            array_move: function(arr, old_index, new_index) {
                if (new_index >= arr.length) {
                    let k = new_index - arr.length + 1;
                    while (k--) {
                        arr.push(undefined);
                    }
                }
                arr.splice(new_index, 0, arr.splice(old_index, 1)[0]);
                return arr; // for testing
            }
        }
    }
</script>

编辑2

想通了!以前使用循环索引可以很好地工作,但是这次似乎并非如此!

我将v-bind:key更改为使用数据库ID,这解决了该问题!

4 个答案:

答案 0 :(得分:2)

有些Caveats带有数组

  

由于JavaScript的限制,Vue无法检测到对数组的以下更改:

     
      
  • 直接用索引设置项目时,例如vm.items[indexOfItem] = newValue

  •   
  • 当您修改数组的长度时,例如vm.items.length = newLength

  •   

  

要克服第1条警告,以下两项将与vm.items[indexOfItem] = newValue相同,但也会在反应性系统中触发状态更新:

Vue.set(vm.items, indexOfItem, newValue)

或者您的情况

randomise: function() {
      let input = this.list;

      for (let i = input.length-1; i >=0; i--) {

          let randomIndex = Math.floor(Math.random()*(i+1)); 
          let itemAtIndex = input[randomIndex]; 

          Vue.set(input, randomIndex, input[i]); 
          Vue.set(input, i, itemAtIndex);
      }
      this.list = input;

    }

答案 1 :(得分:1)

这是一个有效的示例:Randomize items fiddle

基本上,我将您的randomize函数的逻辑更改为:

randomize() {
  let new_list = []
  const old_list = [...this.list] //we don't need to copy, but just to be sure for any future update

  while (new_list.length < 4) {
    const new_item = old_list[this.get_random_number()]
    const exists = new_list.findIndex(item => item.id === new_item.id)
    if (!~exists) { //if the new item does not exists in the new randomize list add it
      new_list.push(new_item)
    }
  }
  this.list = new_list //update the old list with the new one   
},
get_random_number() { //returns a random number from 0 to 3
    return Math.floor(Math.random() * 4)
}

答案 2 :(得分:0)

from flask import Flask, render_template
import os
from flask import redirect, url_for, request
from flask_sqlalchemy import SQLAlchemy
import sys
import sqlite3
import datetime
from datetime import date
import csv

app = Flask(__name__)

@app.route("/", methods=["GET", "POST"])
def log():
    names = os.getlogin().split(".")[0].title()
    error= None
    if request.method == "POST":
        if request.form["username"]!= os.getlogin() or request.form["password"]!="1234":
            error = "Invalid Credentials.Please Try again."
        else:
            return redirect(url_for("welcome"))
    return render_template("login.html", error=error, name=names)

@app.route("/welcome",methods=["GET","POST"])
def welcome():
    return render_template("welcome.html")

@app.route("/paymentplan",methods=["GET","POST"])
def paymentplan():
    conn = sqlite3.connect("payment_tco.db")
    fdate = date.today()
    if request.method=="POST":
        rxidnumber = request.form["xidnumber"]#
        #mytext = request.form["mytexta[]"]# unable to get the value of mytext[]
    return render_template("payment.html")

@app.route("/tco",methods=["GET","POST"])
def tco():
    return render_template("tco.html")

app.run(debug=True)
  

在Vue中,数组更改检测有些棘手。大部分就位   数组方法按预期工作(即在您的计算机中进行拼接)   $ data.names数组可以使用),但直接关联值(即   $ data.names [0] ='Joe')不会更新反应式渲染   组件。根据您处理服务器端结果的方式,   可能需要考虑本文所述的这些选项   文档:阵列更改检测。

     

一些需要探索的想法:

     

使用v-bind:key =“ some_id”更好地使用推送添加   使用Vue.set(example1.items,indexOfItem,newValue)的新元素   (Artokun也提到过)

Source

请注意,它可以工作,但是我很忙,所以我无法对其进行优化,但是它有点太复杂了,我明天再编辑。

答案 3 :(得分:0)

由于Vue.js具有caveats个检测数组修改的功能,可以作为对该问题突出显示的其他答案,因此您可以在随机化数组之前对其进行浅表复制:

randomise: function() {
  // make shallow copy
  let input = this.list.map(function(item) {
     return item;
  });

  for (let i = input.length-1; i >=0; i--) {

      let randomIndex = Math.floor(Math.random()*(i+1)); 
      let itemAtIndex = input[randomIndex]; 

      input[randomIndex] = input[i]; 
      input[i] = itemAtIndex;
  }

  this.list = input;

}