以BootStrap Tab为例写一个前端组件


Posted in Javascript onJuly 25, 2017

介绍

本文以Bootstrap标签页组件为例,介绍如何编写或者封装一个前端组件,以下是实现效果:

以BootStrap Tab为例写一个前端组件

原生的Bootstrap-tab组件主要有html,css组成,开发者使用时,需要写很多代码,不易于使用,对bootstrap-tab封装后,可以更方便地使用,同时提供关闭、增加tab页、指定当前选中页、即使加载等功能,这样组件可以适配更多的场景。

原生bootstrap-tab组件使用可参考https://www.runoob.com/bootstrap/bootstrap-tab-plugin.html

其中官网一段实例代码是:

<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>菜鸟教程是一个提供最新的web技术站点,本站免费提供了建站相关的技术文档,帮助广大web技术爱好者快速入门并建立自己的网站。菜鸟先飞早入行——学的不仅是技术,更是梦想。</p>
  </div>
  <div class="tab-pane fade" id="ios">
    <p>iOS 是一个由苹果公司开发和发布的手机操作系统。最初是于 2007 年首次发布 iPhone、iPod Touch 和 Apple
      TV。iOS 派生自 OS X,它们共享 Darwin 基础。OS X 操作系统是用在苹果电脑上,iOS 是苹果的移动版本。</p>
  </div>
  <div class="tab-pane fade" id="jmeter">
    <p>jMeter 是一款开源的测试软件。它是 100% 纯 Java 应用程序,用于负载和性能测试。</p>
  </div>
  <div class="tab-pane fade" id="ejb">
    <p>Enterprise Java Beans(EJB)是一个创建高度可扩展性和强大企业级应用程序的开发架构,部署在兼容应用程序服务器(比如 JBOSS、Web Logic 等)的 J2EE 上。
    </p>
  </div>
</div>
<script>
  $(function () {
    $('#myTab li:eq(1) a').tab('show');
  });
</script>

那么如何封装或者开发一个组件呢?

组件开发步骤

Step1:结构化静态代码,梳理核心的问题

在组件开发流程中,可能拿到前端设计的静态代码(html+css的组合),这时候要拆解代码结构,使得结构能够模板化。其次梳理核心问题,bootstrap-tab组件化之后,应该能够动态加载tab内容,这个可以通过jquery.load方法解决,这样可以做到主页面和子页面解耦。

读懂了静态代码,理解了结构和核心问题就可以写代码了,首先搭建组件的架子。

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();
  }
  //默认配置
  BaseTab.prototype.default = {
  }
  //结构模板
  BaseTab.prototype.template = {
  }
  //初始化
  BaseTab.prototype.init = function () {
  } 
})(jQuery, window, document)

搭建了以上组件的骨架,并对组件命名为tabs,这样就可以通过$("#tab-container").data("tabs")获取组价的方法和属性。在入口方法中,会将初始化后的对象缓存到页面html中,这样可以避免重复创建对象。一些经典的开源前端组件都是这样写法,比如Bootstrap-treeview,大家有时间可以看看它的源码。

以上的写法使用原型链的写法。定义了默认配置,结构模板,初始化入口。

编写代码

在组件的代码骨架里,填充模板代码,这里使用占位符{0},{1}等表示外部传入的变量,然后在init方法中校验外部传入数据的合法性,然后构建组件,并且绑定关闭事件、点击事件。

在开发前端组件的时候,往往不知道默认参数应该有什么,可以在开发的时候,用到就加上去,这里加了两个默认参数,一个showIndex是默认显示的tab页索引,一个loadAlltab是否一次性把所有的页面数据加载完。

具体的逻辑请看下面的代码: 

//默认配置
  BaseTab.prototype.default = {
    showIndex: 0, //默认显示页索引
    loadAll: true,//true=一次全部加在页面,false=只加在showIndex指定的页面,其他点击时加载,提高响应速度
  }
  //结构模板
  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="关闭"></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("请指定tab页数据");
      return;
    }
    //当前显示的显示的页面是否超出索引
    if (this.options.showIndex < 0 || this.options.showIndex > this.options.data.length - 1) {
      console.error("showIndex超出了范围");
      //指定为默认值
      this.options.showIndex = this.default.showIndex;
    }
    //清除原来的tab页
    this.$element.html("");
    this.builder(this.options.data);
  }
  //使用模板搭建页面结构
  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));
      //如果可关闭,插入关闭图标,并绑定关闭事件
      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点击即加载事件
    //设置一个值,记录每个tab页是否加载过
    this.stateObj = {};
    var data = this.options.data;
    //如果是当前页或者配置了一次性全部加载,否则点击tab页时加载
    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页未指定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))
      }
    }
    //关闭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();
      })
    });
  }

测试

编写一个前端界面,测试组件

<!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>

通过配置各种参数,看看组件是否满足了预期的要求。

以BootStrap Tab为例写一个前端组件

扩展

组件在使用的过程中还会遇到各种问题,或者各种需求,比如新增一个tab页面,比如获取当前tab的ID或index,这是可以在代码中按需扩展。

//新增一个tab页
  BaseTab.prototype.addTab=function (obj) {
    //nav-tab
    var ul_li = $(this.template.ul_li.format(obj.id, obj.text));
    //如果可关闭,插入关闭图标,并绑定关闭事件
    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");
  }
  //根据id设置活动tab页
  BaseTab.prototype.showTab=function (tabId) {
    this.$element.find(".nav-tabs li a[href='#" + tabId + "']").tab("show");
  }
  //获取当前活动tab页的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版本已经开源,详见我的Github地址:

bootstrap-tab:https://github.com/bill1012/bootstrap-tab

总结

以上所述是小编给大家介绍的以BootStrap Tab为例写一个前端组件,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!

Javascript 相关文章推荐
页面回到顶部的三种实现(锚标记,js)
Oct 01 Javascript
jquery封装的对话框简单实现
Jul 21 Javascript
JavaScript数组的一些奇葩行为
Jan 25 Javascript
基于jquery实现无限级树形菜单
Mar 22 Javascript
jQuery自适应轮播图插件Swiper用法示例
Aug 24 Javascript
vue实现图书管理demo详解
Oct 17 Javascript
Vue仿支付宝支付功能
May 25 Javascript
layer.close()关闭进度条和Iframe窗的方法
Aug 17 Javascript
clipboard在vue中的使用的方法示例
Oct 19 Javascript
使用Object.defineProperty如何巧妙找到修改某个变量的准确代码位置
Nov 02 Javascript
手动下载Chrome并解决puppeteer无法使用问题
Nov 12 Javascript
微信公众号平台接口开发 菜单管理的实现
Aug 14 Javascript
基于Bootstrap的标签页组件及bootstrap-tab使用说明
Jul 25 #Javascript
js事件委托和事件代理案例分享
Jul 25 #Javascript
基于JavaScript实现多级菜单效果
Jul 25 #Javascript
简单谈谈React中的路由系统
Jul 25 #Javascript
老生常谈js中的MVC
Jul 25 #Javascript
教你5分钟学会用requirejs(必看篇)
Jul 25 #Javascript
浅谈Vue.js 1.x 和 2.x 实例的生命周期
Jul 25 #Javascript
You might like
PHP 定界符 使用技巧
2009/06/14 PHP
详谈PHP文件目录基础操作
2014/11/11 PHP
PHP实现恶意DDOS攻击避免带宽占用问题方法
2015/05/27 PHP
PHP实现的随机IP函数【国内IP段】
2016/07/20 PHP
php中strtotime函数性能分析
2016/11/20 PHP
浅析PHP echo 和 print 语句
2020/06/30 PHP
JS array 数组详解
2009/03/22 Javascript
Javascript String对象扩展HTML编码和解码的方法
2009/06/02 Javascript
jquery 注意事项与常用语法小结
2010/06/07 Javascript
关于jquery append() html时的小问题的解决方法
2010/12/16 Javascript
深入理解JavaScript系列(7) S.O.L.I.D五大原则之开闭原则OCP
2012/01/15 Javascript
用jQuery实现一些导航条切换,显示隐藏的实例代码
2013/06/08 Javascript
基于jQuery仿淘宝产品图片放大镜代码分享
2020/06/23 Javascript
javascript实现获取浏览器版本、浏览器类型
2015/12/02 Javascript
原生javascript实现的ajax异步封装功能示例
2016/11/03 Javascript
bootstrap table 数据表格行内修改的实现代码
2017/02/13 Javascript
利用jquery去掉时光轴头尾部线条的方法实例
2017/06/16 jQuery
详解微信小程序审核不通过的解决方法
2018/01/17 Javascript
微信小程序支付前端源码
2018/08/29 Javascript
浅析js中mvvm模式实现的原理
2018/10/06 Javascript
Python 循环语句之 while,for语句详解
2018/04/23 Python
python 去除txt文本中的空格、数字、特定字母等方法
2018/07/24 Python
python linecache 处理固定格式文本数据的方法
2019/01/08 Python
python 函数中的内置函数及用法详解
2019/07/02 Python
python使用if语句实现一个猜拳游戏详解
2019/08/27 Python
Tensorflow 实现分批量读取数据
2020/01/04 Python
python通过对字典的排序,对json字段进行排序的实例
2020/02/27 Python
浅谈keras使用预训练模型vgg16分类,损失和准确度不变
2020/07/02 Python
Python批量获取并保存手机号归属地和运营商的示例
2020/10/09 Python
Pyecharts 中Geo函数常用参数的用法说明
2021/02/01 Python
《最大的麦穗》教学反思
2014/04/17 职场文书
大学生村官座谈会发言材料
2014/05/25 职场文书
考试作弊检讨书1000字(5篇)
2014/10/19 职场文书
2014年质检员工作总结
2014/11/18 职场文书
华山导游词
2015/02/03 职场文书
Linux中一对多配置日志服务器的详细步骤
2022/07/23 Servers