HTML 数据列表在使用 Vue 动态加载时不断崩溃

HTML datalist keeps crashing when dynamically loaded with Vue

我正在使用 Vue.js 加载 HTML 数据列表。每当我在连接到我的数据列表的输入框中键入内容时,我的页面就会冻结(使用 Chrome)。我正在使用 jQuery 进行 AJAX 调用以在页面加载时最初获取我的所有用户,然后使用 JavaScript 过滤器函数创建一个具有 indexOf 在我的输入框中输入任何内容,然后将新过滤的对象数组放入数据列表元素中。

这是我的HTML:

<div id="my-app">
  <input list="user-search" type="text" id="find-user" name="find-user" v-model="findUser">
    <datalist id="user-search">
      <option v-for="user in findUserList">{{ user.vendorName }}</option>
    </datalist>
</div>

这是我的 Vue JavaScript:

var myApp = new Vue({
  el: '#my-app',
  data: {
    users: [],
    findUser: '',
    findUserList: '',
  },
  watch: {
    findUser: function(val) {
      this.findUserResults();
    }
  },
  methods: {
    findUserResults: function() {
      var lookFor = this.findUser.toLowerCase();
      this.findUserList = this.users.filter(function(user) {
        return (user.vendorName.toLowerCase().indexOf(myApp.findUser.toLowerCase()) > -1 || user.email.toLowerCase().indexOf(myApp.findUser.toLowerCase()) > -1);
      });
    },
    loadUsers: function() {
      $.ajax({
        method: 'GET',
        url: '/users',
        success: function(data) {
          myApp.users = JSON.parse(data);
        },
        error: function() {
                console.log('error...');
        }
      });
    }
  },
  mounted: function() {
    this.loadUsers();
  }
})

页面加载时用户加载正常。那里没有问题。我什至注释掉了 v-for 并且只是 console.log'' 过滤器的结果也没有问题。当我实现在 <datalist> 中动态添加 <option> 值时,问题就出现了。我试过将选项包装在 vue <template> 标签中并将 v-for 移到那里但没有成功。

我在另一个页面上运行良好,但我用 <tr><td> 填充 table 而不是 <datalist><option>.

什么可能导致我的页面崩溃? <datalist> 不足以处理所有这些吗?也许我遗漏了第二双眼睛可以帮助解决的问题。

编辑

填充到 users 中的数据如下所示(它是一个对象数组):

[{id:1, vendorName:'john'}, {id:2, vendorName:'Rachel', {id:3, vendorName:'Steve'}]

回答

这实际上只是某人(我)想太多的一个例子。 B.Fleming 关于递归的回答让我明白了为什么我的上述方法不正确。无需在用户每次键入时都重新加载数据列表选项。这正是 <datalist> 链接到 <input> 所做的;不需要 JavaScript。我需要(编辑)做的就是在页面加载时(或每当我希望显示输入和数据列表时)将所有 ~3,000 个用户加载到 <datalist> 标记中作为 <option>s,然后让数据列表和输入处理其余部分。我没有用上面示例中的应用程序对此进行测试,因为我不在那台计算机附近,但作为数据列表可以处理数千个选项元素的概念证明,我在本地编写了这个 运行没有问题(不确定为什么代码段控制台在工作时一直说有错误):

window.onload = function() {
    var datalistElement = document.getElementById('datalist-test');
    var datalistString = '';
    for (var i = 0; i < 3000; i++) {
        datalistString += '<option>' + Math.random().toString(36).substring(7); + '</option>';
    }
    datalistElement.innerHTML = datalistString;
}
<!DOCTYPE html>
<html>
<head>
 <title>Datalist Test</title>
</head>

<body>
 <input list="datalist-test" type="text">
 <datalist id="datalist-test">
 </datalist>
</body>
</html>

3,000 个数据列表选项元素,没问题。

你有无限递归调用。您在 entering/deleting 搜索文本上调用 myApp.findUser(),它调用 myApp.findUserResults(),它调用 myApp.findUser(),等等。您需要解决这个问题。

要解决此问题,您只需将所有用户加载到数据列表选项中一次。然后,让输入框和数据列表处理剩下的事情。无需在用户每次键入时都重新加载数据列表选项。

通常您会为此使用 computed property。我还做了一些其他的改变。首先,从内部引用 Vue 本身是一种不好的做法;只需使用 this。数据列表选项也有一个您需要指定的值 属性。

console.clear()

const users = [
  {vendorName: "Vendor One", email: "bob@example.com"},
  {vendorName: "Vendor Two", email: "mary@example.com"},
  {vendorName: "Vendor Three", email: "jim@example.com"},
  {vendorName: "Vendor Four", email: "joe@vendor.com"},
  {vendorName: "Vendor Five", email: "sara@vendor.com"},
  
]
var myApp = new Vue({
  el: '#my-app',
  data: {
    users: [],
    findUser: '',
  },
  computed:{
    vendors(){
      return this.users.filter(u => {
        return u.vendorName.toLowerCase().indexOf(this.findUser) > -1 ||
          u.email.toLowerCase().indexOf(this.findUser) > -1
      })
    }
  },
  methods: {
    loadUsers: function() {
      // obviously, this is different for example purposes
      this.users = users
    }
  },
  mounted: function() {
    this.loadUsers();
  }
})
<script src="https://unpkg.com/vue@2.4.2"></script>
<div id="my-app">
  <h3>Type "V"</h3>
  <input list="user-search" name="find-user" v-model="findUser">
  <datalist id="user-search">
    <option v-for="user in vendors" :value="user.vendorName">
  </datalist>
</div>