改造 Combo Select支持伺服器端模糊搜索

来源:https://www.cnblogs.com/codestory/archive/2018/01/02/8178409.html
-Advertisement-
Play Games

使用combo select完善原始select的功能,當碰到大數據量時,反應很慢,因為數據是一次性載入。 嘗試修改控制項的數據載入方案,變更為伺服器端模糊搜索,降低數據量,降低頁面響應時間。 ...


項目中使用了 combo select,為預設的select增加模糊搜索的功能,一直運行得很好。

1    碰到的問題

但最近碰到一個大數據量的select:初始化載入的數據項有2000多個。我們採用的是ajax讀取所有的option json,並由js在瀏覽器中遍歷並最終生成完整的html。當數據量變大的時候,ajax讀取數據和瀏覽器處理數據都會有比較明顯的損耗,頁面初始化時需要較長時間,降低了用戶友好度。

2    備選解決方案

大家簡單分析了一下這個問題,想到了三種可能的解決方案。

2.1 修改數據結構

目前的同級數據有2000多條,數據從邏輯上可以拆分為兩級結構。這樣,將數據拆分為兩級結構後,使用兩個聯動Select,能大大減少每個select載入的option數量。

2.2 使用redis緩存數據

因為採用分散式部署,這些數據實際上經過了多次伺服器之間的傳輸。數據量大,每一級傳輸耗時增加,導致最終的耗時難於接受。

可以在api server端利用nosql對數據進行緩存,能在一定程度上降低耗時。

2.3 修改combo select插件

從前端入手,select只顯示少量數據,當用戶輸入關鍵字進行搜索時,實時從伺服器載入。這種方式增加了調用次數,但可以大大降低數據量,縮短頁面載入的耗時。

三種方案,都能在一定程度上解決問題。我們決定先從combo select插件嘗試,如果達不到效果,再考慮redis緩存或修改數據結構的方案。

3    Combo Select代碼分析

網址 https://github.com/PebbleRoad/combo-select ,感謝提供如此優秀的一個插件。

3.1 基本用法

首先在頁面中構建一個select,並初始化option數據,然後調用腳本

$("#selectId").comboSelect();

其他更複雜的功能,請自行前往官網學習。

3.2 html結構

 

Combo Select在執行時,在原 select 外層套了一個 <div class=”combo-select”>,然後在select後面添加了三個element。

div.combo-arrow,是下拉箭頭

ul.combo-dropdown是用來顯示的下拉列表

input.combo-input 是用來輸入模糊搜索內容的輸入框

並通過修改原 select 的屬性,隱藏掉。

3.3 js數據模型

combo select初始化時,經過一系列代碼,最終構造幾個屬性:

$container : 生成一個新的div,將原來的select和新生成的ul等都放在其中。

$el : 初始的select element

$options : 所有的option 數據

$dropdown : 生成的 ul.combo-dropdown 對象

$items : 所有的options轉成 li 格式後的數據。

下圖是數據模型和html元素之間的對應關係。

 

3.4 插件初始化

在js插件的代碼function Plugin ( element, options )會完成插件的初始化,根據select當前的數據,完成html元素的調整,以及js數據模型的初始化。初始化流程如下

 

3.5 模糊查詢的邏輯

當用戶在input中輸入文字的時候,會觸發 keydown和keyup事件,在keyup事件中,對 $items中的數據依次進行匹配,設置 visible屬性,實現部分數據的展示。

 

在這個過程中,原始的select($el)及其所有的options($options)沒有變化,下拉列表的變化,主要是將ul.li($items)設置為可見或不可見。

4    修改為Server端實時查詢方案

整個修改方案,分別從Server API、js組件、前端調用三方面解決。

4.1 Server API 修改

Server端需要提供根據名稱進行模糊搜索的介面。不贅述,需要註意的是返回數據要設置最大條數。避免根據查詢條件返回了大量的數據,就失去瞭解決的優勢。

限制最大條數後,需要跟產品介紹清楚這個實現邏輯,如果用戶輸入的關鍵字區分度不大時,可能無法查到真正需要的數據;此時需要用戶輸入更具有區分度的關鍵字。

4.2 ComboSelect組件修改

4.2.1      修改方案

修改keyup事件時的邏輯:原來是分別設置ul.li是否可見,修改為重新載入select的所有options,並根據options重建$items,並設置為所有ul.li都是可見的。

 

4.2.2      為組件新增幾個參數

              entity: 'entity',

              itemName: 'itemName',

              curItemField: 'curItemCode',

              curItemValue: '',

              curItemName: '',

              url: '',

              limit: 7

  • entity: 當前處理的數據類型,這是為了適應不同api返回的json定義的差異。更好的辦法是要求所有數據類型使用相同的屬性名;變通的方案就是增加這個entity,在js上做差異化處理。這樣就減少了改造的通用性。
  • itemName: 調用api時需要的用戶輸入值的參數名
  • curItemField:在html中,item的input名稱
  • curItemValue: 當前已選中數據的value
  • curItemName: 當前已選中數據的title
  • limit: 伺服器api模糊搜索返回值的分頁大小

4.2.3      修改 _filter() 方法實現伺服器端模糊查詢

修改了原組件的這個方法,判斷是否設置了伺服器端刷新的url。如果沒設置,沿用原來的邏輯;如果設置了,根據用戶輸入進行模糊查詢,並重新生成瀏覽器中被隱藏的select的所有options,並更新到$dropdown中。

if(self.settings.url != ''){

 // 準備調用api需要的json數據

 var self = this;

 var ajaxData = {

  "paging": true,

  "offset": 0,

  "limit": self.settings.limit

 };

 if(self.settings.itemName != '' && needle != ''){

  ajaxData[self.settings.itemName] = needle;

 }

 if(self.settings.curItemField != '' && self.settings.curItemValue != ''){

  ajaxData[self.settings.curItemField] = self.settings.curItemValue;

 }

 

 // 從伺服器查詢數據

$.ajax({

  url : self.settings.url,

  type : 'post',

  data: ajaxData,

  success : function(data) {

   var obj = $.parseJSON(data);

 

   // 先刪掉select原來的數據,並遍歷查詢結果生成option添加到select中

   var dropdownHtml = '', k = 0, p = '';

   self.$el.empty();

   self.$el.append("<option value=''>請選擇</option>");

  

   var confirmedValue;

   self.$dropdown.html("<li class='option-item' data-index='0' data-value=''>請選擇</li>");

   for (var i = 0; i < obj.length; i++) {

    var itemCode;

    var itemName;

    var itemExtraCode;

    if(self.settings.entity == 'entity'){

     itemCode = obj[i].entityCode;

     itemName = obj[i].entityName;

     itemExtraCode = obj[i].entityShortName;

    }else{

     itemCode = obj[i].itemCode;

     itemName = obj[i].itemName;

     itemExtraCode = itemCode;

    }

 

    // 生成select option

    var oneOption = $("<option></option>");

    $(oneOption).val(itemCode);

    $(oneOption).html(itemName);

    if(itemCode == self.settings.curItemValue || itemExtraCode == self.settings.curItemValue || itemName == self.settings.curItemName){

     $(oneOption).attr("selected", "selected");

     self.settings.curItemValue = itemCode;

     confirmedValue = itemCode;

    }

    self.$el.append(oneOption);

   

    if(confirmedValue != undefined && confirmedValue != ''){

     self.$el.val(confirmedValue);

    }

 

    // 生成$dropdown 中的li

    var oneItem = $("<li></li>");

    $(oneItem).attr("class",this.disabled? self.settings.disabledClass : "option-item");

    $(oneItem).attr("data-index", (i+1));

    $(oneItem).attr("data-value", itemCode);

    $(oneItem).html(itemName);

   

    self.$dropdown.append(oneItem);

   }

  

   // 為$items 重新賦值

   self.$items = self.$dropdown.children();

  

   // 觸發後續的open方法

   self.$container.trigger('comboselect:open')

  }

 });

}

 

4.2.4      修改 init() 實現首次載入

代碼類似_filter()。應該要獨立出一個方法來在兩個方法中調用,沒做。

init: function () {

 var self = this;

 

 if(self.settings.url != ''){

  //動態刷新代碼

  ... ...

 }else{

  // 組件的原始邏輯

  self._construct();

  self._events();

 }

},

 

4.3 前端調用

4.3.1      html代碼中添加參數

使用 comboselect- 首碼,如

<select class="list-filedV" id="entityCode" name="entityCode"

comboselect-entity="entity" onchange="getBranch('')">

</select>

<input type='hidden' name='entityName' id='entityName'>

4.3.2      js生成沒有預設值的combobox

在js代碼中完成初始化,代碼

//獲取數據

function getEntityData(){

    $("#entityCode").comboSelect({

       "itemName": "entityName",

        "url": contextPath+"/new/dictionary/searchEntityData.ajax",

        "limit": 7

    });

}

4.3.3      js生成有預設值的combobox

在編輯界面比較常見

//獲取數據_修改

function getEntityDataUp(curEntityCode, curEntityName){

    $("#entityCode").comboSelect({

        "itemName": "entityName",

        "curItemField": "includeEntityCode",

        "curItemValue": curEntityCode,

        "curItemName": curEntityName,

        "url": contextPath+"/new/dictionary/searchEntityData.ajax",

        "limit": 7

    });

}

 

5    降低調用伺服器頻度

註意看_keyup 的代碼,每次按鍵(不包括該函數忽略的特殊字元),每次都會刷新數據。如果是在瀏覽器內部進行數據過濾,問題還不明顯。但每次模糊查詢都通過伺服器查詢,就會帶來大量的api訪問。

5.1 修改方案

在_keyup()中,調用_delayFilter(),由它觸發前面修改後的 _filter()方法。

 

5.2 代碼 _delayFilter()

this.filterTimer = 0;

 

_delayFilter: function(search){

 if(this.filterTimer > 0){

  clearTimeout(this.filterTimer);

  this.filterTimer = 0;

 }

 var self = this;

 this.filterTimer = setTimeout(function(){

  self._filter(search);

 }, 500);

},


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 最近用ofo小黃車App的時候,發現以前下方掃一掃變成了一個眼睛動的小黃人,覺得蠻有意思的,這裡用HTML5仿一下效果。 ofo眼睛效果 效果分析 從效果中不難看出,是使用陀螺儀事件實現的。 這裡先來看一下HTML5中陀螺儀事件的一些概念。 陀螺儀事件為deviceorientation,這裡主要獲 ...
  • 毛玻璃效果 ios里毛玻璃效果的使用非常多,本文介紹一個實現div毛玻璃背景的方法 CSS3 Filter CSS3的Filter主要用在圖像的特效處理上,預設值為none,還有以下備選項:   1.grayscale灰度   2.sepia褐色   ...
  • 從接觸網站開發以來到現在,已經有五個年頭了吧,今天偶然整理電腦資料看到當時為參加系裡面一個比賽而做的第一個網站時,勾起了在這網站開發道路上的一串串回憶,成功與喜悅、煩惱與糾結都歷歷在目,感慨頗多。 先從大家學習上的一個誤區開始談起。 Web前端的學習誤區 網頁製作是電腦專業同學在大學期間都會接觸到 ...
  • 塊元素(block element) HTML標簽分類明細 * address - 地址 * blockquote - 塊引用 * center - 舉中對齊塊 * dir - 目錄列表 * div - 常用塊級容易,也是css layout的主要標簽 * dl - 定義列表 * fieldset ...
  • 第一階段:HTML的學習 超文本標記語言(HyperText Mark-up Language 簡稱HTML)是一個網頁的骨架,無論是靜態網頁還是動態網頁,最終返回到瀏覽器端的都是HTML代碼,瀏覽器將HTML代碼解釋渲染後呈現給用戶。因此,我們必須掌握HTML的基本結構和常用標記及屬性。 HTML ...
  • 一、容器溢出 語法:overflow:visible|hidden|scroll|auto|inherit; visible:預設值,溢出內容不會被裁剪,正常顯示 hidden: 溢出內容隱藏不可見 scroll: 當容器溢出時,溢出的內容以滾動條的形式查看(當容器沒有溢出時,也會顯示一個預設的滾動 ...
  • [1]數據結構 [2]創建鏈表 [3]雙向鏈表 [4]迴圈鏈表 ...
  • 這是分享按鈕: 這是js調用代碼: 這個就是分享js文件NativeShare.js: !function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof def ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...