37

(我找不到它,但话说回来我真的不知道如何搜索它。)

我想使用<input list=xxx><datalist id=xxx>获得自动完成功能,但我希望浏览器通过“包含”方法匹配所有选项,而不是“开始于”,这似乎是标准的。有办法吗?

如果不是简单的,有没有办法强制显示我想要显示的建议,而不是浏览器匹配的建议?假设我正在输入“foo”并且我想显示选项“bar”和“baz”。我可以将这些强加给用户吗?如果我只是用那些(使用 JS)填充数据列表,浏览器仍然会进行“开始于”检查,并将它们过滤掉。

我希望最终控制数据列表选项的显示方式。不是因为它的用户界面、灵活性、可访问性等,所以我不想完全改造它。甚至不建议使用 jQuery 插件。

如果我可以最终控制表单元素验证,为什么不能自动完成,对吧?

编辑:我现在看到 Firefox 确实使用“包含”方法......这甚至不是标准?有什么办法可以强制吗?我可以改变 Firefox 的方式吗?

编辑:我做了这个来说明我想要什么:http: //jsfiddle.net/rudiedirkx/r3jbfpxw/

4

4 回答 4

16

“包含”方法

也许这就是您正在寻找的(问题的第 1 部分)。

它具有“开始于”的限制,并在进行选择时发生变化。

'use strict';
function updateList(that) {
    if (!that) {
        return;
    }
    var lastValue = that.lastValue,
        value = that.value,
        array = [],
        pos = value.indexOf('|'),
        start = that.selectionStart,
        end = that.selectionEnd,
        options;

    if (that.options) {
        options = that.options;
    } else {
        options = Object.keys(that.list.options).map(function (option) {
            return that.list.options[option].value;
        });
        that.options = options;
    }

    if (lastValue !== value) {
        that.list.innerHTML = options.filter(function (a) {
            return ~a.toLowerCase().indexOf(value.toLowerCase());
        }).map(function (a) {
            return '<option value="' + value + '|' + a + '">' + a + '</option>';
        }).join();
        updateInput(that);
        that.lastValue = value;
    }
}

function updateInput(that) {
    if (!that) {
        return;
    }
    var value = that.value,
        pos = value.indexOf('|'),
        start = that.selectionStart,
        end = that.selectionEnd;

    if (~pos) {
        value = value.slice(pos + 1);
    }
    that.value = value;
    that.setSelectionRange(start, end);
}

document.getElementsByTagName('input').browser.addEventListener('keyup', function (e) {
    updateList(this);
});
document.getElementsByTagName('input').browser.addEventListener('input', function (e) {
    updateInput(this);
});
<input list="browsers" name="browser" id="browser" onkeyup="updateList();" oninput="updateInput();">
<datalist id="browsers">
    <option value="Internet Explorer">
    <option value="Firefox">
    <option value="Chrome">
    <option value="Opera">
    <option value="Safari">
</datalist>

编辑

显示搜索内容的不同方法,以明确发生了什么。这也适用于 Chrome。灵感来自Show datalist labels 但提交实际值

   'use strict';
var datalist = {
        r: ['ralph', 'ronny', 'rudie'],
        ru: ['rudie', 'rutte', 'rudiedirkx'],
        rud: ['rudie', 'rudiedirkx'],
        rudi: ['rudie'],
        rudo: ['rudolf'],
        foo: [
            { value: 42, text: 'The answer' },
            { value: 1337, text: 'Elite' },
            { value: 69, text: 'Dirty' },
            { value: 3.14, text: 'Pi' }
        ]
    },
    SEPARATOR = ' > ';

function updateList(that) {
    var lastValue = that.lastValue,
        value = that.value,
        array,
        key,
        pos = value.indexOf('|'),
        start = that.selectionStart,
        end = that.selectionEnd;

    if (lastValue !== value) {
        if (value !== '') {
            if (value in datalist) {
                key = value;
            } else {
                Object.keys(datalist).some(function (a) {
                    return ~a.toLowerCase().indexOf(value.toLowerCase()) && (key = a);
                });
            }
        }
        that.list.innerHTML = key ? datalist[key].map(function (a) {
            return '<option data-value="' + (a.value || a) + '">' + value + (value === key ? '' : SEPARATOR + key) + SEPARATOR + (a.text || a) + '</option>';
        }).join() : '';
        updateInput(that);
        that.lastValue = value;
    }
}

function updateInput(that) {
    var value = that.value,
        pos = value.lastIndexOf(SEPARATOR),
        start = that.selectionStart,
        end = that.selectionEnd;

    if (~pos) {
        value = value.slice(pos + SEPARATOR.length);
    }
    Object.keys(that.list.options).some(function (option) {
        var o = that.list.options[option],
            p = o.text.lastIndexOf(SEPARATOR);
        if (o.text.slice(p + SEPARATOR.length) === value) {
            value = o.getAttribute('data-value');
            return true;
        }
    });
    that.value = value;
    that.setSelectionRange(start, end);
}

document.getElementsByTagName('input').xx.addEventListener('keyup', function (e) {
    updateList(this);
});
document.getElementsByTagName('input').xx.addEventListener('input', function (e) {
    updateInput(this);
});
<input list="xxx" name="xx" id="xx">
<datalist id="xxx" type="text"></datalist>

于 2015-09-04T09:06:06.910 回答
4

然而这个线程是在大约 2 年前发布的。但是如果你正在阅读这个帖子,你可能需要检查你的浏览器的更新版本:

当前规范:https ://html.spec.whatwg.org/multipage/forms.html#the-list-attribute

当建议的数量很大时,鼓励用户代理过滤由建议源元素表示的建议,仅包括最相关的建议(例如,基于到目前为止的用户输入)。没有定义精确的阈值,但将列表限制在四到七个值是合理的。如果基于用户的输入进行过滤,用户代理应该对建议的标签和值使用子字符串匹配

在撰写这篇文章时,Firefox (51) 和 Chrome (56) 的行为已经更改以符合规范。

这意味着 op 想要的东西现在应该可以工作了。

于 2017-02-17T06:17:53.150 回答
0

这个小提琴在这里破解了你的要求但是我不确定如何在没有这种依赖的情况下让它工作,因为当与 Bootstrap 一起使用时,UI 看起来有点奇怪和不合适。

 elem.autocomplete({
    source: list.children().map(function() {
        return $(this).text();
    }).get()
于 2016-04-20T09:37:26.797 回答
0

我发现这个问题是因为我想要“开始于”行为,现在所有的浏览器似乎都实现了“包含”。所以我实现了这个函数,如果从输入事件处理程序(以及可选的从 focusin 事件处理程序)调用,它在 Firefox(可能还有其他)上提供“开始于”行为。

let wrdlimit = prefix =>
{ let elm = mydatalist.firstElementChild;
  while( elm )
  { if( elm.value.startsWith( prefix ))
    { elm.removeAttribute('disabled');
    } else
    { elm.setAttribute('disabled', true );
    }
    elm = elm.nextElementSibling;
  }
}
于 2020-02-29T04:24:01.197 回答