介绍

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

原生的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" data-toggle="tab">菜鸟教程</a></li><li><a href="#ios" data-toggle="tab">iOS</a></li><li class="dropdown"><a href="#" 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" tabindex="-1" data-toggle="tab">jmeter</a></li><li><a href="#ejb" 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 和 AppleTV。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}" 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-tabvar 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("&nbsp;");}ul_nav.append(ul_li);//div-contentvar 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">
<link rel="stylesheet" href="font-awesome/css/font-awesome.min.css">
<link rel="stylesheet" href="../css/bootstrap-tab.css"><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>

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

扩展

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

//新增一个tab页BaseTab.prototype.addTab=function (obj) {//nav-tabvar 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("&nbsp;");}this.$element.find(".nav-tabs").append(ul_li);//div-contentvar 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页的IDBaseTab.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为例相关推荐

  1. Vue手写一个日历组件

    工作中遇到一个需求是根据日历查看某一天/某一周/某一月的睡眠报告,但是找了好多日历组件都不是很符合需求,只好自己手写一个日历组件,顺便记录一下. 先来看看设计图是什么样式, 跟其他日历有点不一样,这个 ...

  2. Day 2---vue2 从0开始 写一个前端框架

    项目背景:vue2 业务需求:用Vue+Element 写一个前端框架 今日主线任务:完成静态登陆页面 项目地址: https://gitee.com/whwbs/my_project.git 准备工 ...

  3. 设计一个前端组件库,需要具备哪些能力?

    大厂技术  高级前端  Node进阶 点击上方 程序员成长指北,关注公众号 回复1,加入高级Node交流群 在研究生的时候用 Vue2.0 做过一个守望先锋UI库. 当时很沉迷<守望先锋> ...

  4. 让我们一起写一个前端监控系统吧!

    CSDN话题挑战赛第2期 参赛话题:前端技术分享 项目介绍 我们基于Vue2.利用vue-plugin实现项目级别的npm包监控报错,并专为Vue项目设计了监控中台 核心监控插件开箱即用,用户可灵活选 ...

  5. 练手:原生js(部分jquery)写一个前端页面分页功能

    准备一个获取数据的接口 –注–:页面可能有点简陋,我们这里主要写如何操作dom来实现分页的功能. 这里我是用node搭建了一个简易的服务器,用来给前端发送数据: const express = req ...

  6. 手把手教你写一个Vue3组件库但是乞丐版

    好久没写文章了,最近在研究一些组件库的实现方法,分享一下.在这我这篇文章之前其实已经有一篇文章讲了Vue如何打包组件库了(最底部),但是这篇文章一是没有源码二是Vue3和Vue2的组件库写法有点不一样 ...

  7. 帮我写一个前端页面,使用react,组件使用antd,页面中需要有一个表格,表格包含序号、名称、创建日期。表格可以分页显示...

    好的,下面是一个使用 React 和 Antd 实现的带有分页的表格的示例: import { Table, Pagination } from 'antd';const columns = [{ti ...

  8. 学习笔记Vue(十 四)—— 用vue写一个日历组件

    先看一下实现的效果: 实现日历的逻辑: 先写出日历的大致结构,分两个部分,头部和主体部分,日历先显示6排7列,总共42个数字,按从1到42来显示: <div class="every- ...

  9. js 写一个前端图片查看器

    1. 前言 网上已经有不少成熟的图片查看器插件,如果是单纯想要点击图片放大预览的话,可以直接使用插件.例如viewerjs 但是,当打开图片后还需要对图片进行一些像删除.下载.标记等业务层面上的操作, ...

最新文章

  1. 上海市金山区财政局容灾项目竞争性谈判600万元
  2. Python递归实现快速排序
  3. 访问一个HTTPS的网站的大致流程
  4. 【数据挖掘】卷积神经网络 ( 池化 | 丢弃 | 批量规范化 | 卷积神经网络完整流程示例 | 卷积 | 池化 | 全连接 | 输出 | 卷积神经网络总结 )
  5. 用户态与内核态的区别
  6. 语音识别:从GMM-HMM到端到端
  7. 基于Eclipse搭建STM32开源开发环境
  8. javascript 的参数有长度限制吗?一个细节引起的误区
  9. 如何让fragment每次都重新加载_带上税控在哪都能开票,如何重新安装开票软件?...
  10. 【新手向】阿里云上ubuntu+flask+gunicorn+nginx服务器部署(二)项目部署
  11. python如何检查错误-python中的错误如何查看
  12. linux/windows双系统安装、启动顺序设置及重新设置
  13. Maven超级详细安装教程ovo
  14. 在Linux中使用飞信发送手机短信
  15. 小白莲的操作系统day05-2.3(01-05)
  16. python的label属性_python内置GUI库tkinter——Label类属性
  17. 深信服“监控员工跳槽倾向”引争议,律师称未告知员工涉嫌违法
  18. 抖音开发 发布内容至抖音H5
  19. Pearson 相关系数--最佳理解及相关应用
  20. 博客登录注册界面的实现

热门文章

  1. 英语一和英语二历年真题卷和解析
  2. oracle dbms_workload_repository,Oracle10g dbms_workload_repository使用-性能调优-Oracle频道-中国IT实验室...
  3. OpenStack架构分析与实践
  4. 爬虫小案例-爬取当当网TOP500的图书并将数据存入数据库
  5. C++ STL常用库的使用方法(下)
  6. TFT-LCD电路设计之电源电路(Power IC)
  7. 初创企业重新设计管理系统租用方案:添加ARM处理资源并将云计算作为主脑
  8. nginx 代理tcp长连接短连接配置
  9. 在flash中嵌入ppt视频
  10. string库的简介和使用