使用Javascript更快地填充<select>的方法

15

我在表单中有两个 <select>选择框。选择第一个 <select>框中的项目将确定第二个 <select>中应该出现什么内容(使用Ajax http_request)。

在某些情况下,第二个选择框中可能有大约500个项目(猜测),在IE中更新需要5-10秒的时间。Firefox似乎完美运行。

我想知道是否有更快的方法来实现这一点。目前,服务器创建一个字符串,将其传递给客户端,然后通过创建选项元素并将其添加到 <select> 中来将其拆分并添加每个项目。

我尝试在服务器上将整个选择项作为字符串创建并添加到表单中,但由于某种原因它在Firefox中无法工作(是否漏掉了什么?)

谢谢

10个回答

20

即使对于IE,500个元素也不算很多。你一定是做了其他的事情导致了滞后。

我在IE6、IE7、FF2和FF3中尝试了500个以上的选项,所有选项都几乎瞬间完成。 我使用了这段代码:

var data = [
    { text: 'foo', value: 'bar' },
    // ...
    { text: 'foo', value: 'bar' }
];

var select = document.getElementsByTagName('select')[0];
select.options.length = 0; // clear out existing items
for(var i=0; i < data.length; i++) {
    var d = data[i];
    select.options.add(new Option(d.text, i))
}

我建议对获取数据并填充下拉框的代码进行剖析。可能还有其他原因导致了延迟。例如,请检查“分解”从服务器返回的字符串值的代码是否高效(听起来你正在使用自定义解析)。


5
嗯...应该是 select.options.add(new Option(d.text, d.value)),对吗? - tzot

4
第一段代码没问题,但对我来说这样更好:
var data = [
    { text: 'uno', value: '1' },
    {text: 'dos', value: '2' }
];

var select = document.getElementById('select-choice-1');
select.options.length = 0; // clear out existing items
for (var i = 0; i < data.length; i++) {
    var d = data[i];
    select.options.add(new Option(d.text, d.value))
}

2
使用SelectElement.innerHTML设置它会是最快的方法...但在IE中会失败
据我所知,在IE中,如果您将所有选项包装在虚假的<div>标记中或者设置整个选择列表的.outerHTML,就可以实现此操作。

2
所有使用SelectElement.innerHTML的答案的问题在于你无法在SELECT中做到这一点。解决方案是在SELECT元素本身的父级上使用innerHTML。因此,在您的ajax/jquery/whatever代码中创建一个包含所有SELECT HTML的字符串,然后获取容器(div或span或其他),并将innerHTML设置为您构造的字符串。
为了防止销毁/重建SELECT元素时其他HTML元素成为受害者,您需要将SELECT从页面中隔离出来,并为其指定显式父元素(span或div)。
简短回答:
parentselectelement.removeChild(selectelement);
parentselectelement.innerHTML = "<select ...><options...></select>";

1

我会在服务器上创建整个select并将其注入页面中。这种方法可以避免烦人的浏览器差异,并减少客户端代码的复杂性。

你提到过你尝试过这种方法,但在火狐浏览器中失败了。我建议坚持努力让它工作起来,在另一个问题中寻求帮助,或编辑你的问题向我们展示你在火狐浏览器中无法运行的内容。


1
不要忘记先将内容添加到document.createDocumentFragment(),再将其添加到SELECT中。

0

当我使用第一个版本时,它可以工作,但更新第二个选择框可能会非常慢

<html>
<form id='myform' method='post' action='$_SERVER[PHP_SELF]'>
<table>
<tr><td><select onselect='CALL_AJAX_AND_UPDATE();'></select></td></tr>
<tr><td><select id='selectid'></select></td></tr>
</table>
</form>
</html>
<script type=\"text/javascript\"> function UPDATE( updatedata ) { var itemid = document.getElementById('selectid');
var data = updatedata.split( '|' ); var len = data.length;
for( i=0; i < len; i ++ ) { var opt = document.createElement('option'); opt.text = data[i];
try { itemid.add( opt, null ); } catch(ex) { itemid.add( opt ); } } } </script>

这个版本在IE中可以工作,但是Firefox似乎没有提交第二个选择器的数据。我有什么遗漏吗?

<html>
<form id='myform' method='post' action='$_SERVER[PHP_SELF]'>
<table>
<tr><td><select onselect='CALL_AJAX_AND_UPDATE();'></select></td></tr>
<tr><td><div id='addselect'></div></td></tr>
</table>
</form>
</html>
<script type=\"text/javascript\"> function UPDATE( updatedata ) { // 更新数据是完整的选择器HTML var itemid = document.getElementById('addselect'); itemid.innerHTML = updatedata; } </script>

0

看到你的代码会非常有帮助。

如果你正在创建一个<option>元素,并且每次迭代都将其附加,那么你应该考虑一次性创建所有的<option>元素,然后一次性附加它们。

因此(伪代码):

// Don't do this:
for choice in choices:
    option = new Options(choice)
    select.append(option)


// Do this instead
var options = array()

for choice in choices:
   options.append( new Options(choice) )

for option in options:
   select.append(option)

// Or you might try building the select element off-screen and then appending to the DOM
var options = array()
var select = new SelectElement()

for choice in choices:
   select.append( new Options(choice) )

dom_element.append(select)

使用数组有什么好处呢?你仍然需要调用{n}个附加到选择列表中(这就是导致速度问题的原因,因为浏览器需要在每次附加后确定是否需要更新列表大小)。 - scunliffe
@scunliffe - 浏览器优化很少涉及到大O复杂度分析。我猜测这里的问题是,如果所有新的Option元素都一次性附加到DOM上,IE可能会延迟将它们呈现到屏幕上,这应该可以加快速度。这只是一个尝试。 - Kenan Banks

0

我喜欢Crescent Fresh和Kemal Fadillah的答案,因为两者都使用了:

select.options.add(new Options(name, value))

关于数据对象,我建议进行以下小调整:

var data = {
  'uno': 1,
  'dos': 2
};

var select = document.getElementById('select-choice-1');
select.options.length = 0; // clear out existing items
for (var i in data) {
      select.options.add(new Option(i, data[i]));
}

0
如果您不介意使用CoffeeScript,那么以下代码可以用几行来填充一个选择列表中的JSON数据。
HTML
<select id="clients"></select>

CoffeeScript

fillList=($list, url)=>
    $.getJSON(url)
    .success((data)->
        $list
        .empty()
        .append("<option value=\"#{item.Id}\">#{item.Name}</option>" for item in data)
    )

$ -> 
    fillList($('#clients'), '/clients/all')

注意:在append中的循环调用append方法之前生成整个HTML字符串。这样做非常高效。

JSON示例

[
  {"Id":"1","Name":"Client-1"},
  {"Id":"2","Name":"Client-2"}
]

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接