JS實現動態提示框

引言

什麼項目都有個需求,應開發需求,須要寫一個公式編輯器選擇公式的插件,下面給你們講一下實現過程。(擦汗,強做淡定,咳,開嗓~)javascript

看圖說話

本小菜開發功能前樂於先寫個需求思惟導圖(純屬我的愛好):css

Html 

真的只有一點點~html

複製代碼
<!DOCTYPE html>  
<html>  
<head>  
    <meta charset="UTF-8">
    <title>公式編輯器測試</title>
    <link rel="stylesheet" type="text/css" href="./css/global.css">
    <script type="text/javascript" src="./js/jquery-1.8.3.min.js"></script>  
    <script type="text/javascript" src="./js/editTips.js"></script> 
    
</head>  
<body> 

    <textarea id="test" ></textarea>

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

css

一塊兒給了吧~早晚要給:前端

複製代碼
/* 編輯器下拉框相關樣式 */
table,tr,th,td{padding:0;margin:0;}
ul,li,textarea,input{text-decoration:none;list-style:none;margin:0;padding:0;box-sizing: border-box;}
input{ 
    outline:none;
 }
.editTips{
    padding:5px 0;
    border-radius: 0!important;
    box-shadow: 0 2px 4px rgba(0,0,0,.2);
    max-height: auto;
    margin:0;
    z-index:9999;
}
.editTips li{
    text-align:left;
    box-sizing:border-box;
    display:block;
    width:100%;
    line-height:1.42857143;
    margin:1px 0;
    padding:6px 11px;
    color:#333;
    cursor:pointer;
    overflow:hidden;
    text-overflow:ellipsis;
    white-space:nowrap;
    font-weight:400;
    line-height:1.42857143;
    border-bottom:solid 1px #e5e5e5;
    background:#e5e5e5;
}
.editTips li:last-child{
    border-bottom:none;
}
.active{ 
    background:#fee188!important; 
} 
.editTips li.active{ background:#fee188!important; }
textarea{
    text-decoration: none;
    list-style: none;
    margin: 0;
    padding: 0;
    display: block;
    box-sizing: border-box;
    width: 500px;
    height: 300px;
    margin-top: 100px;
    margin-left: 100px;
}
複製代碼

 插件模板 - this 爲輸入框

複製代碼
(function ($) {
    $.fn.extend({
        "editTips": function (options) {
            var opts = $.extend({}, defaults, options); //使用jQuery.extend 覆蓋插件默認參數
            return    this.each(function () { //這裏的this 就是 jQuery對象

                });
            }
        });
          //默認參數
          var defaults = {

          };                    
})(window.jQuery);
複製代碼

插入下拉框

這裏 this 爲輸入框,在 html 中,不須要再去js插入,固然這不是問題,在這裏咱們將 輸入框和下拉框都自定義一下,插入的 ul 中 editTips 類能夠去掉,爲了方便看效果暫時加上java

我我的確定是但願下拉框寬度是能夠自定義的: 'width':opts.dropdownWidth, 這裏咱們定義了第一個參數: 下拉框寬度 node

 

複製代碼
 1                     var _this = this;                      
 2                       _this.entertext = $(this);
 3                       _this.dropdown = $('<ul class="editTips" style="display:none;"></ul>');
 5                       $("body").after(_this.dropdown);                      
 6                     _this.dropdown.css({
 7                         'width':opts.dropdownWidth,
 8                         'position':'absolute',
 9                     });

複製代碼

 監聽文本框

ps:既然是公式編輯器,那說明不會一直觸發檢索事件,只有在輸入了指定字符的時候纔會觸發檢索事件,好比:! @ # 之類,這裏咱們以 $ 爲例,從這裏咱們能夠想到,咱們確定jquery

須要一個參數來動態改變檢索事件觸發條件,先記在內心json

檢索流程: 輸入框輸入值  -  輸入特定字符觸發檢索,如 $  -  是否符合放鬆請求條件:輸入間隔一秒  -  調用回調函數,咱們這裏爲 callbacktips 匹配關鍵字  -  返回包含關鍵字部分匹配結果,以數組形式  -  遍歷數組添加到下拉框 ul 中顯示  -  選取當前項 

其中數組相關方法運用得較多數組

 由於其中還涉及到限制請求,方向鍵切換當前項,這裏就不分開說了,直接給出整塊代碼以下:session

複製代碼
// 監聽輸入框
_this.dropdown.parent().on("keyup",this,function(event){                        
    var nowTime =  window.sessionStorage.getItem('nowTime');
    // 當前項索引
    var n = _this.dropdown.find(".active").index();
    // li 個數
    var n_max = _this.dropdown.find("li").length;
    // 注意 event在 firefox 中不能兼容,在方法中帶上event參數,以下聲明實現兼容
    EVT = event || window.event;
    if( EVT.keyCode == 38 ){
        // 方向鍵控制 li 選項
        if(n-1>=0){
            _this.dropdown.find('li').eq(n-1).addClass("active").siblings().removeClass("active");
        }
        if( n == 0){
            _this.dropdown.find('li').eq(n_max-1).addClass("active").siblings().removeClass("active");
        }
        return false;
    }
     // 禁止enter鍵換行
    if( EVT.keyCode == 13 ){
        return false;
    }
    if( EVT.keyCode == 40 ){
        // 方向鍵控制 li 選項
        if(n<n_max-1){
            _this.dropdown.find('li').eq(n+1).addClass("active").siblings().removeClass("active");    
        }
        if( n+1 == n_max ){
            _this.dropdown.find('li').eq(0).addClass("active").siblings().removeClass("active");
        }
        return false;
    }
    // 限制請求,輸入間隔不超過一秒時不觸發檢索事件發送請求
    if( nowTime){
        var oldTime = Date.now();
        var nowTime = window.sessionStorage.getItem('nowTime');
        var m =  parseInt((oldTime - nowTime)/1000);
        if( m >= 1){                                
            // 文本內容
            var val = _this.entertext.val();
            // 以空格切割文本返回數組
            var arr_test = val.split(" ");
            // 獲取數組最後一個元素
            var temp = arr_test[arr_test.length-1];
            // 切割最後一個元素 單字符元素 返回數組
            var temp_type = temp.split("");
            // 獲取數字第一個字符
            var temp_cha = temp_type[0];
            // 最後一個元素長度
            var temp_len = temp.length;

            var temp_dot = temp_type.lastIndexOf(".");
            // 定義回調函數 callbacktips
            var  callbacktips = function(arr_json){                            
                 // 初始化 UL 
                _this.dropdown.find("li").remove();
                for( i=0;i<arr_json.length;i++ ){
                    _this.dropdown.append('<li>'+arr_json[i]+'</li>');            
                };
                _this.dropdown.show();
                _this.dropdown.find("li:first-child").addClass("active");
                // 自定義樣式
                _this.dropdown.find("li").css({    
                    'width':'100%',
                });
            };
            // 最後一個元素爲空值 
            if( temp_len == 0 ){
                _this.dropdown.hide();
                _this.dropdown.find('li').remove();
            }
            // 爲特定字符 符合觸發條件 
            if( temp_cha == opts.triggerCharacter ){                            
                if($.isFunction(opts.keyPressAction)){
                    
                    opts.keyPressAction(temp, function(arr_json){
                        // 調用回調函數
                        callbacktips(arr_json);
                    
                    });
                }
            }else{
                _this.dropdown.hide();
                _this.dropdown.find('li').remove();
            }                 
        }
    }
    // 初始化第一次時間
    window.sessionStorage.setItem('nowTime',Date.now());
});
複製代碼
ps:這裏出現了咱們第二個參數,也是相當重要的一個參數,觸發檢索事件字符: opts.triggerCharacter

鼠標切換當前項

下拉菜單顯示以後(這裏咱們先無論下拉菜單顯示的位置),從體驗上來講我但願既能夠用鼠標選取,也能夠用方向鍵選取,方向鍵切換當前項整合在上面的代碼中,這裏鼠標切換當前項:

// 切換當前項
_this.dropdown.on('mouseenter','li',function(){
    $(this).addClass("active").siblings().removeClass("active");
});

阻止鍵盤按鍵默認事件 - enter鍵選取當前項

若是不作處理,咱們在用方向鍵切換當前項的時候,你會看到光標也在上下移動,這如何能忍?怎麼辦?屏蔽它~,在這裏咱們能夠整合enter鍵選取當前項,看代碼:

複製代碼
// 阻止輸入過程當中 方向鍵盤的默認事件
_this.entertext.on("keydown",_this.entertext,function(event){
    EVT = event || window.event;
    if( EVT.keyCode == 38 ){
        EVT.preventDefault();
    }
    if( EVT.keyCode == 40 ){
        EVT.preventDefault();
    }
    // enter鍵選取對應的 li
    if( EVT.keyCode == 13 ){
        EVT.preventDefault();
        var txt = _this.dropdown.find(".active").html();
        var test_txt = _this.entertext.val();
        var arr_change = test_txt.split(" ");
        // 以空格切割文本返回數組
        var arr_test = test_txt.split(" ");
        // 獲取數組最後一個元素
        var temp = arr_test[arr_test.length-1];
        var temp_type = temp.split("");
        var temp_dot = temp_type.lastIndexOf(".");
        var n ;
        temp_type.splice(temp_dot+1,temp_type.length-1-temp_dot,txt);
        n = temp_type.join('');
        arr_change.splice(arr_change.length-1,1,""+n);
        _this.entertext.val(arr_change.join(" "));
        _this.dropdown.hide();
        _this.dropdown.find('li').remove();
        }
});
複製代碼

點擊當前項 重組val

要不咱們直接看代碼吧,你可能已經餓了~好的。看代碼:

複製代碼
// 點擊替換 重組val
$(document).on("click",'li',function(){
    var txt = $(this).html();
    var test_txt = _this.entertext.val();
    var arr_change = test_txt.split(" ");
    // 以空格切割文本返回數組
    var arr_test = test_txt.split(" ");
    // 獲取數組最後一個元素
    var temp = arr_test[arr_test.length-1];y
    var temp_type = temp.split("");
    var temp_dot = temp_type.lastIndexOf(".");
    var n ;
    temp_type.splice(temp_dot+1,temp_type.length-1-temp_dot,txt);
    n = temp_type.join('');
    arr_change.splice(arr_change.length-1,1,""+n);
    _this.entertext.val(arr_change.join(" "));
    _this.dropdown.hide();
    _this.dropdown.find('li').remove();
});
複製代碼

默認參數

到了這裏拋開動態顯示下拉框位置,咱們的公式編輯器應該能夠跑一跑了,這裏咱們給參數設置一下默認值:

//默認參數
var defaults = {
    triggerCharacter : '$',
    dropdownWidth:'150px'
};    

這裏咱們將特定字符設定爲 $,下拉框默認默認寬度爲150px,固然其中還有一些配角參數,不屑一提,看官們有興趣也能夠自行添加一些參數

測試以後發現是能夠正常使用的,那麼接下來就是下拉框顯示位置的問題了,這個想象好像不是秒秒鐘能解決的問題,怎麼辦?(吐槽:什麼怎麼辦?問百度啊~不要問我搜不到怎麼辦,由於我也不知道~)

這種時候不得不安慰本身:身爲菜鳥仍是有好處的,畢竟有無數前輩在前進的道路上閃閃發光~

搜~

掌聲,在這裏附上獲取光標像素左邊的原文連接以示感謝:http://blog.csdn.net/kingwolfofsky/article/details/6586029

剩下的就是整合啦,固然對於整合過程當中遇到的一點小問題沒必要訝異(都坐下,基本操做):

1,測試以後發現下拉框位置是動態出現了,可位置不對,偏移內心的理想位置有八百里。沒辦法,再去安靜的閱讀一下前輩的代碼,看完代碼,發現上文中 下拉框的位置是絕對定位的座標,這意味着什麼

呢?(我認可是後來才發現的~不測試不知道),這意味着下拉框的顯示位置不是相對於輸入框,而是相對於整個body,因此咱們應該把下拉框插入在body裏面:

$("body").after(_this.dropdown);

2,再測:發現位置大致上是對了,但仍是有偏移,再測測測~原來下拉框顯示位置還受輸入框 margin-left 和 margin-top 的影響,測試得出如下代碼:

複製代碼
// 調用 kingwolfofsky, 獲取光標座標
function show(elem) {  
    var p = kingwolfofsky.getInputPositon(elem);  
    var s = _this.dropdown.get(0); 
    var ttop = parseInt(_this.entertext.css("marginTop"));
    var tleft = parseInt(_this.entertext.css("marginLeft")) 
    console.log(ttop); 
    s.style.top = p.bottom-ttop+10+'px';  
    s.style.left = p.left-tleft + 'px';                    
} 
複製代碼

如今咱們須要一次完整的測試,調用:

複製代碼
$("#test").editTips({
    triggerCharacter : '$',
    dropdownWidth:'150px',  
    keyPressAction:function(temp,callbacktips){
        var arr_json;
        if( temp == "$" ){
            arr_json = ["$a","$ab","$b","$bb"]
        }
        if(temp && temp.indexOf("$a")== 0){
            arr_json = ["$a","$ab"];
        }
        else if(temp && temp.indexOf("$b")== 0){
            arr_json = ["$b","$bb"];
        }
        callbacktips(arr_json);
    }           
});
複製代碼

固然咱們這裏只是模擬返回數組,若是公式庫不是很大,能夠在前端完成,好比說本身建一個 json文件啥的~測試結果如圖:

所有 js 代碼

效果很ok,那麼接下來呢?看官息怒,我知道到了該出所有代碼的時候到了:

複製代碼
/*
*****公式編輯器*****
* 調用 editTips()方法
* editTips({
*        triggerCharacter:  觸發匹配字符 默認爲 "$"
*        textareaWidth:        輸入框寬度 默認 auto
*        textareaHeight:    輸入框高度 默認 auto
*        dropdownWidth:        下拉提示框寬度 默認150px
*        keyPressAction:function(temp,callbacktips){  
*        // 參數爲temp 返回 arr_json 數組 調用回調函數 callbacktips(arr_json)
*            var arr_json;
*            callbacktips(arr_json);
*        }            
*   });
* 
*/

(function ($) {
    $.fn.extend({
        "editTips": function (options) {
            var opts = $.extend({}, defaults, options); //使用jQuery.extend 覆蓋插件默認參數
            return    this.each(function () { //這裏的this 就是 jQuery對象
                    // 獲取輸入光標在頁面中的座標 返回left和top,bottom  
                    var kingwolfofsky = {  
                        getInputPositon: function (elem) {  
                            if (document.selection) {   //IE Support  
                                elem.focus();  
                                var Sel = document.selection.createRange();  
                                return {  
                                    left: Sel.boundingLeft,  
                                    top: Sel.boundingTop,  
                                    bottom: Sel.boundingTop + Sel.boundingHeight  
                                };  
                            } else {  
                                var that = this;  
                                var cloneDiv = '{$clone_div}', cloneLeft = '{$cloneLeft}', cloneFocus = '{$cloneFocus}', cloneRight = '{$cloneRight}';  
                                var none = '<span style="white-space:pre-wrap;"> </span>';  
                                var div = elem[cloneDiv] || document.createElement('div'), focus = elem[cloneFocus] || document.createElement('span');  
                                var text = elem[cloneLeft] || document.createElement('span');  
                                var offset = that._offset(elem), index = this._getFocus(elem), focusOffset = { left: 0, top: 0 };  
                      
                                if (!elem[cloneDiv]) {  
                                    elem[cloneDiv] = div, elem[cloneFocus] = focus;  
                                    elem[cloneLeft] = text;  
                                    div.appendChild(text);  
                                    div.appendChild(focus);  
                                    document.body.appendChild(div);  
                                    focus.innerHTML = '|';  
                                    focus.style.cssText = 'display:inline-block;width:0px;overflow:hidden;z-index:-100;word-wrap:break-word;word-break:break-all;';  
                                    div.className = this._cloneStyle(elem);  
                                    div.style.cssText = 'visibility:hidden;display:inline-block;position:absolute;z-index:-100;word-wrap:break-word;word-break:break-all;overflow:hidden;';  
                                };  
                                div.style.left = this._offset(elem).left + "px";  
                                div.style.top = this._offset(elem).top + "px";  
                                var strTmp = elem.value.substring(0, index).replace(/</g, '<').replace(/>/g, '>').replace(/\n/g, '<br/>').replace(/\s/g, none);  
                                text.innerHTML = strTmp;  
                      
                                focus.style.display = 'inline-block';  
                                try { focusOffset = this._offset(focus); } catch (e) { };  
                                focus.style.display = 'none';  
                                return {  
                                    left: focusOffset.left,  
                                    top: focusOffset.top,  
                                    bottom: focusOffset.bottom  
                                };  
                            }  
                        },
                            // 克隆元素樣式並返回類  
                        _cloneStyle: function (elem, cache) {  
                            if (!cache && elem['${cloneName}']) return elem['${cloneName}'];  
                            var className, name, rstyle = /^(number|string)$/;  
                            var rname = /^(content|outline|outlineWidth)$/; //Opera: content; IE8:outline && outlineWidth  
                            var cssText = [], sStyle = elem.style;  
                      
                            for (name in sStyle) {  
                                if (!rname.test(name)) {  
                                    val = this._getStyle(elem, name);  
                                    if (val !== '' && rstyle.test(typeof val)) { // Firefox 4  
                                        name = name.replace(/([A-Z])/g, "-$1").toLowerCase();  
                                        cssText.push(name);  
                                        cssText.push(':');  
                                        cssText.push(val);  
                                        cssText.push(';');  
                                    };  
                                };  
                            };  
                            cssText = cssText.join('');  
                            elem['${cloneName}'] = className = 'clone' + (new Date).getTime();  
                            this._addHeadStyle('.' + className + '{' + cssText + '}');  
                            return className;  
                        },  
                      
                        // 向頁頭插入樣式  
                        _addHeadStyle: function (content) {  
                            var style = this._style[document];  
                            if (!style) {  
                                style = this._style[document] = document.createElement('style');  
                                document.getElementsByTagName('head')[0].appendChild(style);  
                            };  
                            style.styleSheet && (style.styleSheet.cssText += content) || style.appendChild(document.createTextNode(content));  
                        },  
                        _style: {},  
                      
                        // 獲取最終樣式  
                        _getStyle: 'getComputedStyle' in window ? function (elem, name) {  
                            return getComputedStyle(elem, null)[name];  
                        } : function (elem, name) {  
                            return elem.currentStyle[name];  
                        },  
                            // 獲取光標在文本框的位置  
                        _getFocus: function (elem) {  
                            var index = 0;  
                            if (document.selection) {// IE Support  
                                elem.focus();  
                                var Sel = document.selection.createRange();  
                                if (elem.nodeName === 'TEXTAREA') {//textarea  
                                    var Sel2 = Sel.duplicate();  
                                    Sel2.moveToElementText(elem);  
                                    var index = -1;  
                                    while (Sel2.inRange(Sel)) {  
                                        Sel2.moveStart('character');  
                                        index++;  
                                    };  
                                }  
                                else if (elem.nodeName === 'INPUT') {// input  
                                    Sel.moveStart('character', -elem.value.length);  
                                    index = Sel.text.length;  
                                }  
                            }  
                            else if (elem.selectionStart || elem.selectionStart == '0') { // Firefox support  
                                index = elem.selectionStart;  
                            }  
                            return (index);  
                        },  
                      
                        // 獲取元素在頁面中位置  
                        _offset: function (elem) {  
                            var box = elem.getBoundingClientRect(), doc = elem.ownerDocument, body = doc.body, docElem = doc.documentElement;  
                            var clientTop = docElem.clientTop || body.clientTop || 0, clientLeft = docElem.clientLeft || body.clientLeft || 0;  
                            var top = box.top + (self.pageYOffset || docElem.scrollTop) - clientTop, left = box.left + (self.pageXOffset || docElem.scrollLeft) - clientLeft;  
                            return {  
                                left: left,  
                                top: top,  
                                right: left + box.width,  
                                bottom: top + box.height  
                            };  
                        }  
                    };  
                    // 文本框監聽事件 
                    var _this = this;                      
                      _this.entertext = $(this);
                      _this.dropdown = $('<ul class="editTips" style="display:none;"></ul>');
                      // 獲取到的彈出的下拉框的位置是絕對定位的座標,因此得把彈出的層放到body裏
                      $("body").after(_this.dropdown);                      
                    _this.dropdown.css({
                        'width':opts.dropdownWidth,
                        'position':'absolute',
                    });
                    $(this).css({
                          'position': 'relative',

                      });
                      
                    // 監聽輸入框
                    _this.dropdown.parent().on("keyup",this,function(event){                        
                        var nowTime =  window.sessionStorage.getItem('nowTime');
                        // 當前項索引
                        var n = _this.dropdown.find(".active").index();
                        // li 個數
                        var n_max = _this.dropdown.find("li").length;
                        // 注意 event在 firefox 中不能兼容,在方法中帶上event參數,以下聲明實現兼容
                        EVT = event || window.event;
                        if( EVT.keyCode == 38 ){
                            // 方向鍵控制 li 選項
                            if(n-1>=0){
                                _this.dropdown.find('li').eq(n-1).addClass("active").siblings().removeClass("active");
                            }
                            if( n == 0){
                                _this.dropdown.find('li').eq(n_max-1).addClass("active").siblings().removeClass("active");
                            }
                            return false;
                        }
                         // 禁止enter鍵換行
                        if( EVT.keyCode == 13 ){
                            return false;
                        }
                        if( EVT.keyCode == 40 ){
                            // 方向鍵控制 li 選項
                            if(n<n_max-1){
                                _this.dropdown.find('li').eq(n+1).addClass("active").siblings().removeClass("active");    
                            }
                            if( n+1 == n_max ){
                                _this.dropdown.find('li').eq(0).addClass("active").siblings().removeClass("active");
                            }
                            return false;
                        }
                        // 限制請求,輸入間隔不超過一秒時不觸發檢索事件發送請求
                        if( nowTime){
                            var oldTime = Date.now();
                            var nowTime = window.sessionStorage.getItem('nowTime');
                            var m =  parseInt((oldTime - nowTime)/1000);
                            if( m >= 1){                                
                                // 文本內容
                                var val = _this.entertext.val();
                                // 以空格切割文本返回數組
                                var arr_test = val.split(" ");
                                // 獲取數組最後一個元素
                                var temp = arr_test[arr_test.length-1];
                                // 切割最後一個元素 單字符元素 返回數組
                                var temp_type = temp.split("");
                                // 獲取數字第一個字符
                                var temp_cha = temp_type[0];
                                // 最後一個元素長度
                                var temp_len = temp.length;

                                var temp_dot = temp_type.lastIndexOf(".");
                                // 定義回調函數 callbacktips
                                var  callbacktips = function(arr_json){                            
                                     // 初始化 UL 
                                    _this.dropdown.find("li").remove();
                                    for( i=0;i<arr_json.length;i++ ){
                                        _this.dropdown.append('<li>'+arr_json[i]+'</li>');            
                                    };
                                    _this.dropdown.show();
                                    _this.dropdown.find("li:first-child").addClass("active");
                                    // 自定義樣式
                                    _this.dropdown.find("li").css({    
                                        'width':'100%',
                                    });
                                };
                                // 最後一個元素爲空值 
                                if( temp_len == 0 ){
                                    _this.dropdown.hide();
                                    _this.dropdown.find('li').remove();
                                }
                                // 爲特定字符 符合觸發條件 
                                if( temp_cha == opts.triggerCharacter ){                            
                                    if($.isFunction(opts.keyPressAction)){
                                        
                                        opts.keyPressAction(temp, function(arr_json){
                                            // 調用回調函數
                                            callbacktips(arr_json);
                                        
                                        });
                                    }
                                }else{
                                    _this.dropdown.hide();
                                    _this.dropdown.find('li').remove();
                                }                 
                            }
                        }
                        // 初始化第一次時間
                        window.sessionStorage.setItem('nowTime',Date.now());
                    });

                    // 切換當前項
                    _this.dropdown.on('mouseenter','li',function(){
                        $(this).addClass("active").siblings().removeClass("active");
                    });
                    // 阻止輸入過程當中 方向鍵盤的默認事件
                    _this.entertext.on("keydown",_this.entertext,function(event){
                        EVT = event || window.event;
                        if( EVT.keyCode == 38 ){
                            EVT.preventDefault();
                        }
                        if( EVT.keyCode == 40 ){
                            EVT.preventDefault();
                        }
                        // enter鍵選取對應的 li
                        if( EVT.keyCode == 13 ){
                            EVT.preventDefault();
                            var txt = _this.dropdown.find(".active").html();
                            var test_txt = _this.entertext.val();
                            var arr_change = test_txt.split(" ");
                            // 以空格切割文本返回數組
                            var arr_test = test_txt.split(" ");
                            // 獲取數組最後一個元素
                            var temp = arr_test[arr_test.length-1];
                            var temp_type = temp.split("");
                            var temp_dot = temp_type.lastIndexOf(".");
                            var n ;
                            temp_type.splice(temp_dot+1,temp_type.length-1-temp_dot,txt);
                            n = temp_type.join('');
                            arr_change.splice(arr_change.length-1,1,""+n);
                            _this.entertext.val(arr_change.join(" "));
                            _this.dropdown.hide();
                            _this.dropdown.find('li').remove();
                            }
                    });
                    // 點擊替換 重組val
                    $(document).on("click",'li',function(){
                        var txt = $(this).html();
                        var test_txt = _this.entertext.val();
                        var arr_change = test_txt.split(" ");
                        // 以空格切割文本返回數組
                        var arr_test = test_txt.split(" ");
                        // 獲取數組最後一個元素
                        var temp = arr_test[arr_test.length-1];
                        var temp_type = temp.split("");
                        var temp_dot = temp_type.lastIndexOf(".");
                        var n ;
                        temp_type.splice(temp_dot+1,temp_type.length-1-temp_dot,txt);
                        n = temp_type.join('');
                        arr_change.splice(arr_change.length-1,1,""+n);
                        _this.entertext.val(arr_change.join(" "));
                        _this.dropdown.hide();
                        _this.dropdown.find('li').remove();
                    });
                    // 調用獲取座標方法 show(elem)
                    $(this).keyup(function(){
                        show(this);
                    });                
                    // 調用 kingwolfofsky, 獲取光標座標
                    function show(elem) {  
                        var p = kingwolfofsky.getInputPositon(elem);  
                        var s = _this.dropdown.get(0); 
                        var ttop = parseInt(_this.entertext.css("marginTop"));
                        var tleft = parseInt(_this.entertext.css("marginLeft")) 
                        console.log(ttop); 
                        s.style.top = p.bottom-ttop+10+'px';  
                        s.style.left = p.left-tleft + 'px';                    
                    } 
                });
            }
        });
            //默認參數
var defaults = {
    triggerCharacter : '$',
    dropdownWidth:'150px'
};                    
})(window.jQuery);
複製代碼

調用插件

對呀,仍是上面的調用,沒問題的吧~

複製代碼
        $("#test").editTips({
            triggerCharacter : '$',
            dropdownWidth:'150px',  
            keyPressAction:function(temp,callbacktips){
                var arr_json;
                if( temp == "$" ){
                    arr_json = ["$a","$ab","$b","$bb"]
                }
                if(temp && temp.indexOf("$a")== 0){
                    arr_json = ["$a","$ab"];
                }
                else if(temp && temp.indexOf("$b")== 0){
                    arr_json = ["$b","$bb"];
                }
                callbacktips(arr_json);
            }           
        });
複製代碼

最後,複製粘貼上面的 html ,css ,js ,調用,它就是你的了~

此次分享就到這裏了,歡迎親們品鑑,有問題能夠私信或者留言哦~(偷笑:雖然我不必定看~看了不必定回~回了不必定能解決問題~)

 完整代碼:

<!DOCTYPE html>  
<html>  
<head>  
    <meta charset="UTF-8">
    <title>公式測試</title>


<style>


/* 編輯器下拉框相關樣式 */
table,tr,th,td{padding:0;margin:0;}
ul,li,textarea,input{text-decoration:none;list-style:none;margin:0;padding:0;box-sizing: border-box;}
input{ 
    outline:none;
 }
.editTips{
    padding:5px 0;
    border-radius: 0!important;
    box-shadow: 0 2px 4px rgba(0,0,0,.2);
    max-height: auto;
    margin:0;
    z-index:9999;
}
.editTips li{
    text-align:left;
    box-sizing:border-box;
    display:block;
    width:100%;
    line-height:1.42857143;
    margin:1px 0;
    padding:6px 11px;
    color:#333;
    cursor:pointer;
    overflow:hidden;
    text-overflow:ellipsis;
    white-space:nowrap;
    font-weight:400;
    line-height:1.42857143;
    border-bottom:solid 1px #e5e5e5;
    background:#e5e5e5;
}
.editTips li:last-child{
    border-bottom:none;
}
.active{ 
    background:#fee188!important; 
} 
.editTips li.active{ background:#fee188!important; }
textarea{
    text-decoration: none;
    list-style: none;
    margin: 0;
    padding: 0;
    display: block;
    box-sizing: border-box;
    width: 500px;
    height: 300px;
    margin-top: 100px;
    margin-left: 100px;
}



</style>    



</head>  
<body> 
    <textarea id="test" ></textarea>

</body>  
</html>


<script type="text/javascript" src="./jquery-1.8.3.min.js"></script>  

<script type="text/javascript">

/*
*****公式編輯器*****
* 調用 editTips()方法
* editTips({
*        triggerCharacter:  觸發匹配字符 默認爲 "$"
*        textareaWidth:        輸入框寬度 默認 auto
*        textareaHeight:    輸入框高度 默認 auto
*        dropdownWidth:        下拉提示框寬度 默認150px
*        keyPressAction:function(temp,callbacktips){  
*        // 參數爲temp 返回 arr_json 數組 調用回調函數 callbacktips(arr_json)
*            var arr_json;
*            callbacktips(arr_json);
*        }            
*   });
* 
*/

(function ($) {
    $.fn.extend({
        "editTips": function (options) {
            var opts = $.extend({}, defaults, options); //使用jQuery.extend 覆蓋插件默認參數
            return    this.each(function () { //這裏的this 就是 jQuery對象
                    // 獲取輸入光標在頁面中的座標 返回left和top,bottom  
                    var kingwolfofsky = {  
                        getInputPositon: function (elem) {  
                            if (document.selection) {   //IE Support  
                                elem.focus();  
                                var Sel = document.selection.createRange();  
                                return {  
                                    left: Sel.boundingLeft,  
                                    top: Sel.boundingTop,  
                                    bottom: Sel.boundingTop + Sel.boundingHeight  
                                };  
                            } else {  
                                var that = this;  
                                var cloneDiv = '{$clone_div}', cloneLeft = '{$cloneLeft}', cloneFocus = '{$cloneFocus}', cloneRight = '{$cloneRight}';  
                                var none = '<span style="white-space:pre-wrap;"> </span>';  
                                var div = elem[cloneDiv] || document.createElement('div'), focus = elem[cloneFocus] || document.createElement('span');  
                                var text = elem[cloneLeft] || document.createElement('span');  
                                var offset = that._offset(elem), index = this._getFocus(elem), focusOffset = { left: 0, top: 0 };  
                      
                                if (!elem[cloneDiv]) {  
                                    elem[cloneDiv] = div, elem[cloneFocus] = focus;  
                                    elem[cloneLeft] = text;  
                                    div.appendChild(text);  
                                    div.appendChild(focus);  
                                    document.body.appendChild(div);  
                                    focus.innerHTML = '|';  
                                    focus.style.cssText = 'display:inline-block;width:0px;overflow:hidden;z-index:-100;word-wrap:break-word;word-break:break-all;';  
                                    div.className = this._cloneStyle(elem);  
                                    div.style.cssText = 'visibility:hidden;display:inline-block;position:absolute;z-index:-100;word-wrap:break-word;word-break:break-all;overflow:hidden;';  
                                };  
                                div.style.left = this._offset(elem).left + "px";  
                                div.style.top = this._offset(elem).top + "px";  
                                var strTmp = elem.value.substring(0, index).replace(/</g, '<').replace(/>/g, '>').replace(/\n/g, '<br/>').replace(/\s/g, none);  
                                text.innerHTML = strTmp;  
                      
                                focus.style.display = 'inline-block';  
                                try { focusOffset = this._offset(focus); } catch (e) { };  
                                focus.style.display = 'none';  
                                return {  
                                    left: focusOffset.left,  
                                    top: focusOffset.top,  
                                    bottom: focusOffset.bottom  
                                };  
                            }  
                        },
                            // 克隆元素樣式並返回類  
                        _cloneStyle: function (elem, cache) {  
                            if (!cache && elem['${cloneName}']) return elem['${cloneName}'];  
                            var className, name, rstyle = /^(number|string)$/;  
                            var rname = /^(content|outline|outlineWidth)$/; //Opera: content; IE8:outline && outlineWidth  
                            var cssText = [], sStyle = elem.style;  
                      
                            for (name in sStyle) {  
                                if (!rname.test(name)) {  
                                    val = this._getStyle(elem, name);  
                                    if (val !== '' && rstyle.test(typeof val)) { // Firefox 4  
                                        name = name.replace(/([A-Z])/g, "-$1").toLowerCase();  
                                        cssText.push(name);  
                                        cssText.push(':');  
                                        cssText.push(val);  
                                        cssText.push(';');  
                                    };  
                                };  
                            };  
                            cssText = cssText.join('');  
                            elem['${cloneName}'] = className = 'clone' + (new Date).getTime();  
                            this._addHeadStyle('.' + className + '{' + cssText + '}');  
                            return className;  
                        },  
                      
                        // 向頁頭插入樣式  
                        _addHeadStyle: function (content) {  
                            var style = this._style[document];  
                            if (!style) {  
                                style = this._style[document] = document.createElement('style');  
                                document.getElementsByTagName('head')[0].appendChild(style);  
                            };  
                            style.styleSheet && (style.styleSheet.cssText += content) || style.appendChild(document.createTextNode(content));  
                        },  
                        _style: {},  
                      
                        // 獲取最終樣式  
                        _getStyle: 'getComputedStyle' in window ? function (elem, name) {  
                            return getComputedStyle(elem, null)[name];  
                        } : function (elem, name) {  
                            return elem.currentStyle[name];  
                        },  
                            // 獲取光標在文本框的位置  
                        _getFocus: function (elem) {  
                            var index = 0;  
                            if (document.selection) {// IE Support  
                                elem.focus();  
                                var Sel = document.selection.createRange();  
                                if (elem.nodeName === 'TEXTAREA') {//textarea  
                                    var Sel2 = Sel.duplicate();  
                                    Sel2.moveToElementText(elem);  
                                    var index = -1;  
                                    while (Sel2.inRange(Sel)) {  
                                        Sel2.moveStart('character');  
                                        index++;  
                                    };  
                                }  
                                else if (elem.nodeName === 'INPUT') {// input  
                                    Sel.moveStart('character', -elem.value.length);  
                                    index = Sel.text.length;  
                                }  
                            }  
                            else if (elem.selectionStart || elem.selectionStart == '0') { // Firefox support  
                                index = elem.selectionStart;  
                            }  
                            return (index);  
                        },  
                      
                        // 獲取元素在頁面中位置  
                        _offset: function (elem) {  
                            var box = elem.getBoundingClientRect(), doc = elem.ownerDocument, body = doc.body, docElem = doc.documentElement;  
                            var clientTop = docElem.clientTop || body.clientTop || 0, clientLeft = docElem.clientLeft || body.clientLeft || 0;  
                            var top = box.top + (self.pageYOffset || docElem.scrollTop) - clientTop, left = box.left + (self.pageXOffset || docElem.scrollLeft) - clientLeft;  
                            return {  
                                left: left,  
                                top: top,  
                                right: left + box.width,  
                                bottom: top + box.height  
                            };  
                        }  
                    };  
                    // 文本框監聽事件 
                    var _this = this;                      
                      _this.entertext = $(this);
                      _this.dropdown = $('<ul class="editTips" style="display:none;"></ul>');
                      // 獲取到的彈出的下拉框的位置是絕對定位的座標,因此得把彈出的層放到body裏
                      $("body").after(_this.dropdown);                      
                    _this.dropdown.css({
                        'width':opts.dropdownWidth,
                        'position':'absolute',
                    });
                    $(this).css({
                          'position': 'relative',

                      });
                      
                    // 監聽輸入框
                    _this.dropdown.parent().on("keyup",this,function(event){                        
                        var nowTime =  window.sessionStorage.getItem('nowTime');
                        // 當前項索引
                        var n = _this.dropdown.find(".active").index();
                        // li 個數
                        var n_max = _this.dropdown.find("li").length;
                        // 注意 event在 firefox 中不能兼容,在方法中帶上event參數,以下聲明實現兼容
                        EVT = event || window.event;
                        if( EVT.keyCode == 38 ){
                            // 方向鍵控制 li 選項
                            if(n-1>=0){
                                _this.dropdown.find('li').eq(n-1).addClass("active").siblings().removeClass("active");
                            }
                            if( n == 0){
                                _this.dropdown.find('li').eq(n_max-1).addClass("active").siblings().removeClass("active");
                            }
                            return false;
                        }
                         // 禁止enter鍵換行
                        if( EVT.keyCode == 13 ){
                            return false;
                        }
                        if( EVT.keyCode == 40 ){
                            // 方向鍵控制 li 選項
                            if(n<n_max-1){
                                _this.dropdown.find('li').eq(n+1).addClass("active").siblings().removeClass("active");    
                            }
                            if( n+1 == n_max ){
                                _this.dropdown.find('li').eq(0).addClass("active").siblings().removeClass("active");
                            }
                            return false;
                        }
                        // 限制請求,輸入間隔不超過一秒時不觸發檢索事件發送請求
                        if( nowTime){
                            var oldTime = Date.now();
                            var nowTime = window.sessionStorage.getItem('nowTime');
                            var m =  parseInt((oldTime - nowTime)/1000);
                            if( m >= 1){                                
                                // 文本內容
                                var val = _this.entertext.val();
                                // 以空格切割文本返回數組
                                var arr_test = val.split(" ");
                                // 獲取數組最後一個元素
                                var temp = arr_test[arr_test.length-1];
                                // 切割最後一個元素 單字符元素 返回數組
                                var temp_type = temp.split("");
                                // 獲取數字第一個字符
                                var temp_cha = temp_type[0];
                                // 最後一個元素長度
                                var temp_len = temp.length;

                                var temp_dot = temp_type.lastIndexOf(".");
                                // 定義回調函數 callbacktips
                                var  callbacktips = function(arr_json){                            
                                     // 初始化 UL 
                                    _this.dropdown.find("li").remove();
                                    for( i=0;i<arr_json.length;i++ ){
                                        _this.dropdown.append('<li>'+arr_json[i]+'</li>');            
                                    };
                                    _this.dropdown.show();
                                    _this.dropdown.find("li:first-child").addClass("active");
                                    // 自定義樣式
                                    _this.dropdown.find("li").css({    
                                        'width':'100%',
                                    });
                                };
                                // 最後一個元素爲空值 
                                if( temp_len == 0 ){
                                    _this.dropdown.hide();
                                    _this.dropdown.find('li').remove();
                                }
                                // 爲特定字符 符合觸發條件 
                                if( temp_cha == opts.triggerCharacter ){                            
                                    if($.isFunction(opts.keyPressAction)){
                                        
                                        opts.keyPressAction(temp, function(arr_json){
                                            // 調用回調函數
                                            callbacktips(arr_json);
                                        
                                        });
                                    }
                                }else{
                                    _this.dropdown.hide();
                                    _this.dropdown.find('li').remove();
                                }                 
                            }
                        }
                        // 初始化第一次時間
                        window.sessionStorage.setItem('nowTime',Date.now());
                    });

                    // 切換當前項
                    _this.dropdown.on('mouseenter','li',function(){
                        $(this).addClass("active").siblings().removeClass("active");
                    });
                    // 阻止輸入過程當中 方向鍵盤的默認事件
                    _this.entertext.on("keydown",_this.entertext,function(event){
                        EVT = event || window.event;
                        if( EVT.keyCode == 38 ){
                            EVT.preventDefault();
                        }
                        if( EVT.keyCode == 40 ){
                            EVT.preventDefault();
                        }
                        // enter鍵選取對應的 li
                        if( EVT.keyCode == 13 ){
                            EVT.preventDefault();
                            var txt = _this.dropdown.find(".active").html();
                            var test_txt = _this.entertext.val();
                            var arr_change = test_txt.split(" ");
                            // 以空格切割文本返回數組
                            var arr_test = test_txt.split(" ");
                            // 獲取數組最後一個元素
                            var temp = arr_test[arr_test.length-1];
                            var temp_type = temp.split("");
                            var temp_dot = temp_type.lastIndexOf(".");
                            var n ;
                            temp_type.splice(temp_dot+1,temp_type.length-1-temp_dot,txt);
                            n = temp_type.join('');
                            arr_change.splice(arr_change.length-1,1,""+n);
                            _this.entertext.val(arr_change.join(" "));
                            _this.dropdown.hide();
                            _this.dropdown.find('li').remove();
                            }
                    });
                    // 點擊替換 重組val
                    $(document).on("click",'li',function(){
                        var txt = $(this).html();
                        var test_txt = _this.entertext.val();
                        var arr_change = test_txt.split(" ");
                        // 以空格切割文本返回數組
                        var arr_test = test_txt.split(" ");
                        // 獲取數組最後一個元素
                        var temp = arr_test[arr_test.length-1];
                        var temp_type = temp.split("");
                        var temp_dot = temp_type.lastIndexOf(".");
                        var n ;
                        temp_type.splice(temp_dot+1,temp_type.length-1-temp_dot,txt);
                        n = temp_type.join('');
                        arr_change.splice(arr_change.length-1,1,""+n);
                        _this.entertext.val(arr_change.join(" "));
                        _this.dropdown.hide();
                        _this.dropdown.find('li').remove();
                    });
                    // 調用獲取座標方法 show(elem)
                    $(this).keyup(function(){
                        show(this);
                    });                
                    // 調用 kingwolfofsky, 獲取光標座標
                    function show(elem) {  
                        var p = kingwolfofsky.getInputPositon(elem);  
                        var s = _this.dropdown.get(0); 
                        var ttop = parseInt(_this.entertext.css("marginTop"));
                        var tleft = parseInt(_this.entertext.css("marginLeft")) 
                        console.log(ttop); 
                        s.style.top = p.bottom-ttop+10+'px';  
                        s.style.left = p.left-tleft + 'px';                    
                    } 
                });
            }
        });
            //默認參數
var defaults = {
    triggerCharacter : '$',
    dropdownWidth:'150px'
};                    
})(window.jQuery);




//調用,仍是上面的調用
       $("#test").editTips({
            triggerCharacter : '$',
            dropdownWidth:'150px',  
            keyPressAction:function(temp,callbacktips){
                var arr_json;
                if( temp == "$" ){
                    arr_json = ["$a","$ab","$b","$bb 副科級"]
                }
                if(temp && temp.indexOf("$a")== 0){
                    arr_json = ["$a","$ab"];
                }
                else if(temp && temp.indexOf("$b")== 0){
                    arr_json = ["$b","$bb  這個是說明"];
                }
                callbacktips(arr_json);
            }           
        });


</script> 
View Code

 

若是想使用的時候顯得高大上的感受,其中的不足和高級功能須要你本身去補充了。

 

出處:http://www.cnblogs.com/wbsndbf/p/7976300.html

相關文章
相關標籤/搜索