以BootStrap Tab為例寫一個(gè)前端組件
介紹
本文以Bootstrap標(biāo)簽頁(yè)組件為例,介紹如何編寫或者封裝一個(gè)前端組件,以下是實(shí)現(xiàn)效果:
原生的Bootstrap-tab組件主要有html,css組成,開發(fā)者使用時(shí),需要寫很多代碼,不易于使用,對(duì)bootstrap-tab封裝后,可以更方便地使用,同時(shí)提供關(guān)閉、增加tab頁(yè)、指定當(dāng)前選中頁(yè)、即使加載等功能,這樣組件可以適配更多的場(chǎng)景。
原生bootstrap-tab組件使用可參考https://www.runoob.com/bootstrap/bootstrap-tab-plugin.html
其中官網(wǎng)一段實(shí)例代碼是:
<ul id="myTab" class="nav nav-tabs"> <li class="active"><a href="#home" rel="external nofollow" data-toggle="tab"> 菜鳥教程</a> </li> <li><a href="#ios" rel="external nofollow" data-toggle="tab">iOS</a></li> <li class="dropdown"> <a href="#" rel="external nofollow" id="myTabDrop1" class="dropdown-toggle" data-toggle="dropdown">Java <b class="caret"></b> </a> <ul class="dropdown-menu" role="menu" aria-labelledby="myTabDrop1"> <li><a href="#jmeter" rel="external nofollow" tabindex="-1" data-toggle="tab"> jmeter</a> </li> <li><a href="#ejb" rel="external nofollow" tabindex="-1" data-toggle="tab"> ejb</a> </li> </ul> </li> </ul> <div id="myTabContent" class="tab-content"> <div class="tab-pane fade in active" id="home"> <p>菜鳥教程是一個(gè)提供最新的web技術(shù)站點(diǎn),本站免費(fèi)提供了建站相關(guān)的技術(shù)文檔,幫助廣大web技術(shù)愛好者快速入門并建立自己的網(wǎng)站。菜鳥先飛早入行——學(xué)的不僅是技術(shù),更是夢(mèng)想。</p> </div> <div class="tab-pane fade" id="ios"> <p>iOS 是一個(gè)由蘋果公司開發(fā)和發(fā)布的手機(jī)操作系統(tǒng)。最初是于 2007 年首次發(fā)布 iPhone、iPod Touch 和 Apple TV。iOS 派生自 OS X,它們共享 Darwin 基礎(chǔ)。OS X 操作系統(tǒng)是用在蘋果電腦上,iOS 是蘋果的移動(dòng)版本。</p> </div> <div class="tab-pane fade" id="jmeter"> <p>jMeter 是一款開源的測(cè)試軟件。它是 100% 純 Java 應(yīng)用程序,用于負(fù)載和性能測(cè)試。</p> </div> <div class="tab-pane fade" id="ejb"> <p>Enterprise Java Beans(EJB)是一個(gè)創(chuàng)建高度可擴(kuò)展性和強(qiáng)大企業(yè)級(jí)應(yīng)用程序的開發(fā)架構(gòu),部署在兼容應(yīng)用程序服務(wù)器(比如 JBOSS、Web Logic 等)的 J2EE 上。 </p> </div> </div> <script> $(function () { $('#myTab li:eq(1) a').tab('show'); }); </script>
那么如何封裝或者開發(fā)一個(gè)組件呢?
組件開發(fā)步驟
Step1:結(jié)構(gòu)化靜態(tài)代碼,梳理核心的問(wèn)題
在組件開發(fā)流程中,可能拿到前端設(shè)計(jì)的靜態(tài)代碼(html+css的組合),這時(shí)候要拆解代碼結(jié)構(gòu),使得結(jié)構(gòu)能夠模板化。其次梳理核心問(wèn)題,bootstrap-tab組件化之后,應(yīng)該能夠動(dòng)態(tài)加載tab內(nèi)容,這個(gè)可以通過(guò)jquery.load方法解決,這樣可以做到主頁(yè)面和子頁(yè)面解耦。
讀懂了靜態(tài)代碼,理解了結(jié)構(gòu)和核心問(wèn)題就可以寫代碼了,首先搭建組件的架子。
Step2:組件骨架
/** * Bootstrap tab組件封裝 * @author billjiang qq:475572229 * @created 2017/7/24 * */ (function ($, window, document, undefined) { 'use strict'; var pluginName = 'tabs'; //入口方法 $.fn[pluginName] = function (options) { var self = $(this); if (this == null) return null; var data = this.data(pluginName); if (!data) { data = new BaseTab(this, options); self.data(pluginName, data); } return data; }; var BaseTab = function (element, options) { this.$element = $(element); this.options = $.extend(true, {}, this.default, options); this.init(); } //默認(rèn)配置 BaseTab.prototype.default = { } //結(jié)構(gòu)模板 BaseTab.prototype.template = { } //初始化 BaseTab.prototype.init = function () { } })(jQuery, window, document)
搭建了以上組件的骨架,并對(duì)組件命名為tabs,這樣就可以通過(guò)$("#tab-container").data("tabs")獲取組價(jià)的方法和屬性。在入口方法中,會(huì)將初始化后的對(duì)象緩存到頁(yè)面html中,這樣可以避免重復(fù)創(chuàng)建對(duì)象。一些經(jīng)典的開源前端組件都是這樣寫法,比如Bootstrap-treeview,大家有時(shí)間可以看看它的源碼。
以上的寫法使用原型鏈的寫法。定義了默認(rèn)配置,結(jié)構(gòu)模板,初始化入口。
編寫代碼
在組件的代碼骨架里,填充模板代碼,這里使用占位符{0},{1}等表示外部傳入的變量,然后在init方法中校驗(yàn)外部傳入數(shù)據(jù)的合法性,然后構(gòu)建組件,并且綁定關(guān)閉事件、點(diǎn)擊事件。
在開發(fā)前端組件的時(shí)候,往往不知道默認(rèn)參數(shù)應(yīng)該有什么,可以在開發(fā)的時(shí)候,用到就加上去,這里加了兩個(gè)默認(rèn)參數(shù),一個(gè)showIndex是默認(rèn)顯示的tab頁(yè)索引,一個(gè)loadAlltab是否一次性把所有的頁(yè)面數(shù)據(jù)加載完。
具體的邏輯請(qǐng)看下面的代碼:
//默認(rèn)配置 BaseTab.prototype.default = { showIndex: 0, //默認(rèn)顯示頁(yè)索引 loadAll: true,//true=一次全部加在頁(yè)面,false=只加在showIndex指定的頁(yè)面,其他點(diǎn)擊時(shí)加載,提高響應(yīng)速度 } //結(jié)構(gòu)模板 BaseTab.prototype.template = { ul_nav: '<ul class="nav nav-tabs"></ul>', ul_li: '<li><a href="#{0}" rel="external nofollow" data-toggle="tab"><span>{1}</span></a></li>', ul_li_close: '<i class="fa fa-remove closeable" title="關(guān)閉"></i>', div_content: '<div class="tab-content"></div>', div_content_panel: '<div class="tab-pane fade" id="{0}"></div>' } //初始化 BaseTab.prototype.init = function () { if (!this.options.data || this.options.data.length == 0) { console.error("請(qǐng)指定tab頁(yè)數(shù)據(jù)"); return; } //當(dāng)前顯示的顯示的頁(yè)面是否超出索引 if (this.options.showIndex < 0 || this.options.showIndex > this.options.data.length - 1) { console.error("showIndex超出了范圍"); //指定為默認(rèn)值 this.options.showIndex = this.default.showIndex; } //清除原來(lái)的tab頁(yè) this.$element.html(""); this.builder(this.options.data); } //使用模板搭建頁(yè)面結(jié)構(gòu) BaseTab.prototype.builder = function (data) { var ul_nav = $(this.template.ul_nav); var div_content = $(this.template.div_content); for (var i = 0; i < data.length; i++) { //nav-tab var ul_li = $(this.template.ul_li.format(data[i].id, data[i].text)); //如果可關(guān)閉,插入關(guān)閉圖標(biāo),并綁定關(guān)閉事件 if (data[i].closeable) { var ul_li_close = $(this.template.ul_li_close); ul_li.find("a").append(ul_li_close); ul_li.find("a").append(" "); } ul_nav.append(ul_li); //div-content var div_content_panel = $(this.template.div_content_panel.format(data[i].id)); div_content.append(div_content_panel); } this.$element.append(ul_nav); this.$element.append(div_content); this.loadData(); this.$element.find(".nav-tabs li:eq(" + this.options.showIndex + ") a").tab("show"); } BaseTab.prototype.loadData = function () { var self = this; //tab點(diǎn)擊即加載事件 //設(shè)置一個(gè)值,記錄每個(gè)tab頁(yè)是否加載過(guò) this.stateObj = {}; var data = this.options.data; //如果是當(dāng)前頁(yè)或者配置了一次性全部加載,否則點(diǎn)擊tab頁(yè)時(shí)加載 for (var i = 0; i < data.length; i++) { if (this.options.loadAll || this.options.showIndex == i) { if (data[i].url) { $("#" + data[i].id).load(data[i].url); this.stateObj[data[i].id] = true; } else { console.error("id=" + data[i].id + "的tab頁(yè)未指定url"); this.stateObj[data[i].id] = false; } } else { this.stateObj[data[i].id] = false; (function (id, url) { self.$element.find(".nav-tabs a[href='#" + id + "']").on('show.bs.tab', function () { if (!self.stateObj[id]) { $("#" + id).load(url); self.stateObj[id] = true; } }); }(data[i].id, data[i].url)) } } //關(guān)閉tab事件 this.$element.find(".nav-tabs li a i.closeable").each(function (index, item) { $(item).click(function () { var href = $(this).parents("a").attr("href").substr(1); $(this).parents("li").remove(); $("#" + href).parent().remove(); }) }); }
測(cè)試
編寫一個(gè)前端界面,測(cè)試組件
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Tab組件</title> </head> <link rel="stylesheet" href="bootstrap/css/bootstrap.min.css" rel="external nofollow" > <link rel="stylesheet" href="font-awesome/css/font-awesome.min.css" rel="external nofollow" > <link rel="stylesheet" href="../css/bootstrap-tab.css" rel="external nofollow" > <body> <div id="tabContainer"></div> </body> <script src="jquery/jquery-1.8.3.min.js"></script> <script src="bootstrap/js/bootstrap.min.js"></script> <script src="../js/bootstrap-tab.js"></script> <script> $("#tabContainer").tabs({ data: [{ id: 'home', text: '百度一下', url: "tab_first.html", closeable:true }, { id: 'admineap', text: 'AdminEAP', url: "tab_second.html" }, { id: 'edit', text: '編輯人員', url: "tab_content.html", closeable:true }], showIndex:1, loadAll:false }) </script> </html>
通過(guò)配置各種參數(shù),看看組件是否滿足了預(yù)期的要求。
組件在使用的過(guò)程中還會(huì)遇到各種問(wèn)題,或者各種需求,比如新增一個(gè)tab頁(yè)面,比如獲取當(dāng)前tab的ID或index,這是可以在代碼中按需擴(kuò)展。
//新增一個(gè)tab頁(yè) BaseTab.prototype.addTab=function (obj) { //nav-tab var ul_li = $(this.template.ul_li.format(obj.id, obj.text)); //如果可關(guān)閉,插入關(guān)閉圖標(biāo),并綁定關(guān)閉事件 if (obj.closeable) { var ul_li_close = $(this.template.ul_li_close); ul_li.find("a").append(ul_li_close); ul_li.find("a").append(" "); } this.$element.find(".nav-tabs").append(ul_li); //div-content var div_content_panel = $(this.template.div_content_panel.format(obj.id)); this.$element.find(".tab-content").append(div_content_panel); $("#" + obj.id).load(obj.url); this.stateObj[obj.id] = true; if(obj.closeable){ this.$element.find(".nav-tabs li a[href='#" + obj.id + "'] i.closeable").click(function () { var href = $(this).parents("a").attr("href").substr(1); $(this).parents("li").remove(); $("#" + href).parent().remove(); }) } this.$element.find(".nav-tabs a[href='#" + obj.id + "']").tab("show"); } //根據(jù)id設(shè)置活動(dòng)tab頁(yè) BaseTab.prototype.showTab=function (tabId) { this.$element.find(".nav-tabs li a[href='#" + tabId + "']").tab("show"); } //獲取當(dāng)前活動(dòng)tab頁(yè)的ID BaseTab.prototype.getCurrentTabId=function () { var href=this.$element.find(".nav-tabs li.active a").attr("href"); href=href.substring(1); return href; }
更完善的bootrap-tab版本已經(jīng)開源,詳見我的Github地址:
bootstrap-tab:https://github.com/bill1012/bootstrap-tab
總結(jié)
以上所述是小編給大家介紹的以BootStrap Tab為例寫一個(gè)前端組件,希望對(duì)大家有所幫助,如果大家有任何疑問(wèn)請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!
- JS組件Bootstrap Table使用實(shí)例分享
- JS組件Bootstrap Table布局詳解
- JS表格組件神器bootstrap table詳解(強(qiáng)化版)
- JS組件系列之Bootstrap table表格組件神器【二、父子表和行列調(diào)序】
- JS組件系列之Bootstrap table表格組件神器【終結(jié)篇】
- JS組件Bootstrap Table使用方法詳解
- JS表格組件神器bootstrap table詳解(基礎(chǔ)版)
- JS組件Bootstrap Table表格多行拖拽效果實(shí)現(xiàn)代碼
- JS組件Bootstrap Table表格行拖拽效果實(shí)現(xiàn)代碼
相關(guān)文章
javascript 設(shè)計(jì)模式之組合模式原理與應(yīng)用詳解
這篇文章主要介紹了javascript 設(shè)計(jì)模式之組合模式原理與應(yīng)用,結(jié)合實(shí)例形式分析了javascript組合模式基本概念、原理、應(yīng)用場(chǎng)景及操作注意事項(xiàng),需要的朋友可以參考下2020-04-04JavaScript知識(shí)點(diǎn)總結(jié)之如何提高性能
JavaScript的性能問(wèn)題不容小覷,這就需要我們開發(fā)人員在編寫JavaScript程序時(shí)多注意一些細(xì)節(jié),本文非常詳細(xì)的介紹了一下JavaScript性能優(yōu)化方面的知識(shí)點(diǎn),絕對(duì)是干貨,需要的朋友快來(lái)一起學(xué)習(xí)吧2016-01-01基于JavaScript實(shí)現(xiàn)多級(jí)菜單效果
這篇文章主要為大家詳細(xì)介紹了基于JavaScript實(shí)現(xiàn)多級(jí)菜單效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-07-07javascript實(shí)現(xiàn)模擬時(shí)鐘的方法
這篇文章主要介紹了javascript實(shí)現(xiàn)模擬時(shí)鐘的方法,涉及javascript操作時(shí)間實(shí)時(shí)顯示的相關(guān)技巧,需要的朋友可以參考下2015-05-05