BootstrapTagsInput是一个基于jQuery和Bootstrap.css的用于管理标签的插件。javascript
官网在这:官网php
这个官网呢,怎么说呢,比较简洁。示例聊胜于无。css
最简单的用法就是在引入jquery,和Bootstrap的前提下,在input标签中添加 data-role="tagsinput",便可初始化。html
<input type="text" value="" data-role="tagsinput" />
缘由在于下方代码,代码最后一部分,写了是如何初始化的。前端
/** * Initialize tagsinput behaviour on inputs and selects which have * data-role=tagsinput */ $(function() { $("input[data-role=tagsinput], select[multiple][data-role=tagsinput]").tagsinput(); });
还有一个经过 select标签初始化的方式。并在标签加上 multiple 属性,在经过$("select").tagsinput('items'),获取值时,返回的是一个数组,而不是逗号分隔的字符串了。java
<select multiple data-role="tagsinput"> <option value="Amsterdam">Amsterdam</option> <option value="Washington">Washington</option> <option value="Sydney">Sydney</option> <option value="Beijing">Beijing</option> <option value="Cairo">Cairo</option> </select>
以上两个方法都会将现有value值或者option元素,自动设置为标签。jquery
通常来讲,若是你只使用输入,回车成为标签的功能,那你可能遇不到什么坑。git
可是一旦你遇到了根据用户输入显示相关补全/提示/预输入的需求时,坑就来了。github
在其文档中,有一个介绍,就是关于Typeahead的,他是这么说的:web
Typeahead is not included in Bootstrap 3, so you'll have to include your own typeahead library. I'd recommed typeahead.js. An example of using this is shown below.
大意是:Bootstrap 3中已经不包含Typeahead啦,若是你想用,你必须本身引入的Typeahead库。
咱们推荐了typeahead.js。下面是使用此示例的示例。巴拉巴拉。
<input type="text" value="Amsterdam,Washington" data-role="tagsinput" /> <script> var citynames = new Bloodhound({ datumTokenizer: Bloodhound.tokenizers.obj.whitespace('name'), queryTokenizer: Bloodhound.tokenizers.whitespace, prefetch: { url: 'assets/citynames.json', filter: function(list) { return $.map(list, function(cityname) { return { name: cityname }; }); } } }); citynames.initialize(); $('input').tagsinput({ typeaheadjs: { name: 'citynames', displayKey: 'name', valueKey: 'name', source: citynames.ttAdapter() } }); </script>
-------------------------------------------------------------------------------------------------------------------------------------------------------------
而后在其文档下方有个Options介绍表,里面有一项关于typeahead的介绍,其中关于source的介绍是:
An array (or function returning a promise or array), which will be used as source for a typeahead.
大意是:一个数组(或返回一个承诺或数组的函数),它将用typeahead的数据源。
说实话,tagsinput 这文档给我一种什么感受呢?
就是=>饶你奸似鬼!照样喝老娘的洗脚水!
上面说了,他给了一个推荐的Typeahead示列,而后下方的option表中有其对应的描述。
若是你只是直接复制示例代码,直接运行,你会遇到别的坑,可是我要说的是,睁大眼睛,仔细观瞧!
在初始化tagsinput时有两个预输入选项,一个是typeaheadjs,另外一个是typeahead。
看出区别了吗?区别多了一个js!!!!!
typeahead.js
Inspired by twitter.com's autocomplete search functionality, typeahead.js is a flexible JavaScript library that provides a strong foundation for building robust typeaheads.The typeahead.js library consists of 2 components: the suggestion engine, Bloodhound, and the UI view, Typeahead. The suggestion engine is responsible for computing suggestions for a given query. The UI view is responsible for rendering suggestions and handling DOM interactions. Both components can be used separately, but when used together, they can provide a rich typeahead experience.
这里说明了,typeaheadjs是受twitter.com自动完成搜索功能的启发,独立的库。
typeahead.js库由2个组件组成:建议引擎, Bloodhound和UI视图,Typeahead。
而后按照tagsinput的示例代码去作。能够作出来。
可是例子是你显示什么!值就是什么!就是说你显示“大脑虎”,你选择输入“大脑虎”成为标签,你提交的值也是“大脑虎”这个字符串!
通常状况下,用于搜索功能没啥问题,由于搜的就是字符串,可是若是用于其余地方,实际值id和显示值name分离的怎么办??
例如城市选择:
[{id: 101, name: "北京"},{id: 102, name: "南京"}]
给用户展现的是“北京”,“南京”的字符串,实际上传递给后台入库的实际上是“id”的值。
示例中的初始化是这样的:
$('input').tagsinput({ typeaheadjs: { name: 'citynames', displayKey: 'name',// valueKey: 'name',//你把这个name换成ID他也不正常 source: citynames.ttAdapter() } });
注意啊,这个displayKey和valueKey 设置的是typeaheadjs 的显示和实际值,和tagsinput没有关系,显示依然不正确!
须要引入的文件:
<link rel="stylesheet" href="./bootstrap-tagsinput.css" /> <script src="./jquery-3.2.1.js"></script> <script src="./typeaheadjs.js"></script> <script src="./bootstrap-tagsinput.js"></script>
提示栏的下拉样式:
<style> .label { background: #428bca; } .bootstrap-tagsinput .tag { color: #000; } .twitter-typeahead.tt-query, .twitter-typeahead .tt-hint { margin-bottom: 0; } .twitter-typeahead .tt-hint { display: none; } .tt-menu { position: absolute; top: 100%; left: 0; z-index: 1000; display: none; float: left; min-width: 160px; padding: 5px 0; margin: 2px 0 0; list-style: none; font-size: 14px; background-color: #ffffff; border: 1px solid #cccccc; border: 1px solid rgba(0, 0, 0, 0.15); border-radius: 4px; -webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175); box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175); background-clip: padding-box; cursor: pointer; } .tt-suggestion { display: block; padding: 3px 20px; clear: both; font-weight: normal; line-height: 1.428571429; color: #333333; white-space: nowrap; } .tt-suggestion:hover, .tt-suggestion:focus { color: #ffffff; text-decoration: none; outline: 0; background-color: #428bca; } </style>
HTML:
<body> <div class="example"> <h2>基本示例</h2> <form action="#" method="get"> <input data-ajax="test.php" class="typeahead" type="text" name="test" placeholder="请输入省份" value="" /> <button type="submit">提交</button> </form> </div> </body>
PHP后端:
<?php echo json_encode([["id"=>101,"name"=>"北京"],["id"=>102,"name"=>"南京"]]); ?>
PHP注意事项:
一、新建一个名叫“test.php”的文件,把这个粘贴进去,放在与你script的同级目录下。
二、要在服务器端上运行(本地的),且安装了PHP。
js:
function tagsinputAjax(inputSelector, valueName, showName) { var $input = $(inputSelector), ajaxUrl = $input.attr("data-ajax"); //初始化bh var engine = new Bloodhound({ queryTokenizer: Bloodhound.tokenizers.whitespace, datumTokenizer: Bloodhound.tokenizers.whitespace, remote: { url: ajaxUrl + "?q=%QUERY", wildcard: "%QUERY" } }); engine.initialize(); var typeaheadConfig = { name: valueName, // displayKey: valueName, // valueKey: showName, templates: { suggestion: function (data) { //格式化预输 console.log(data) return '<div data-id="' + data[valueName] + '">' + data[showName] + '</div>'; } }, source: engine.ttAdapter() }; //初始化 $input.tagsinput({ itemValue: valueName, itemText: showName, typeaheadjs: typeaheadConfig }) } tagsinputAjax(".typeahead", "id", "name");
这段作了一个简单的封装,指定了class为“.typeahead”的input初始化为tags-input,显示的值为“name”,实际值为“id”。
注意事项:
1.此例子为后台处理查询值,前端get方式获取类似值。
2.数据为动态获取,非一次性获取所有数据,使用建议引擎去提示(tagsinput官网给的是所有的获取过来的)方式,而是每次输入的提示都从后台获取,我作的时候总数据有3w条,一次性加载过来显然是不合适的。
3.typeaheadjs会缓存数据的,因此在调试的时候要注意,若是未按照预期呈现结果,记得清缓存后再次调试。
4.注释掉的displayKey 和 valueKey不会有影响,是由于格式化了suggestion条目。
5.data-ajax="test.php"写在了input上,由于我实际作项目时,表单页面是后台动态生成的,根据不一样表单设置不一样的data-ajax能够获取不一样预输入数据。
介绍就不贴了,本身看吧。
Bootstrap 3 Typeahead 原来是集成在Bootstrap 2里的一个js插件,到3的时候给独立出来了。
直接翻到GitHub官网最下面,就是介绍Bootstrap Tags Input如何使用Bootstrap 3 Typeahead。
Bootstrap Tags Input is a jQuery plugin providing a Twitter Bootstrap user interface for managing tags. Bootstrap Tags Input has a typeahead option which allows you to set the source:
$("input").tagsinput({ typeahead: { source: ["Amsterdam", "Washington", "Sydney", "Beijing", "Cairo"] } });or
$("input").tagsinput({ typeahead: { source: function(query) { return $.get("http://someservice.com"); } } });See also: https://github.com/bassjobsen/Bootstrap-3-Typeahead/issues/40
本地的预输入没有问题,有问题的是第二个,你把$.get中的地址换成你本身以后,它请求成功了,可是!它没有提示!它没有显示预输入的下拉。
这是为啥呢?我也不知道。
问题出现了!那就想办法解决吧。
首先,我把代码由:
$("input").tagsinput({ typeahead: { source: function (query) { return $.get("test.php?q=" + query); } } });
改成:
$("input").tagsinput({ typeahead: { source: function (query) { // return $.get("test.php?q=" + query); return ["北京", "南京"]; } } });
结果发现可用,那说明什么?
说明:
1.请求时成功的,而且是返回数据的,那么请求的数据没有问题。
2.直接return城市数据组,依然可使用,说明不是数据格式的问题。
3.问题出在了$.get()这了。
说明是返回数据的问题,我把数据返回一下,写成这样是否是就好了?
$("input").tagsinput({ typeahead: { source: function (query) { var result=null; $.ajax({ url: "test.php?q=" + query, type: "get", dataType: "json",//对的,数据类型不能少 success: function (res) { result = res.data; } }); return result; } } });
而后报错了...
Uncaught TypeError: Cannot read property 'success' of null bootstrap-tagsinput.js:294
at Typeahead.source (bootstrap-tagsinput.js:294)
at Typeahead.<anonymous> (bootstrap3-typeahead.js:226)
查了一下 ,截取一下tagsinput.js
...... source: function (query, process) { function processItems(items) { var texts = []; for (var i = 0; i < items.length; i++) { var text = self.options.itemText(items[i]); map[text] = items[i]; texts.push(text); } process(texts); } this.map = {}; var map = this.map, data = typeahead.source(query);// 这里的data就是返回的数据 if ($.isFunction(data.success)) {//报错的是这里 // support for Angular callbacks data.success(processItems); } else if ($.isFunction(data.then)) { // support for Angular promises data.then(processItems); } else { // support for functions and jquery promises $.when(data) .then(processItems); } }, ......
打印了一下data为null,因此报错。为啥呢?为返回的数据是null。network里显示xhr请求时成功的啊,也返回了数据啊?
其实改一下代码就行了:
$("input").tagsinput({ typeahead: { source: function (query) { var result=null; $.ajax({ url: "test.php?q=" + query, type: "get", dataType: "json",//对的,数据类型不能少 async: false,//新增了一个async为false success: function (res) { result = res.data; } }); return result; } } });
而后就OK了。为啥这就OK了呢?本身想一下,很简单的。
若是仍然想用显示和值分离,则以下:
$("input").tagsinput({ itemValue: '此处填写实际的要传递给后台的key', itemText: '此处填写显示给用户看的的key', typeahead: { source: function (query) { var result=null; $.ajax({ url: "test.php?q=" + query, type: "get", async: false, success: function (res) { result = res.data; } }); return result; } } });
php:
<?php echo json_encode(["status" => "OK", "data" => [ ["id"=>101,"name"=>"北京"], ["id"=>102,"name"=>"南京"] ]]) ?>
注意:
我此次作项目用到了tagsinput.js,这货的手册作的特别的不友好,示列也不许确。基本上初次用的人都会遇到各类各样的问题,我为了解决各类问题各类google。心累,不爱。
typeahead和typeaheadjs傻傻分不清楚。
tagsinput.js源码中有注释,看到没,它去判断设置中用的是Bootstrap 3 Typeahead的预输入仍是用的typeaheadjs。
更操蛋的是,它重写了
Bootstrap tagsinput use the source parameter only. When using this
typeahead
option bootstrap tagsinput initiates a newtypeahead
class:self.$input.typeahead
. Bootstrap tagsinput's typeahead classes overwrite the original source function and has a call to process already as shown below:
Bootstrap tagsinput仅使用source参数。使用此typeahead
选项时,bootstrap tagsinput会启动一个新typeahead
类:self.$input.typeahead
。Bootstrap tagsinput的typeahead类覆盖原始源函数,而且已经调用process,以下所示:
if (self.options.typeahead) { var typeahead = self.options.typeahead || {}; makeOptionFunction(typeahead, 'source'); self.$input.typeahead($.extend({}, typeahead, { source: function (query, process) { function processItems(items) { var texts = []; for (var i = 0; i < items.length; i++) { var text = self.options.itemText(items[i]); map[text] = items[i]; texts.push(text); } process(texts); } this.map = {}; var map = this.map, data = typeahead.source(query); if ($.isFunction(data.success)) { // support for Angular callbacks data.success(processItems); } else if ($.isFunction(data.then)) { // support for Angular promises data.then(processItems); } else { // support for functions and jquery promises $.when(data) .then(processItems); } }, updater: function (text) { self.add(this.map[text]); return this.map[text]; }, matcher: function (text) { return (text.toLowerCase().indexOf(this.query.trim().toLowerCase()) !== -1); }, sorter: function (texts) { return texts.sort(); }, highlighter: function (text) { var regex = new RegExp( '(' + this.query + ')', 'gi' ); return text.replace( regex, "<strong>$1</strong>" ); } })); }
生活啊 !坑爹啊!