Bootstrap Typeahead 組件

Bootstrap 中的 Typeahead 組件就是通常所說的自動完成 AutoComplete,功能很強大,但是,使用上並不太方便。這裏我們將介紹一下這個組件的使用。

第一,簡單使用

首先,最簡單的使用方式,就是直接在標記中聲明,通過 data-provide="typeahead" 來聲明這是一個 typeahead 組件,通過 data-source= 來提供數據。當然了,你還必須提供 bootstrap-typeahead.js 腳本。

複製代碼
<html>
<head>
<link href="bootstrap.min.css" rel="stylesheet" type="text/css" />
</head>
<body>
 
<div style="margin: 50px 50px">
<label for="product_search">Product Search: </label>
<input id="product_search" type="text" data-provide="typeahead"
     data-source='["Deluxe Bicycle", "Super Deluxe Trampoline", "Super Duper Scooter"]'>
</div>
 
<script src="js/jquery-1.8.3.min.js"></script>
<script src="js/bootstrap-typeahead.js"></script>
 
</body>
</html>
複製代碼

第二,使用腳本填充數據

通常,我們使用腳本來填充數據,那麼,頁面可以變成如下的形式。

複製代碼
<html>
<head>
<link href="bootstrap.min.css" rel="stylesheet" type="text/css" />
</head>
<body>
 
<div style="margin: 50px 50px">
<label for="product_search">Product Search: </label>
<input id="product_search" type="text" data-provide="typeahead">
</div>
 
<script src="js/jquery-1.8.3.min.js"></script>
<script src="js/bootstrap-typeahead.js"></script>
 
<script>
$(document).ready(function($) {
   // Workaround for bug in mouse item selection
   $.fn.typeahead.Constructor.prototype.blur = function() {
      var that = this;
      setTimeout(function () { that.hide() }, 250);
   };
 
   $('#product_search').typeahead({
      source: function(query, process) {
         return ["Deluxe Bicycle", "Super Deluxe Trampoline", "Super Duper Scooter"];
      }
   });
})
</script>
 
</body>
</html>
複製代碼

注意,我們提供了一個 source 函數來提供數據,這個函數接收兩個參數,第一個參數 query 表示用戶的輸入,第二個參數是 process 函數,這個 process 函數是 typeahead 提供的,用來處理我們的數據。

如果你希望通過 Ajax 調用從服務器端獲取匹配的數據,那麼,在異步完成的處理函數中,你需要獲取一個匹配的字符串數組,然後,將這個數組作爲參數,調用 process 函數。

第三,支持 Ajax 獲取數據

說了半天,數據都是從本地獲取的,到底如何從服務器端獲取數據呢?

其實很簡單,在 source 函數中,自己調用 Ajax 方法來獲取數據,主要注意的是,在獲取數據之後,調用 typeahead 的 process 函數處理即可。

複製代碼
$('#product_search').typeahead({
    source: function (query, process) {
        var parameter = {query: query};
        $.post('@Url.Action("AjaxService")', parameter, function (data) {
            process(data);
        });
    }
});
複製代碼

當然了,在服務器上,你需要創建一個服務來提供數據,這裏,我們演示使用隨機數來生成一組隨機數據的方法。

複製代碼
public ActionResult AjaxService(string query)
{
    System.Collections.ArrayList list
        = new System.Collections.ArrayList();
    System.Random random = new Random();

    for (int i = 0; i < 20; i++)
    {
        string item  = string.Format("{0}{1}", query, random.Next(10000));
        list.Add(item);
    }
    return this.Json(list);
}
複製代碼

第四,使用 highlighter 和 updater

除了使用 source 函數之外,還可以使用 highlighter 函數來特別處理匹配項目的顯示,使用 updater 函數,在選擇了某個匹配項之後,做出一些後繼的處理。

默認的 highlighter 是這樣實現的,item 是匹配的項目,找到匹配的部分之後,使用 <strong> 加粗了。

highlighter: function (item) {
    var query = this.query.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, '\\$&')
    return item.replace(new RegExp('(' + query + ')', 'ig'), function ($1, match) {
        return '<strong>' + match + '</strong>'
    })
}

而 updater 的默認實現就更加簡單了。

updater: function (item) {
    return item
}

我們可以重寫這兩個函數,來實現自定義的處理。

 

複製代碼
<html>
<head>
<link href="bootstrap.min.css" rel="stylesheet" type="text/css" />
</head>
<body>
 
<div style="margin: 50px 50px">
<label for="product_search">Product Search: </label>
<input id="product_search" type="text" data-provide="typeahead">
</div>
 
<script src="js/jquery-1.8.3.min.js"></script>
<script src="js/bootstrap-typeahead.js"></script>
 
<script>
$(document).ready(function($) {
   // Workaround for bug in mouse item selection
   $.fn.typeahead.Constructor.prototype.blur = function() {
   var that = this;
      setTimeout(function () { that.hide() }, 250);
   };
 
   $('#product_search').typeahead({
      source: function(query, process) {
         return ["Deluxe Bicycle", "Super Deluxe Trampoline", "Super Duper Scooter"];
      },
 
      highlighter: function(item) {
         return "==>" + item + "<==";
      },
 
      updater: function(item) {
         console.log("'" + item + "' selected.");
      return item;
}
});
})
</script>
</body>
</html>
複製代碼

第五,使用對象數據

實際上,你的數據可能是一組對象而不是一個字符串數組,下面的例子中,我們使用一個產品對象的數組來說明,每個產品對象有一個 id 編號,還有名稱  name 和價格 price .

複製代碼
<html>
<head>
    <link href="~/Content/dist/css/bootstrap.min.css" rel="stylesheet" />
</head>
<body>

    <div style="margin: 50px 50px">
        <label for="product_search">Product Search: </label>
        <input id="product_search" type="text" data-provide="typeahead">
    </div>
    <script src="~/Content/dist/js/jquery.js"></script>
    <script src="~/Content/dist/js/bootstrap-typeahead.js"></script>
    <script src="~/Content/dist/js/underscore-min.js"></script>


    <script>
        $(document).ready(function ($) {
            // Workaround for bug in mouse item selection
            $.fn.typeahead.Constructor.prototype.blur = function () {
                var that = this;
                setTimeout(function () { that.hide() }, 250);
            };

            var products = [
            {
                id: 0,
                name: "Deluxe Bicycle",
                price: 499.98
            },
            {
                id: 1,
                name: "Super Deluxe Trampoline",
                price: 134.99
            },
            {
                id: 2,
                name: "Super Duper Scooter",
                price: 49.95
            }
            ];

            $('#product_search').typeahead({
                source: function (query, process) {
                    var results = _.map(products, function (product) {
                        return product.name;
                    });
                    process(results);
                },

                highlighter: function (item) {
                    return "==>" + item + "<==";
                },

                updater: function (item) {
                    console.log("'" + item + "' selected.");
                    return item;
                }
            });
        })
    </script>

</body>
</html>
複製代碼

第六,高級用法

我們希望能夠在提示中顯示產品的更加詳細的信息。

首先,修改我們的 source 函數,原來這個函數返回一個字符串的數組,現在我們返回一個產品 id 的數組,但是,process 函數期望得到一個字符串數組的參數,所以,我們將每個 id 都轉換爲字符串類型。

然後,typeahead 組件就會調用 matcher 函數來檢查用戶的輸入是否與某個項目匹配,你可以使用產品的 id 在產品列表中獲取產品對象,然後檢查產品的名稱與用戶的輸入是否匹配。

默認的 matcher 直接使用用戶的輸入來匹配,我們如果使用 id 的話,顯然不能匹配,我們需要重寫 matcher 函數。

matcher 接收一個當前項目的字符串,用戶當前的輸入爲 this.query,匹配返回 true, 否則返回 false. 默認的 matcher 如下:

, matcher: function (item) {
    return ~item.toLowerCase().indexOf(this.query.toLowerCase())
}

將它重寫爲永遠匹配,直接返回 true。而在 highlighter 中將顯示結果替換爲希望的產品名稱和價格組合。在下一步的 highlighter 中,我們使用 Underscore 組件中的 find 方法,通過產品的 id 在產品列表中獲取產品對象,然後,顯示產品名稱和價格的組合。

highlighter: function (id) {
    var product = _.find(products, function (p) {
        return p.id == id;
    });
    return product.name + " ($" + product.price + ")";
}

默認的 updater 直接返回當前匹配的內容,我們這裏是一個 id, 需要重寫。

updater: function (item) {
    return item
}

在用戶選擇之後,typeahead 將會調用 updater 函數,我們通過產品的 id 在產品列表中獲取產品對象,然後

最後,updater 函數返回一個產品名稱的字符串,爲輸入框提供內容。setSelectedProduct 是我們的一個自定義函數。

複製代碼
updater: function (id) {
    var product = _.find(products, function (p) {
        return p.id == id;
    });
    that.setSelectedProduct(product);
    return product.name;
}
複製代碼

下面是全部的代碼。

複製代碼
<html>
<head>
    <link href="~/Content/dist/css/bootstrap.min.css" rel="stylesheet" />

</head>
<body>

    <div style="margin: 50px 50px">
        <label for="product_search">Product Search: </label>
        <input id="product_search" type="text" data-provide="typeahead">
        <div id="product" style="border-width: 1; padding: 5px; border-style: solid"></div>
    </div>

    <script src="~/Content/dist/js/jquery.js"></script>
    <script src="~/Content/dist/js/bootstrap-typeahead.js"></script>
    <script src="~/Content/dist/js/underscore-min.js"></script>

    <script>
        $(document).ready(function ($) {
            // Workaround for bug in mouse item selection
            $.fn.typeahead.Constructor.prototype.blur = function () {
                var that = this;
                setTimeout(function () { that.hide() }, 250);
            };

            var products = [
            {
                id: 0,
                name: "Deluxe Bicycle",
                price: 499.98
            },
            {
                id: 1,
                name: "Super Deluxe Trampoline",
                price: 134.99
            },
            {
                id: 2,
                name: "Super Duper Scooter",
                price: 49.95
            }
            ];

            var that = this;

            $('#product_search').typeahead({
                source: function (query, process) {
                    $('#product').hide();
                    var results = _.map(products, function (product) {
                        return product.id + "";
                    });
                    process(results);
                },

                matcher: function (item) {
                    return true;
                },

                highlighter: function (id) {
                    var product = _.find(products, function (p) {
                        return p.id == id;
                    });
                    return product.name + " ($" + product.price + ")";
                },

                updater: function (id) {
                    var product = _.find(products, function (p) {
                        return p.id == id;
                    });
                    that.setSelectedProduct(product);
                    return product.name;
                }

            });

            $('#product').hide();
            this.setSelectedProduct = function (product) {
                $('#product').html("Purchase: <strong>" + product.name + " ($" + product.price + ")</strong>").show();
            }
        })
    </script>

</body>
</html>

 參考資料

Twitter Boostrap Typeahead Tutorial

typeahead 下載地址

underscore 下載地址

typeahead()詳解

參考官方README和其他一些博客的資料,可以瞭解typeahead函數可以接受的一些參數,這些參數可以通過指定標籤屬性來傳遞,也可以直接在JavaScript中給出。對於標籤屬性傳遞參數來說,需要在參數前加上data-,例如data-source="".

下表爲官方README文檔中參數表格的翻譯版本:

NameTypeDefaultDescription
sourcearray, function[]

用來查詢的數據源。可以是數組或字符串,一個帶有name屬性的JSON對象的數組集合,或者一個函數。函數可以接受兩個參數,query代表輸入框中你的輸入值(即查詢值),process回調函數。The function may be used synchronously by returning the data source directly or asynchronously via the process callback's single argument.

itemsnumber8下拉選項中出現條目的最大數量。也可以設置爲“all”
minLengthnumber1出發下拉提示的最小長度字符串。可以設置爲0,即使沒有填寫任何內容,也會出現提示。
showHintOnFocusboolean or "all"false當輸入框獲得焦點時立刻顯示提示。如果設置爲true,顯示所有匹配項。如果設置爲“all”,顯示所有提示,並不會按照當前文本過濾。當你需要一個組合框(Combo Box,由文本框和下拉框組成)功能時,可以考慮這個。
scrollHeightnumber, function0Number of pixels the scrollable parent container scrolled down (scrolled out the viewport).
matcherfunctioncase insensitive該函數用來確定匹配條目的規則。接受一個參數,item用於測試查詢字符串是否匹配。通過當前查詢字符串this.query。如果相匹配則返回true
sorterfunctionexact match,
case sensitive,
case insensitive
該函數用來對結果進行排序。接受一個參數items並且具有typeahead實例的作用域,通過this.query得到當前查詢。
updaterfunctionreturns selected item該函數用來返回選中的條目。接受一個item參數並且具有typeahead實例的作用域。
highlighterfunctionhighlights all default matches用來高亮自動補全的結果。接受一個item參數並且擁有typeahead實例的作用域。應該返回html
displayTextfunctionitem.name || item用來得到數據源的條目的文本表示。接受一個item參數並且擁有typeahead實例的作用域。應該返回一個字符串。
autoSelectbooleantrue允許你決定是否自動選擇第一個建議。關閉它意味着如果沒有選擇任何內容(或Enter或Tab),輸入將不會清空。
afterSelectfunction$.noop()選擇一個條目後的回調函數。It gets the current active item in parameter if any.
delayinteger0在查找之間添加延遲
appendTojQuery elementnull默認情況下,菜單將會出現在輸入元素的之後。使用這個選項來添加菜單到其他div。如果你想使用bootstrap的dropup或者dropdown-menu-right classes,就不要使用它
fitToElementbooleanfalse如果你希望菜單的大小與其所鏈接的輸入的大小相同,置爲true
addItemJSON objectfalse在list的最後添加一個條目,例如“New Entry”。這可能被用到,例如當一個條目在數據集中沒有被找
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章