用纯JavaScript实现一个自动完成下拉框

4
这是我的HTML代码。
<h2>Please Enter the Value in the Box(click on the desired value)</h2>
<input id='value' type="text" autocomplete="on" placeholder="country" />
<div id="dropdown">
    <select name="list" id="list"></select>
</div>

这是我的JavaScript代码。
var arr = ["Afghanistan","Albania","Algeria","Andorra","Angola","Anguilla","Antigua &amp; Barbuda","Argentina","Armenia","Aruba","Australia","Austria","Azerbaijan","Bahamas","Bahrain","Bangladesh","Barbados","Belarus","Belgium","Belize","Benin","Bermuda","Bhutan","Bolivia","Bosnia &amp; Herzegovina","Botswana","Brazil","British Virgin Islands","Brunei","Bulgaria","Burkina Faso","Burundi","Cambodia","Cameroon","Cape Verde","Cayman Islands","Chad","Chile","China","Colombia","Congo","Cook Islands","Costa Rica","Cote D Ivoire","Croatia","Cruise Ship","Cuba","Cyprus","Czech Republic","Denmark","Djibouti","Dominica","Dominican Republic","Ecuador","Egypt","El Salvador","Equatorial Guinea","Estonia","Ethiopia","Falkland Islands","Faroe Islands","Fiji","Finland","France","French Polynesia","French West Indies","Gabon","Gambia","Georgia","Germany","Ghana","Gibraltar","Greece","Greenland","Grenada","Guam","Guatemala","Guernsey","Guinea","Guinea Bissau","Guyana","Haiti","Honduras","Hong Kong","Hungary","Iceland","India","Indonesia","Iran","Iraq","Ireland","Isle of Man","Israel","Italy","Jamaica","Japan","Jersey","Jordan","Kazakhstan","Kenya","Kuwait","Kyrgyz Republic","Laos","Latvia","Lebanon","Lesotho","Liberia","Libya","Liechtenstein","Lithuania","Luxembourg","Macau","Macedonia","Madagascar","Malawi","Malaysia","Maldives","Mali","Malta","Mauritania","Mauritius","Mexico","Moldova","Monaco","Mongolia","Montenegro","Montserrat","Morocco","Mozambique","Namibia","Nepal","Netherlands","Netherlands Antilles","New Caledonia","New Zealand","Nicaragua","Niger","Nigeria","Norway","Oman","Pakistan","Palestine","Panama","Papua New Guinea","Paraguay","Peru","Philippines","Poland","Portugal","Puerto Rico","Qatar","Reunion","Romania","Russia","Rwanda","Saint Pierre &amp; Miquelon","Samoa","San Marino","Satellite","Saudi Arabia","Senegal","Serbia","Seychelles","Sierra Leone","Singapore","Slovakia","Slovenia","South Africa","South Korea","Spain","Sri Lanka","St Kitts &amp; Nevis","St Lucia","St Vincent","St. Lucia","Sudan","Suriname","Swaziland","Sweden","Switzerland","Syria","Taiwan","Tajikistan","Tanzania","Thailand","Timor L'Este","Togo","Tonga","Trinidad &amp; Tobago","Tunisia","Turkey","Turkmenistan","Turks &amp; Caicos","Uganda","Ukraine","United Arab Emirates","United Kingdom","Uruguay","Uzbekistan","Venezuela","Vietnam","Virgin Islands (US)","Yemen","Zambia","Zimbabwe"];
var input = document.getElementById('value');
var optionsVal = document.getElementById('list');

input.addEventListener('keyup', show);
optionsVal.onclick = function(){
    setVal(this);
};

//shows the list
function show(){
    var dropdown = document.getElementById('dropdown');
    dropdown.style.display = 'none';

    optionsVal.options.length = 0;

    if(input.value){
        dropdown.style.display = 'block';
        optionsVal.size = 3;
        var textCountry = input.value;

        for(var i = 0; i < arr.length; i++){
            if(arr[i].indexOf(textCountry) !== -1){
                //addvalue
                addValue(arr[i],arr[i]);

            }
        }

    }
}

function addValue(text,val){
    var createOptions = document.createElement('option');
    optionsVal.appendChild(createOptions);
    createOptions.text = text;
    createOptions.value = val;
}

//Settin the value in the box by firing the click event
function setVal(selectedVal){
    input.value = selectedVal.value;
    document.getElementById('dropdown').style.display='none';
}

我遇到的问题涉及检查输入值并在下拉列表中显示值时所涉及的逻辑。例如,如果我键入“u”,则只会显示“安圭拉,安提瓜”等国家,而不是任何带有“u”的国家。我知道问题出在indexOf检查上,但我卡在这里。
此外,我该如何使下拉列表的大小动态适应所找到的值?您的反馈对改进整个问题也将非常有帮助。

你能附上一个 jsFiddle 吗? - AhmadAssaf
对我来说,下拉菜单中包含了所有预期的国家。 - Dr.Molle
JSFiddle http://jsfiddle.net/e6220t92/ - Raj
1
Fiddle 在 IE11 中似乎运行良好。 - Mouser
1
当最终目标是自动完成而不是通过JS实现时,您可以查看datalist(仅HTML解决方案)。 - Dr.Molle
@Dr.Molle 是的,我本来会使用 jQuery 小部件或数据列表,就像你提到的那样,但是我想看看在没有外部库的情况下实现它需要什么。 - Raj
2个回答

3

为什么不使用match而不是indexOf?使用match的好处是可以进行大小写不敏感的搜索。 http://jsfiddle.net/e6220t92/2/。这个Fiddle还尝试增加选择框的大小。

    //CODE
    var testableRegExp = new RegExp(RegExp.escape(textCountry),"i");
    if (arr[i].match(testableRegExp ) )
    {
       //logic
    }
    //CODE

//Use this function to replace potential characters that could break the regex
RegExp.escape= function(s) {
    return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
};

谢谢回复,你说得对,匹配是更好的解决方案。 - Raj
2
虽然这是一个老问题,但推荐使用正则表达式并不是最佳策略。使用 .toLowerCase().indexOf() 的组合比 .match(/.../i) 快几个数量级:https://jsbench.me/grjq2l4vhr/1 - Sébastien Vercammen
这取决于列表的长度,不是吗?JS Fiddle似乎非常快。 - Scott

1
问题在于,您需要在筛选输入元素后调整选项列表的大小。
您可以通过删除以下行来实现此操作:
optionsVal.size = 3;

将过滤选项的for循环更改为添加一个与过滤结果相同大小的调整大小:

for(var i = 0; i < arr.length; i++){
    if(arr[i].indexOf(textCountry) !== -1){
        //addvalue
        addValue(arr[i],arr[i]);
        optionsVal.size = optionsVal.options.length;
    }
}

我觉得如果没有选项,这会显得有点丑陋,而当你输入像“a”这样的字符时,它会变得非常长,但我认为这就是你想要的。

更改后的show()函数:

//shows the list
function show(){
    var dropdown = document.getElementById('dropdown');
    dropdown.style.display = 'none';

optionsVal.options.length = 0;

if(input.value){
    dropdown.style.display = 'block';
    var textCountry = input.value;

    for(var i = 0; i < arr.length; i++){
        if(arr[i].indexOf(textCountry) !== -1){
            //addvalue
            addValue(arr[i],arr[i]);
            optionsVal.size = optionsVal.options.length;
        }
    }

    }
}

谢谢,调用函数后添加大小是有意义的。 - Raj

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