使用 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 下載地址

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章