【问题标题】:Use HTML5 (datalist) autocomplete with 'contains' approach, not just 'starts with'使用带有“包含”方法的 HTML5(数据列表)自动完成,而不仅仅是“开始于”
【发布时间】:2015-03-19 20:58:13
【问题描述】:

(我找不到它,但是我真的不知道如何搜索它。)

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

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

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

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

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

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

【问题讨论】:

  • 没有帮助?难以置信……这是我需要使用数据列表时首先想到的。
  • 问题是,数据列表不可编辑,至少在ie11中是这样。我得到这个错误:0x800a13b5 - JavaScript runtime error: Assignment to read-only properties is not allowed in strict mode.
  • @NinaScholz 你什么时候收到这个错误?分配什么给什么?你会做一个小提琴吗?
  • 我采用了innerHTML 的方法。行得通。
  • 当前版本的 Chrome 浏览器 (56) 已经将行为更改为“子字符串匹配”以适应当前规范和 Firefox 的行为。 (我没有测试过旧版本,但似乎这个变化是最近的)

标签: html autocomplete html-datalist


【解决方案1】:

“包含”方法

也许这就是你要找的东西(你的问题的第 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 but submit the actual value

   '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>

【讨论】:

  • 这很聪明!它有效,但它看起来像这样:screencast.com/t/igeQtYJ2 这并不漂亮,尤其是像“ameri”这样的搜索。这是自动完成功能 IMO 中的一个巨大缺陷。我们花时间在更好的 3D 动画上,但没有改进这样的功能 =(
  • 您使用哪种浏览器?
  • Windows 上的 Chrome。在金丝雀也是一样。 Firefox 看起来更好,但 Firefox 已经使用了“包含”方法。
  • 第一种方法:Chrome 56 中未显示工具提示:r,左箭头,e。解决方法:input.value = anyFooResetsCursor; window.setTimeout(() =&gt; this.setSelectionRange(oldStart + FooLen - oldLen, oldEnd + FooLen - oldLen), 0);。如果愿意,我猜超时可能会更改为 onkeyup。
  • @NinaScholz 注意,第一次接近Uncaught TypeError: Cannot read property 'value' of undefinedUncaught TypeError: Cannot read property 'lastValue' of undefined 记录在console
【解决方案2】:

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

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

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

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

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

【讨论】:

  • 是的,确实如此,但如果我能控制它,我仍然会喜欢它。我的下一个自动完成可能必须是“开始于”,但没有办法覆盖自动完成功能。真可惜。
  • 这个答案太短了......请同时反映关于自动填充的部分:w3.org/TR/html/sec-forms.html#autofill(特别是该属性所穿的披风如果省略autocomplete属性,还有“expectation mantle”和“anchor mantle”之间的区别)——不要错过这个:w3.org/TR/html/…
  • @yckart autocomplete 属性只是另一个故事。与这个问题 IMO 无关。如果您愿意,您可能想发布另一个答案或另一个问题。
【解决方案3】:

这个fiddle here 破解了你的要求 但我不确定如何在没有这种依赖关系的情况下使其工作,因为与 Bootstrap 一起使用时 UI 看起来有点奇怪和不合适。

 elem.autocomplete({
    source: list.children().map(function() {
        return $(this).text();
    }).get()

【讨论】:

  • 这使用了 jQuery UI 的autocomplete。根本不使用本机自动完成功能。我希望 2016 年的自动完成功能会更好 =(
  • 在 Bootstrap 3 页面中使用时这对我来说很有趣
【解决方案4】:

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

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;
  }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-11-19
    • 2020-03-15
    • 1970-01-01
    • 1970-01-01
    • 2015-06-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多