javascript suggest效果


像百度與google,當我們往搜索框輸入東西時就會出現一排列表提示用戶有什么熱門或適合的候選詞,這種效果就叫suggest。本文將一步步教你如何設計它。

首先,用到的框架當然是我的框架mass Framework,當然你用其他框架也可以,如jQuery,沒有什么復雜的東西。只要弄懂原理,一下子就能搞出來。想必,以后你們工作也遇到做搜索框的活兒。

由於本人沒有后端,因此取用一個對象作為本地數據庫。而我現在要做的,其實遠遠比suggest高級,類似IDE的語法提示的東西。當前成品已放到github上。

好了,我們動手吧。首先是結構層,裝了FF的同學可以在百度首頁查看源碼,當輸入幾個字母時,會動態生成了那些HTML。不過怎么也好,其成就是一個DIV放到搜索欄的下方,里面放了一個table,table動態存放候選詞。並且候選詞如果不是用戶輸入的部分,也就是說,JS自動補充的部分它會把它們放到一個b標簽加粗顯示出來。不過, 我覺得用table太重量化,改用了ul列表,為了讓IE6也支持掠過變色效果,我還在里面套了一個a標簽。為了放便取詞,我還為它(a標簽),添加了一個屬性,專門用於存放補充元整后的詞匯。大抵是這個樣子:

    <div id="search_wrapper">
        <div>
            <input id="search" autocomplete="off">
        </div>
        <div id="suggest_wrapper">
            <ul id="suggest_list">
                <li>
                    <a data-value="完整的詞匯" href="javascript:void(0)">
                        用戶輸入部分
                        <b>自動提示部分</b>
                    </a>
                </li>
                <li>
                    <a data-value="完整的詞匯" href="javascript:void(0)">
                        用戶輸入部分
                        <b>自動提示部分</b>
                    </a>
                </li>
                <!-- 更多li 最多10個 -->
            </ul>
        </div>
    </div>

看一看結構,其實就是兩部分,div#search_wrapper為可見,div#suggest_wrapper為“不可見”(只要里面沒有li元素,它就不占空間,顯示不出來了)。input搜索框有個屬性autocomplete,用於關掉瀏覽器自帶的提示功能。關於data-value,這種命名方法是HTML5推薦的方式,用於定義要緩存的數據,data-*在新銳瀏覽器中會放到一個叫dataset的對象中。比如:

 <div id="司徒正美"
  data-drink="coffee"
  data-meal-time="12:00">12:00</div>

我們可以通過如下方式訪問到它:

 var el= document.getElementById('司徒正美');
 alert( el.dataset.drink );
 alert( el.dataset.mealTime );

當然,你也可以不用設置屬性,直接取a標簽的innerText或textContext。

注意:完整的詞匯 = 用戶輸入部分 + 自動提示部分。因此你不要在a標簽里面加這么多東西,防止出現空格什么的,導致檢索失敗!

接着是樣式部分,不過不詳述了。很簡單:

  #search_wrapper {
                height:50px;
            }
            #search{
                width:300px;
            }
            #suggest_wrapper{
                position:relative;
            }
            #suggest_list{
                position:absolute;
                z-index:100;
                list-style: none;
                margin:0;
                padding:0;
                background:#fffafa;
                border:1px solid #ccc;
                border-bottom:0 none;
            }
            #suggest_list li a{
                display: block;
                height:20px;
                width:304px;
                color: #000;
                border-bottom:1px solid #ccc;
                line-height:20px;
                text-decoration: none;
            }
            #suggest_list li a:hover, .glow_suggest {
                 background:#ffff80;
            }

好了,到重點了。由於我沒有后台,要使用一個本地對象作為本地數據庫。這對象當然是個JS對象了。我們遍歷對象一般都是obj.aaa.bbb.ccc,這樣一直點下去,其實每到一個點號時,就是用for in 循環進行遍歷。因此我們監聽文本內容的輸入的情況,一但發生變化就取得輸入框的內容,然后在for in 循環中比較。如果是與這個輸入值開頭的屬性就取出來,放到一個數組中,一直取夠十個,然后把這些數組的內容拼接成上述描繪的li元素格式,一並貼到ul元素之內。當中,我們還要注意點中,如果一開始就輸入點號,我們就取window對象的十個屬性吧,以后遇到點號就切換這個對象。

好了,開始寫碼,由於用到我的框架,大家可以到這里去下。在項目首頁有README,教你是怎么安裝微型.Net服務器與查看文檔的。一開始,你就姑且把它當成是添加了模塊加載功能的jQuery,API 90%神似。我們要用到它的事件模塊與屬性模塊,它會把相關依賴加載好的,再添加ready參數,它就會在domReady后執行。我們選擇輸入框后為它綁定一個input事件,這是一個標准瀏覽器都支持的事件,IE下我的框架已經兼容好了,用jQuery與原生的同學請用propertychange事件模擬。

//by 司徒正美
$.require("ready,event,attr",function(){
    var search = $("#search"), hash = window, prefix = "", fixIE = NaN;
    search.addClass("search_target");
    search.input(function(){//監聽輸入
        var
        input = this.value,//原始值
        val = input.slice( prefix.length),//比較值
        output = []; //用來放置輸出內容
        if( fixIE === input){
            return //IE下肅使是通過程序改變輸入框里面的值也會觸發propertychange事件,導致我們無法進行上下翻操作
        }
        for(var prop in hash){
            if( prop.indexOf( val ) === 0  ){//取得以輸入值開頭的API
                if( output.push( '<li><a href="javascript:void(0)" data-value="'+prefix +
                    prop+'">'+ input + "<b>" + (prefix  + prop ).slice( input.length ) +"</b></a></li>" ) == 10){
                    break;
                }
            }
        }
        //如果向前遇到點號,或向后取消點號
        if( val.charAt(val.length - 1) === "." || (input && !val) ){
            var arr = input.split("."); hash = window;
            for(var j = 0; j < arr.length; j++){
                var el = arr[j];
                if(el && hash[ el ]){
                    hash = hash[ el ];//重新設置要遍歷API的對象
                }
            }
            prefix = input == "." ? "" : input;
            for( prop in hash){
                if( output.push( '<li><a href="javascript:void(0)" class="search_target" data-value="'+prefix +
                    prop+'">'+ input + "<b>" + (prefix + prop ).slice( prefix.length ) +"</b></a></li>" ) == 10){
                    break;
                }
            }
        }
        $("#suggest_list").html( output.join("") );
        if(!input){//重置所有
            hash = window;
            fixIE = prefix = output = [];
        }
    });

});

當提示列表出來后,我們就監聽上下翻效果。也就是點擊鍵盤的方位鍵時,會上下高亮提示的條目,並且它填進搜索框中。這時需要綁定keyup事件,檢查其keyCode,標准瀏覽器管它為which,可以看我的這篇博文《javascript 鍵盤事件總結》。實現原理很簡單,定義一個外圍的變量,用於存放高亮的位置(索引值),然后用上翻時就減一,用下翻時就加一,然后取得提示列表中的所有a標簽,用索引值定位到某一個a標簽中,高亮它,然后去掉原先高亮的a標簽。

//by 司徒正美
$.require("ready,event,attr",function(){
    var search = $("#search"), hash = window, prefix = "";
    search.input(function(){//監聽輸入
//.....
    });
    var glowIndex = -1;
    $(document).keyup(function(e){//監聽上下翻
        if(/search_target/i.test( e.target.className)){//只代理特定元素,提高性能
            var upOrdown = 0
            if(e.which === 38 || e.which === 104){ //up 8
                upOrdown --;
            }else if(e.which === 40 || e.which === 98){//down 2
                upOrdown ++;
            }
            if(upOrdown){
                var list =  $("#suggest_list a");
                //轉移高亮的欄目
                list.eq(glowIndex).removeClass("glow_suggest");
                glowIndex += upOrdown;
                var el = list.eq( glowIndex ).addClass("glow_suggest");
                fixIE = el.attr("data-value")
                search.val( fixIE )
                if(glowIndex === list.length - 1){
                    glowIndex = -1;
                }
            }
        }
    });
});

最后是回車提交。我又寫到一個keyup事件中去。當然你們可以設法把兩個keyup合成一個(監聽window),我這樣寫純粹是為了教學的需要。

//by 司徒正美
$.require("ready,event,attr",function(){
    var search = $("#search"), hash = window, prefix = "";
    search.input(function(){//監聽輸入
//.....
    });
    var glowIndex = -1;
    $(window).keyup(function(e){//監聽上下翻
//.....
    });
    search.keyup(function(e){//監聽提交
        var input = this.value;
        if(input && (e.which == 13 || e.which == 108)){ //如果按下ENTER鍵
           alert(input)//實際項目中,應該是進行頁面跳轉,跑到搜索結果頁中去的!
        }
    });
});

到此,suggest效果就完成了。如果下了我的框架的同學,開啟服務器,打開文檔首頁就能看到這個效果。而在實際項目,suggest其實更簡單些,就是當輸入框文本變化時,AJAX請求后台一個數組,然后再把它拼接成li元素的格式就行了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM