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>
我正在使用 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>