{ "info": [ { "message": "信息", "value": [ { "userName": "淳芸", "shortAccount": "chunyun", "userId": 20001 }, { "userName": "orion-01", "userName": "orion-01", "shortAccount": "orion-01", "userId": 20000 }, { "userName": "唐宏禹14", "shortAccount": "TANGHONGYU", "userId": 20011 }, { "userName": "唐宏禹13", "shortAccount": "tanghongyu", "userId": 20011 }, { "userName": "穆曉晨", "shortAccount": "mUXIAOCHEN", "userId": 20002 }, { "userName": "張歡引", "shortAccount": "zhanghuanyin", "userId": 20003 }, { "userName": "吳瓊", "shortAccount": "wuqiong", "userId": 20004 }, { "userName": "吳東鵬", "shortAccount": "wudongpeng", "userId": 20005 }, { "userName": "黃少鉛", "shortAccount": "huangshaoqian", "userId": 20006 }, { "userName": "胡運燕", "shortAccount": "yunyan", "userId": 20007 }, { "userName": "劉幸", "shortAccount": "liuxing", "userId": 20008 }, { "userName": "陳媛媛", "shortAccount": "CHENYUANYUAN", "userId": 20009 }, { "userName": "李大鵬", "shortAccount": "dapeng", "userId": 20010 }, { "userName": "唐宏禹", "shortAccount": "tanghongyu", "userId": 20011 }, { "userName": "曠東林", "shortAccount": "kuangdonglin", "userId": 20010 }, { "userName": "唐宏禹15", "shortAccount": "TANGhongyu", "userId": 20011 }, { "userName": "唐宏禹12", "shortAccount": "tanghongyu", "userId": 20011 }, { "userName": "唐宏禹11", "shortAccount": "TangHongYu", "userId": 20011 }, { "userName": "曠東林", "shortAccount": "kuangdonglin", "userId": 20010 }, { "userName": "唐宏禹10", "shortAccount": "tanghongyu", "userId": 20011 }, { "userName": "唐宏禹", "shortAccount": "tanghongyu", "userId": 20011 }, { "userName": "唐宏禹9", "shortAccount": "tanghongyu", "userId": 20011 }, { "userName": "唐宏禹8", "shortAccount": "tanghongyu", "userId": 20011 }, { "userName": "唐宏禹7", "shortAccount": "tanghongyu", "userId": 20011 }, { "userName": "曠東林", "shortAccount": "kuangdonglin", "userId": 20010 }, { "userName": "唐宏禹6", "shortAccount": "tanghongyu", "userId": 20011 }, { "userName": "唐宏禹5", "shortAccount": "tanghongyu", "userId": 20011 }, { "userName": "唐宏禹4", "shortAccount": "tanghongyu", "userId": 20011 }, { "userName": "唐宏禹3", "shortAccount": "tanghongyu", "userId": 20011 }, { "userName": "唐宏禹2", "shortAccount": "tanghongyu", "userId": 20011 }, { "userName": "唐宏禹1", "shortAccount": "tanghongyu", "userId": 20011 } ], "code": 200, "redirect": "" }] }
利用json-server模擬後臺,json-server使用詳解javascript
進入到模擬數據所在文件夾,執行下面的語句css
json-server 模擬數據文件 -p 啓動端口
例如:json-server data.json -p 8888html
啓動效果以下:前端
利用瀏覽器訪問獲得的響應以下:java
https://jquery.com/download/jquery
https://v3.bootcss.com/git
https://github.com/lzwme/bootstrap-suggest-plugingithub
引入jquery、boostrap的css和js、引入bootstrap-suggestweb
技巧01:編寫一個input和ul便可ajax
坑01:CSS類照着寫,由於bootstrap-suggest依賴須要用到bootstrap相關的樣式
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <title>Suggest使用案例</title> <meta name="description" content=""> <meta name="keywords" content=""> <link href="" rel="stylesheet"> <link rel="stylesheet" type="text/css" href="../css/common.css"> <!-- <link rel="stylesheet" type="text/css" href="../tool/bootstrap-3.3.7/dist/css/bootstrap-theme.min.css"> --> <link rel="stylesheet" type="text/css" href="../tool/bootstrap-3.3.7/dist/css/bootstrap.min.css"> <link rel="stylesheet" type="text/css" href="../tool/bootstrap-3.3.7/dist/css/bootstrap.css"> <script type="text/javascript" src="../tool/jquery/jquery-3.3.1.js"></script> <script type="text/javascript" src="../tool/bootstrap-3.3.7/dist/js/bootstrap.min.js"></script> <script type="text/javascript" src="../tool/bootstrap-suggest-plugin/dist/bootstrap-suggest.min.js"></script> <script type="text/javascript" src="../js/demo01_suggest.js"></script> </head> <body> <div class="panel panel-primary"> <div class="panel-heading">測試</div> <div class="panel-body"> <div class="input-group"> <input type="text" class="form-control" id="modalTest_input" autocomplete="off"> <div class="input-group-btn"> <button type="button" class="btn btn-default dropdown-toggle" data-toggle=""> <span class="caret"></span> </button> <ul class="dropdown-menu dropdown-menu-right" role="menu"></ul> </div> </div> </div> <div class="panel-footer"> <span id="Timer"></span> </div> </div> <hr class="hr"> </body> </html>
$().ready(function() { $("#modalTest_input").bsSuggest({ url: " http://localhost:8888/info", allowNoKeyword: true, // 是否容許非關鍵字搜索【默認true】 showHeader: true, // 是否顯示錶頭【默認true】 clearable: true, // 是否開啓清空數據【默認false】 showBtn: true, // 是否顯示下拉按鈕【默認false】 multiWord: true, //以分隔符號分割的多關鍵字支持 separator: ",", //多關鍵字支持時的分隔符 getDataMethod: 'url', // 請求url effectiveFields: ["userName", "userId", "shortAccount"], // 顯示的字段 effectiveFieldsAlias:{userName: "姓名", userId: "用戶ID", shortAccount: "帳號"}, // 字段標題 idField: "userId", // id字段 keyField: "userName", // input元素中的顯示字段 fnPreprocessKeyword: function(keyword) { //請求數據前,對輸入關鍵字做進一步處理方法。注意,應返回字符串 // alert("搜索關鍵字:" + keyword); return keyword; }, fnProcessData: function (result) { // url 獲取數據時,對數據的處理,做爲 fnGetData 的回調函數 var index, len, data = {value: []}; var json = result[0]; // 判斷是否有響應數據 if (!json || !json.value || json.value.length === 0) { console.log("沒有數據"); return false; } len = json.value.length; // 將獲取到的數據放到data.value中 for (index = 0; index < len; index++) { data.value.push(json.value[index]); } //字符串轉化爲 js 對象 【只要獲取到數據】 return data; } }).on('onDataRequestSuccess', function (e, result) { console.log('onDataRequestSuccess: ', result); }).on('onSetSelectValue', function (e, keyword, data) { console.log("選擇一個事後:"); console.log('onSetSelectValue: ', keyword, data); }).on('onUnsetSelectValue', function () { console.log('onUnsetSelectValue'); }).on('onShowDropdown', function (e, data) { console.log('onShowDropdown', e.target.value, data); }).on('onHideDropdown', function (e, data) { console.log('onHideDropdown', e.target.value, data); }); // 每間隔一秒刷新時間 setInterval("gettime()", 1000); //獲取時間並設置格式 gettime = function GetTime() { var mon, day, now, hour, min, ampm, time, str, tz, end, beg, sec; /* mon = new Array("Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"); */ mon = new Array("一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月"); /* day = new Array("Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"); */ day = new Array("週日", "週一", "週二", "週三", "週四", "週五", "週六"); now = new Date(); hour = now.getHours(); min = now.getMinutes(); sec = now.getSeconds(); if (hour < 10) { hour = "0" + hour; } if (min < 10) { min = "0" + min; } if (sec < 10) { sec = "0" + sec; } $("#Timer").html( now.getFullYear() + "年" + (now.getMonth() + 1) + "月" + now.getDate() + "日" + " " + hour + ":" + min + ":" + sec ); } })
原來的bootstrap-suggest框架僅僅支持get請求
須要進行put或者post請求,並且還須要向後臺傳值
技巧01:bootstrap-suggest中有一個ajax方法,該方法接收兩個參數
參數一 -> options -> 就是咱們在自定義js文件對bootstrap-suggest的一些配置信息
參數二 -> keyword -> 就是input標籤中輸入的值
/** * Bootstrap Search Suggest * @desc 這是一個基於 bootstrap 按鈕式下拉菜單組件的搜索建議插件,必須使用於按鈕式下拉菜單組件上。 * @author renxia <lzwy0820#qq.com> * @github https://github.com/lzwme/bootstrap-suggest-plugin.git * @since 2014-10-09 *=============================================================================== * (c) Copyright 2014-2016 http://lzw.me All Rights Reserved. ********************************************************************************/ (function (factory) { if (typeof define === "function" && define.amd) { define(['jquery'], factory); } else if (typeof exports === 'object' && typeof module === 'object') { factory(require('jquery')); } else if (window.jQuery) { factory(window.jQuery); } else { throw new Error('Not found jQuery.'); } })(function($) { var VERSION = 'VERSION_PLACEHOLDER'; var $window = $(window); var isIe = 'ActiveXObject' in window; // 用於對 IE 的兼容判斷 var inputLock; // 用於中文輸入法輸入時鎖定搜索 // ie 下和 chrome 51 以上瀏覽器版本,出現滾動條時不計算 padding var chromeVer = navigator.userAgent.match(/Chrome\/(\d+)/); if (chromeVer) { chromeVer = +chromeVer[1]; } var notNeedCalcPadding = isIe || chromeVer > 51; // 一些常量 var BSSUGGEST = 'bsSuggest'; var onDataRequestSuccess = 'onDataRequestSuccess'; var DISABLED = 'disabled'; var TRUE = true; var FALSE = false; /** * 錯誤處理 */ function handleError(e1, e2) { if (!window.console || !window.console.trace) { return; } console.trace(e1); if (e2) { console.trace(e2); } } /** * 獲取當前 tr 列的關鍵字數據 */ function getPointKeyword($list) { return $list.data(); } /** * 設置或獲取輸入框的 alt 值 */ function setOrGetAlt($input, val) { return val !== undefined ? $input.attr('alt', val) : $input.attr('alt'); } /** * 設置或獲取輸入框的 data-id 值 */ function setOrGetDataId($input, val) { return val !== (void 0) ? $input.attr('data-id', val) : $input.attr('data-id'); } /** * 設置選中的值 */ function setValue($input, keywords, options) { if (!keywords || !keywords.key) { return; } var separator = options.separator || ',', inputValList, inputIdList, dataId = setOrGetDataId($input); if (options && options.multiWord) { inputValList = $input.val().split(separator); inputValList[inputValList.length - 1] = keywords.key; //多關鍵字檢索支持設置id --- 存在 bug,不建議使用 if (!dataId) { inputIdList = [keywords.id]; } else { inputIdList = dataId.split(separator); inputIdList.push(keywords.id); } setOrGetDataId($input, inputIdList.join(separator)) .val(inputValList.join(separator)) .focus(); } else { setOrGetDataId($input, keywords.id || '').val(keywords.key).focus(); } $input.data('pre-val', $input.val()) .trigger('onSetSelectValue', [keywords, (options.data.value || options._lastData.value)[keywords.index]]); } /** * 調整選擇菜單位置 * @param {Object} $input * @param {Object} $dropdownMenu * @param {Object} options */ function adjustDropMenuPos($input, $dropdownMenu, options) { if (!$dropdownMenu.is(':visible')) { return; } var $parent = $input.parent(); var parentHeight = $parent.height(); var parentWidth = $parent.width(); if (options.autoDropup) { setTimeout(function() { var offsetTop = $input.offset().top; var winScrollTop = $window.scrollTop(); var menuHeight = $dropdownMenu.height(); if ( // 自動判斷菜單向上展開 ($window.height() + winScrollTop - offsetTop) < menuHeight && // 假如向下會撐長頁面 offsetTop > (menuHeight + winScrollTop) // 並且向上不會撐到頂部 ) { $parent.addClass('dropup'); } else { $parent.removeClass('dropup'); } }, 10); } // 列表對齊方式 var dmcss = {}; if (options.listAlign === 'left') { dmcss = { 'left': $input.siblings('div').width() - parentWidth, 'right': 'auto' }; } else if (options.listAlign === 'right') { dmcss = { 'left': 'auto', 'right': 0 }; } // ie 下,不顯示按鈕時的 top/bottom if (isIe && !options.showBtn) { if (!$parent.hasClass('dropup')) { dmcss.top = parentHeight; dmcss.bottom = 'auto'; } else { dmcss.top = 'auto'; dmcss.bottom = parentHeight; } } // 是否自動最小寬度 if (!options.autoMinWidth) { dmcss.minWidth = parentWidth; } /* else { dmcss['width'] = 'auto'; }*/ $dropdownMenu.css(dmcss); return $input; } /** * 設置輸入框背景色 * 當設置了 indexId,而輸入框的 data-id 爲空時,輸入框加載警告色 */ function setBackground($input, options) { var inputbg, bg, warnbg; if ((options.indexId === -1 && !options.idField) || options.multiWord) { return $input; } bg = options.inputBgColor; warnbg = options.inputWarnColor; var curVal = $input.val(); var preVal = $input.data('pre-val'); if (setOrGetDataId($input) || !curVal) { $input.css('background', bg || ''); if (!curVal && preVal) { $input.trigger('onUnsetSelectValue').data('pre-val', ''); } return $input; } inputbg = $input.css('backgroundColor').replace(/ /g, '').split(',', 3).join(','); // 自由輸入的內容,設置背景色 if (!~warnbg.indexOf(inputbg)) { $input.trigger('onUnsetSelectValue') // 觸發取消data-id事件 .data('pre-val', '') .css('background', warnbg); } return $input; } /** * 調整滑動條 */ function adjustScroll($input, $dropdownMenu, options) { // 控制滑動條 var $hover = $input.parent().find('tbody tr.' + options.listHoverCSS), pos, maxHeight; if ($hover.length) { pos = ($hover.index() + 3) * $hover.height(); maxHeight = +$dropdownMenu.css('maxHeight').replace('px', ''); if (pos > maxHeight || $dropdownMenu.scrollTop() > maxHeight) { pos = pos - maxHeight; } else { pos = 0; } $dropdownMenu.scrollTop(pos); } } /** * 解除全部列表 hover 樣式 */ function unHoverAll($dropdownMenu, options) { $dropdownMenu.find('tr.' + options.listHoverCSS).removeClass(options.listHoverCSS); } /** * 驗證 $input 對象是否符合條件 * 1. 必須爲 bootstrap 下拉式菜單 * 2. 必須未初始化過 */ function checkInput($input, $dropdownMenu, options) { if ( !$dropdownMenu.length || // 過濾非 bootstrap 下拉式菜單對象 $input.data(BSSUGGEST) // 是否已經初始化的檢測 ) { return FALSE; } $input.data(BSSUGGEST, { options: options }); return TRUE; } /** * 數據格式檢測 * 檢測 ajax 返回成功數據或 data 參數數據是否有效 * data 格式:{"value": [{}, {}...]} */ function checkData(data) { var isEmpty = TRUE, o; for (o in data) { if (o === 'value') { isEmpty = FALSE; break; } } if (isEmpty) { handleError('返回數據格式錯誤!'); return FALSE; } if (!data.value.length) { // handleError('返回數據爲空!'); return FALSE; } return data; } /** * 判斷字段名是否在 options.effectiveFields 配置項中 * @param {String} field 要判斷的字段名 * @param {Object} options * @return {Boolean} effectiveFields 爲空時始終返回 true */ function inEffectiveFields(field, options) { var effectiveFields = options.effectiveFields; return !(field === '__index' || effectiveFields.length && !~$.inArray(field, effectiveFields)); } /** * 判斷字段名是否在 options.searchFields 搜索字段配置中 */ function inSearchFields(field, options) { return ~$.inArray(field, options.searchFields); } /** * 經過下拉菜單顯示提示文案 */ function showTip(tip, $input, $dropdownMenu, options) { $dropdownMenu.html('<div style="padding:10px 5px 5px">' + tip + '</div>').show(); adjustDropMenuPos($input, $dropdownMenu, options); } /** * 下拉列表刷新 * 做爲 fnGetData 的 callback 函數調用 */ function refreshDropMenu($input, data, options) { var $dropdownMenu = $input.parent().find('ul:eq(0)'), len, i, field, index = 0, tds, html = ['<table class="table table-condensed table-sm" style="margin:0">'], idValue, keyValue; // 做爲輸入框 data-id 和內容的字段值 var dataList = data.value; if (!data || !dataList || !(len = dataList.length)) { if (options.emptyTip) { showTip(options.emptyTip, $input, $dropdownMenu, options); } else { $dropdownMenu.empty().hide(); } return $input; } // 相同數據,不用繼續渲染了 if ( options._lastData && JSON.stringify(options._lastData) === JSON.stringify(data) && $dropdownMenu.find('tr').length === len ) { $dropdownMenu.show(); return adjustDropMenuPos($input, $dropdownMenu, options); // return $input; } options._lastData = data; // 生成表頭 if (options.showHeader) { html.push('<thead><tr>'); for (field in dataList[0]) { if (!inEffectiveFields(field, options)) { continue; } html.push('<th>', (options.effectiveFieldsAlias[field] || field), index === 0 ? ('(' + len + ')') : '' , // 表頭第一列記錄總數 '</th>'); index++; } html.push('</tr></thead>'); } html.push('<tbody>'); // console.log(data, len); // 按列加數據 var dataI; for (i = 0; i < len; i++) { index = 0; tds = []; dataI = dataList[i]; idValue = dataI[options.idField] || ''; keyValue = dataI[options.keyField] || ''; for (field in dataI) { // 標記做爲 value 和 做爲 id 的值 if (!keyValue && options.indexKey === index) { keyValue = dataI[field]; } if (!idValue && options.indexId === index) { idValue = dataI[field]; } index++; // 列表中只顯示有效的字段 if (inEffectiveFields(field, options)) { tds.push('<td data-name="', field, '">', dataI[field], '</td>'); } } html.push('<tr data-index="', (dataI.__index || i), '" data-id="', idValue, '" data-key="', keyValue, '">', tds.join(''), '</tr>'); } html.push('</tbody></table>'); $dropdownMenu.html(html.join('')).show(); // scrollbar 存在時,延時到動畫結束時調整 padding setTimeout(function() { if (notNeedCalcPadding) { return; } var $table = $dropdownMenu.find('table:eq(0)'), pdr = 0, mgb = 0; if ( $dropdownMenu.height() < $table.height() && +$dropdownMenu.css('minWidth').replace('px', '') < $dropdownMenu.width() ) { pdr = 18; mgb = 20; } $dropdownMenu.css('paddingRight', pdr); $table.css('marginBottom', mgb); }, 301); adjustDropMenuPos($input, $dropdownMenu, options); return $input; } /** * ajax 獲取數據 * @param {Object} options 就是自定義js文件的一些配置參數 keyword 就是搜索關鍵字母 * @return {Object} */ function ajax(options, keyword) { keyword = keyword || ''; // console.log(options); // 打印信息 var preAjax = options._preAjax; if (preAjax && preAjax.abort && preAjax.readyState !== 4) { // console.log('abort pre ajax'); preAjax.abort(); } // 指定了非GET請求方式 var type = options.type; if (type && type !='GET' && type != 'get') { if(options.param.keyword){ options.param.keyword = keyword; }else{ options.param['keyword'] = keyword; } var ajaxParam = { type: type, dataType: options.jsonp ? 'jsonp' : 'json', timeout: 5000, data: JSON.stringify(options.param) }; } else { var ajaxParam = { type: 'GET', dataType: options.jsonp ? 'jsonp' : 'json', timeout: 5000, }; } // jsonp if (options.jsonp) { ajaxParam.jsonp = options.jsonp; } // 自定義 ajax 請求參數生成方法 var adjustAjaxParam, fnAdjustAjaxParam = options.fnAdjustAjaxParam; if ($.isFunction(fnAdjustAjaxParam)) { adjustAjaxParam = fnAdjustAjaxParam(keyword, options); // options.fnAdjustAjaxParam 返回false,則終止 ajax 請求 if (FALSE === adjustAjaxParam) { return; } $.extend(ajaxParam, adjustAjaxParam); } // url 調整 ajaxParam.url = function() { if (!keyword || ajaxParam.data) { return ajaxParam.url || options.url; } var type = '?'; if (/=$/.test(options.url)) { type = ''; } else if (/\?/.test(options.url)) { type = '&'; } return options.url + type + encodeURIComponent(keyword); }(); return options._preAjax = $.ajax(ajaxParam).done(function(result) { options.data = options.fnProcessData(result); }).fail(function(err) { if (options.fnAjaxFail) { options.fnAjaxFail(err, options); } }); } /** * 檢測 keyword 與 value 是否存在互相包含 * @param {String} keyword 用戶輸入的關鍵字 * @param {String} key 匹配字段的 key * @param {String} value key 字段對應的值 * @param {Object} options * @return {Boolean} 包含/不包含 */ function isInWord(keyword, key, value, options) { value = $.trim(value); if (options.ignorecase) { keyword = keyword.toLocaleLowerCase(); value = value.toLocaleLowerCase(); } return value && (inEffectiveFields(key, options) || inSearchFields(key, options)) && // 必須在有效的搜索字段中 ( ~value.indexOf(keyword) || // 匹配值包含關鍵字 options.twoWayMatch && ~keyword.indexOf(value) // 關鍵字包含匹配值 ); } /** * 經過 ajax 或 json 參數獲取數據 */ function getData(keyword, $input, callback, options) { var data, validData, filterData = { value: [] }, i, key, len, fnPreprocessKeyword = options.fnPreprocessKeyword; keyword = keyword || ''; // 獲取數據前對關鍵字預處理方法 if ($.isFunction(fnPreprocessKeyword)) { keyword = fnPreprocessKeyword(keyword, options); } // 給了url參數,則從服務器 ajax 請求 // console.log(options.url + keyword); if (options.url) { var timer; if (options.searchingTip) { timer = setTimeout(function() { showTip(options.searchingTip, $input, $input.parent().find('ul'), options); }, 600); } ajax(options, keyword).done(function(result) { callback($input, options.data, options); // 爲 refreshDropMenu $input.trigger(onDataRequestSuccess, result); if (options.getDataMethod === 'firstByUrl') { options.url = null; } }).always(function() { timer && clearTimeout(timer); }); } else { // 沒有給出 url 參數,則從 data 參數獲取 data = options.data; validData = checkData(data); // 本地的 data 數據,則在本地過濾 if (validData) { if (keyword) { // 輸入不爲空時則進行匹配 len = data.value.length; for (i = 0; i < len; i++) { for (key in data.value[i]) { if ( data.value[i][key] && isInWord(keyword, key, data.value[i][key] + '', options) ) { filterData.value.push(data.value[i]); filterData.value[filterData.value.length - 1].__index = i; break; } } } } else { filterData = data; } } callback($input, filterData, options); } // else } /** * 數據處理 * url 獲取數據時,對數據的處理,做爲 fnGetData 以後的回調處理 */ function processData(data) { return checkData(data); } /** * 取得 clearable 清除按鈕 */ function getIClear($input, options) { var $iClear = $input.prev('i.clearable'); // 是否可清除已輸入的內容(添加清除按鈕) if (options.clearable && !$iClear.length) { $iClear = $('<i class="clearable glyphicon glyphicon-remove"></i>') .prependTo($input.parent()); } return $iClear.css({ position: 'absolute', top: 12, // right: options.showBtn ? Math.max($input.next('.input-group-btn').width(), 33) + 2 : 12, zIndex: 4, cursor: 'pointer', fontSize: 12 }).hide(); } /** * 默認的配置選項 * @type {Object} */ var defaultOptions = { url: null, // 請求數據的 URL 地址 jsonp: null, // 設置此參數名,將開啓jsonp功能,不然使用json數據結構 data: { value: [] }, // 提示所用的數據,注意格式 indexId: 0, // 每組數據的第幾個數據,做爲input輸入框的 data-id,設爲 -1 且 idField 爲空則不設置此值 indexKey: 0, // 每組數據的第幾個數據,做爲input輸入框的內容 idField: '', // 每組數據的哪一個字段做爲 data-id,優先級高於 indexId 設置(推薦) keyField: '', // 每組數據的哪一個字段做爲輸入框內容,優先級高於 indexKey 設置(推薦) /* 搜索相關 */ autoSelect: TRUE, // 鍵盤向上/下方向鍵時,是否自動選擇值 allowNoKeyword: TRUE, // 是否容許無關鍵字時請求數據 getDataMethod: 'firstByUrl', // 獲取數據的方式,url:一直從url請求;data:從 options.data 獲取;firstByUrl:第一次從Url獲取所有數據,以後從options.data獲取 delayUntilKeyup: FALSE, // 獲取數據的方式 爲 firstByUrl 時,是否延遲到有輸入時才請求數據 ignorecase: FALSE, // 前端搜索匹配時,是否忽略大小寫 effectiveFields: [], // 有效顯示於列表中的字段,非有效字段都會過濾,默認所有有效。 effectiveFieldsAlias: {}, // 有效字段的別名對象,用於 header 的顯示 searchFields: [], // 有效搜索字段,從前端搜索過濾數據時使用,但不必定顯示在列表中。effectiveFields 配置字段也會用於搜索過濾 twoWayMatch: TRUE, // 是否雙向匹配搜索。爲 true 即輸入關鍵字包含或包含於匹配字段均認爲匹配成功,爲 false 則輸入關鍵字包含於匹配字段認爲匹配成功 multiWord: FALSE, // 以分隔符號分割的多關鍵字支持 separator: ',', // 多關鍵字支持時的分隔符,默認爲半角逗號 delay: 300, // 搜索觸發的延時時間間隔,單位毫秒 emptyTip: '', // 查詢爲空時顯示的內容,可爲 html searchingTip: '搜索中...', // ajax 搜索時顯示的提示內容,當搜索時間較長時給出正在搜索的提示 /* UI */ autoDropup: FALSE, // 選擇菜單是否自動判斷向上展開。設爲 true,則當下拉菜單高度超過窗體,且向上方向不會被窗體覆蓋,則選擇菜單向上彈出 autoMinWidth: FALSE, // 是否自動最小寬度,設爲 false 則最小寬度不小於輸入框寬度 showHeader: FALSE, // 是否顯示選擇列表的 header。爲 true 時,有效字段大於一列則顯示錶頭 showBtn: TRUE, // 是否顯示下拉按鈕 inputBgColor: '', // 輸入框背景色,當與容器背景色不一樣時,可能須要該項的配置 inputWarnColor: 'rgba(255,0,0,.1)', // 輸入框內容不是下拉列表選擇時的警告色 listStyle: { 'padding-top': 0, 'max-height': '375px', 'max-width': '800px', 'overflow': 'auto', 'width': 'auto', 'transition': '0.3s', '-webkit-transition': '0.3s', '-moz-transition': '0.3s', '-o-transition': '0.3s' }, // 列表的樣式控制 listAlign: 'left', // 提示列表對齊位置,left/right/auto listHoverStyle: 'background: #07d; color:#fff', // 提示框列表鼠標懸浮的樣式 listHoverCSS: 'jhover', // 提示框列表鼠標懸浮的樣式名稱 clearable: FALSE, // 是否可清除已輸入的內容 /* key */ keyLeft: 37, // 向左方向鍵,不一樣的操做系統可能會有差異,則自行定義 keyUp: 38, // 向上方向鍵 keyRight: 39, // 向右方向鍵 keyDown: 40, // 向下方向鍵 keyEnter: 13, // 回車鍵 /* methods */ fnProcessData: processData, // 格式化數據的方法,返回數據格式參考 data 參數 fnGetData: getData, // 獲取數據的方法,無特殊需求通常不做設置 fnAdjustAjaxParam: null, // 調整 ajax 請求參數方法,用於更多的請求配置需求。如對請求關鍵字做進一步處理、修改超時時間等 fnPreprocessKeyword: null, // 搜索過濾數據前,對輸入關鍵字做進一步處理方法。注意,應返回字符串 fnAjaxFail: null, // ajax 失敗時回調方法 }; var methods = { init: function(options) { // 參數設置 var self = this; options = options || {}; // 默認配置有效顯示字段多於一個,則顯示列表表頭,不然不顯示 if (undefined === options.showHeader && options.effectiveFields && options.effectiveFields.length > 1) { options.showHeader = TRUE; } options = $.extend(TRUE, {}, defaultOptions, options); // 舊的方法兼容 if (options.processData) { options.fnProcessData = options.processData; } if (options.getData) { options.fnGetData = options.getData; } if (options.getDataMethod === 'firstByUrl' && options.url && !options.delayUntilKeyup) { ajax(options).done(function(result) { options.url = null; self.trigger(onDataRequestSuccess, result); }); } // 鼠標滑動到條目樣式 if (!$('#' + BSSUGGEST).length) { $('head:eq(0)').append('<style id="' + BSSUGGEST + '">.' + options.listHoverCSS + '{' + options.listHoverStyle + '}</style>'); } return self.each(function() { var $input = $(this), $parent = $input.parent(), $iClear = getIClear($input, options), isMouseenterMenu, keyupTimer, // keyup 與 input 事件延時定時器 $dropdownMenu = $parent.find('ul:eq(0)'); // 驗證輸入框對象是否符合條件 if (!checkInput($input, $dropdownMenu, options)) { console.warn('不是一個標準的 bootstrap 下拉式菜單或已初始化:', $input); return; } // 是否顯示 button 按鈕 if (!options.showBtn) { $input.css('borderRadius', 4); $parent.css('width', '100%') .find('.btn:eq(0)').hide(); } // 移除 disabled 類,並禁用自動完成 $input.removeClass(DISABLED).prop(DISABLED, FALSE).attr('autocomplete', 'off'); // dropdown-menu 增長修飾 $dropdownMenu.css(options.listStyle); // 默認背景色 if (!options.inputBgColor) { options.inputBgColor = $input.css('backgroundColor'); } // 開始事件處理 $input.on('keydown', function(event) { var currentList, tipsKeyword; // 提示列表上被選中的關鍵字 // 當提示層顯示時纔對鍵盤事件處理 if (!$dropdownMenu.is(':visible')) { setOrGetDataId($input, ''); return; } currentList = $dropdownMenu.find('.' + options.listHoverCSS); tipsKeyword = ''; // 提示列表上被選中的關鍵字 unHoverAll($dropdownMenu, options); if (event.keyCode === options.keyDown) { // 若是按的是向下方向鍵 if (!currentList.length) { // 若是提示列表沒有一個被選中,則將列表第一個選中 tipsKeyword = getPointKeyword($dropdownMenu.find('tbody tr:first').mouseover()); } else if (!currentList.next().length) { // 若是是最後一個被選中,則取消選中,便可認爲是輸入框被選中,並恢復輸入的值 if (options.autoSelect) { setOrGetDataId($input, '').val(setOrGetAlt($input)); } } else { // 選中下一行 tipsKeyword = getPointKeyword(currentList.next().mouseover()); } // 控制滑動條 adjustScroll($input, $dropdownMenu, options); if (!options.autoSelect) { return; } } else if (event.keyCode === options.keyUp) { // 若是按的是向上方向鍵 if (!currentList.length) { tipsKeyword = getPointKeyword($dropdownMenu.find('tbody tr:last').mouseover()); } else if (!currentList.prev().length) { if (options.autoSelect) { setOrGetDataId($input, '').val(setOrGetAlt($input)); } } else { // 選中前一行 tipsKeyword = getPointKeyword(currentList.prev().mouseover()); } // 控制滑動條 adjustScroll($input, $dropdownMenu, options); if (!options.autoSelect) { return; } } else if (event.keyCode === options.keyEnter) { tipsKeyword = getPointKeyword(currentList); $dropdownMenu.hide(); // .empty(); } else { setOrGetDataId($input, ''); } // 設置值 tipsKeyword // console.log(tipsKeyword); setValue($input, tipsKeyword, options); }).on('compositionstart', function(event) { // 中文輸入開始,鎖定 // console.log('compositionstart'); inputLock = TRUE; }).on('compositionend', function(event) { // 中文輸入結束,解除鎖定 // console.log('compositionend'); inputLock = FALSE; }).on('keyup input paste', function(event) { var word; if (event.keyCode) { setBackground($input, options); } // 若是彈起的鍵是回車、向上或向下方向鍵則返回 if (~$.inArray(event.keyCode, [options.keyDown, options.keyUp, options.keyEnter])) { $input.val($input.val()); // 讓鼠標輸入跳到最後 return; } clearTimeout(keyupTimer); keyupTimer = setTimeout(function() { // console.log('input keyup', event); // 鎖定狀態,返回 if (inputLock) { return; } word = $input.val(); // 若輸入框值沒有改變則返回 if ($.trim(word) && word === setOrGetAlt($input)) { return; } // 當按下鍵以前記錄輸入框值,以方便查看鍵彈起時值有沒有變 setOrGetAlt($input, word); if (options.multiWord) { word = word.split(options.separator).reverse()[0]; } // 是否容許空數據查詢 if (!word.length && !options.allowNoKeyword) { return; } options.fnGetData($.trim(word), $input, refreshDropMenu, options); }, options.delay || 300); }).on('focus', function() { // console.log('input focus'); adjustDropMenuPos($input, $dropdownMenu, options); }).on('blur', function() { if (!isMouseenterMenu) { // 不是進入下拉列表狀態,則隱藏列表 $dropdownMenu.css('display', ''); } }).on('click', function() { // console.log('input click'); var word = $input.val(); if ( $.trim(word) && word === setOrGetAlt($input) && $dropdownMenu.find('table tr').length ) { return $dropdownMenu.show(); } // if ($dropdownMenu.css('display') !== 'none') { if ($dropdownMenu.is(':visible')) { return; } if (options.multiWord) { word = word.split(options.separator).reverse()[0]; } // 是否容許空數據查詢 if (!word.length && !options.allowNoKeyword) { return; } // console.log('word', word); options.fnGetData($.trim(word), $input, refreshDropMenu, options); }); // 下拉按鈕點擊時 $parent.find('.btn:eq(0)').attr('data-toggle', '').click(function() { var display = 'none'; // if ($dropdownMenu.is(':visible')) { if ($dropdownMenu.css('display') === display) { display = 'block'; if (options.url) { $input.click().focus(); if (!$dropdownMenu.find('tr').length) { display = 'none'; } } else { // 不以 keyword 做爲過濾,展現全部的數據 refreshDropMenu($input, options.data, options); } } $dropdownMenu.css('display', display); return FALSE; }); // 列表中滑動時,輸入框失去焦點 $dropdownMenu.mouseenter(function() { // console.log('mouseenter') isMouseenterMenu = 1; $input.blur(); }).mouseleave(function() { // console.log('mouseleave') isMouseenterMenu = 0; $input.focus(); }).on('mouseenter', 'tbody tr', function() { // 行上的移動事件 unHoverAll($dropdownMenu, options); $(this).addClass(options.listHoverCSS); return FALSE; // 阻止冒泡 }) .on('mousedown', 'tbody tr', function() { var keywords = getPointKeyword($(this)); setValue($input, keywords, options); setOrGetAlt($input, keywords.key); setBackground($input, options); $dropdownMenu.hide(); }); // 存在清空按鈕 if ($iClear.length) { $iClear.click(function () { setOrGetDataId($input, '').val(''); setBackground($input, options); }); $parent.mouseenter(function() { if (!$input.prop(DISABLED)) { $iClear.css('right', options.showBtn ? Math.max($input.next('.input-group-btn').width(), 33) + 2 : 12) .show(); } }).mouseleave(function() { $iClear.hide(); }); } }); }, show: function() { return this.each(function() { $(this).click(); }); }, hide: function() { return this.each(function() { $(this).parent().find('ul:eq(0)').css('display', ''); }); }, disable: function() { return this.each(function() { $(this).attr(DISABLED, TRUE) .parent().find('.btn:eq(0)').prop(DISABLED, TRUE); }); }, enable: function() { return this.each(function() { $(this).attr(DISABLED, FALSE) .parent().find('.btn:eq(0)').prop(DISABLED, FALSE); }); }, destroy: function() { return this.each(function() { $(this).off().removeData(BSSUGGEST).removeAttr('style') .parent().find('.btn:eq(0)').off().show().attr('data-toggle', 'dropdown').prop(DISABLED, FALSE) // .addClass(DISABLED); .next().css('display', '').off(); }); }, version: function() { return VERSION; } }; $.fn[BSSUGGEST] = function(options) { // 方法判斷 if (typeof options === 'string' && methods[options]) { var inited = TRUE; this.each(function() { if (!$(this).data(BSSUGGEST)) { return inited = FALSE; } }); // 只要有一個未初始化,則所有都不執行方法,除非是 init 或 version if (!inited && 'init' !== options && 'version' !== options) { return this; } // 若是是方法,則參數第一個爲函數名,從第二個開始爲函數參數 return methods[options].apply(this, [].slice.call(arguments, 1)); } else { // 調用初始化方法 return methods.init.apply(this, arguments); } } });
技巧01:獲取get請求的方式和原來的同樣
技巧01:在bootstrap中的ajax方法中打印options來進行觀察配置信息
技巧01:若是配置了type就必須配置param,並且裏面params中不用包含一個keyword做爲鍵的KV鍵值對,由於在bootstrap-suggest中會將input中輸入的值做爲keyword賦值給param的keyword屬性【PS: 在js中爲某個對象添加屬性和值是直接寫就行啦,不用提早聲明;param.keyword=xxx,就至關於給param新增了一個keyword屬性,並且將xxx賦值給這個屬性】
技巧02:第一次點擊input框時,控制檯打印出來的信息中沒有keyword的信息,由於此時input中尚未任何數據,在input中輸入數據後就有數據啦
技巧03:在input中輸入信息後就會自動向後臺發送post請求,並將相關數據經過請求體發送到後臺;可是這時候控制會報一個500錯誤,由於咱們是使用json-server模擬後臺數據,因此會報錯;在實際應用中鏈接正確的後臺就不會報錯啦
同樣的配方,照着套路來就行啦
技巧01:若是須要配置jsonp,就配置成 jsonp: "jsop" ;不然就不要作jsonp配置啦
技巧02:控制檯一樣會報一個錯,由於咱們使用的是json-server模擬服務器
選擇一條記錄後,input標籤會出現關鍵字字段對應的值
技巧01:能夠在onSetSelectValue進行一些選中一條記錄後的邏輯操做,例如,向後臺發送請求等等
技巧02:能夠在onSetSelectValue方法中獲取到配置的ID字段和關鍵字字段對應的值以及選中後的整條記錄的值,例如
待更新...2018年8月15日22:28:59
本博文源碼:點擊前往
https://www.npmjs.com/package/bootstrap-suggest-plugin