使用带有'包含'的HTML5(datalist)自动完成功能。方法,而不仅仅是'从'开始。

时间:2015-03-19 20:58:14

标签: html5 autocomplete html-datalist

(我无法找到它,但我又不知道如何搜索它。)

我想使用<input list=xxx><datalist id=xxx>来获取自动完成功能,但我希望浏览器能够匹配所有选项,包含&#39;方法,而不是以&#39;开始,这似乎是标准的。有办法吗?

如果不是简单,有没有办法强制显示我想要显示的建议,而不是浏览器匹配的建议?让我们说我打字&#34; foo&#34;我想展示选项&#34; bar&#34;和&#34; baz&#34;。我可以强迫用户使用吗?如果我只是用那些(用JS)填充datalist,浏览器仍然会以&#39;开头。检查并过滤掉它们。

我希望最终控制数据主义选项如何显示。不要超过它的UI,灵活性,可访问性等,所以我不想完全重新制作它。甚至不建议使用jQuery插件。

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

编辑:我现在看到Firefox确实使用了&#39;包含&#39;方法......那甚至不是标准?有什么方法可以强迫这个?我可以改变Firefox的方式吗?

编辑:我这样做是为了说明我的喜好:http://jsfiddle.net/rudiedirkx/r3jbfpxw/

4 个答案:

答案 0 :(得分:14)

'包含'方法

也许这就是你要找的东西(问题的第一部分)。

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

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

答案 1 :(得分:3)

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

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

  

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

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

这意味着操作系统现在应该正常工作。

答案 2 :(得分:1)

fiddle here已经破解了你要求的东西 但我不知道如何在没有这种依赖性的情况下使其工作,因为当与Bootstrap一起使用时,UI看起来有点奇怪而且不合适。

(* an infinite stream of natural numbers, starting from 0 *)
let nats =
  let rec nats_from n = [< 'n; nats_from (n + 1) >]  (* extra syntax *)
  in nats_from 0

(* the first n natural numbers: [0; n-1] *)
let range n = Stream.npeek n nats

答案 3 :(得分:0)

我找到了这个问题,是因为我想要“以……开头”的行为,现在所有的浏览器似乎都实现了“包含”。因此,我实现了此功能,在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;
  }
}