Bootstrap整体框架之JavaScript插件架构


Posted in Javascript onDecember 15, 2016

本文实例为大家介绍了JavaScript插件架构的知识点,供大家参考,具体内容如下

1. JavaScript插件架构

如下是插件alert的全部代码,每个插件都定义在如下类似的作用域中:

+function ($) {
 'use strict';

 // ALERT CLASS DEFINITION
 // ======================

 var dismiss = '[data-dismiss="alert"]'
 var Alert = function (el) {
 $(el).on('click', dismiss, this.close)
 }

 Alert.VERSION = '3.3.7'

 Alert.TRANSITION_DURATION = 150

 Alert.prototype.close = function (e) {
 var $this = $(this)
 var selector = $this.attr('data-target')

 if (!selector) {
 selector = $this.attr('href')
 selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7
 }

 var $parent = $(selector === '#' ? [] : selector)

 if (e) e.preventDefault()

 if (!$parent.length) {
 $parent = $this.closest('.alert')
 }

 $parent.trigger(e = $.Event('close.bs.alert'))

 if (e.isDefaultPrevented()) return

 $parent.removeClass('in')

 function removeElement() {
 // detach from parent, fire event then clean up data
 $parent.detach().trigger('closed.bs.alert').remove()
 }

 $.support.transition && $parent.hasClass('fade') ?
 $parent
 .one('bsTransitionEnd', removeElement)
 .emulateTransitionEnd(Alert.TRANSITION_DURATION) :
 removeElement()
 }


 // ALERT PLUGIN DEFINITION
 // =======================

 function Plugin(option) {
 return this.each(function () {
 var $this = $(this)
 var data = $this.data('bs.alert')

 if (!data) $this.data('bs.alert', (data = new Alert(this)))
 if (typeof option == 'string') data[option].call($this)
 })
 }

 var old = $.fn.alert

 $.fn.alert  = Plugin
 $.fn.alert.Constructor = Alert


 // ALERT NO CONFLICT
 // =================

 $.fn.alert.noConflict = function () {
 $.fn.alert = old
 return this
 }


 // ALERT DATA-API
 // ==============

 $(document).on('click.bs.alert.data-api', dismiss, Alert.prototype.close)

}(jQuery);

//通过将作用域内的Alert类赋值给jQuery的alert对象的Constructor属性,在IIFE作用域外也可以使用Alert类,比如这行代码
var Alert = $.fn.alert.Constructor

BootStrap所有的插件在开发中都遵循了同样的规则,也为自定义插件提供了规范和依据(如下三个规则):
1.HTML布局规则:基于元素自定义属性的布局规则,比如使用类似于data-target的自定义属性
2.JavaScript实现步骤(所有插件都遵循jQuery插件开发的标准步骤,所有事件保持统一的标准)
3.插件调用方法(插件使用方式可以是HTML声明式或者调用式)

1.1 HTML布局规则

基于元素自定义属性的布局规则,类似于data-* 的自定义属性

默认情况下,所有插件都可以通过设置特定的HTML代码和相应的自定义属性来实现。
在页面加载的时候,js代码会自动检测到这些标记,并自动绑定相应的事件,不需要添加额外的代码。

点击按钮之后就会关闭警告框:

<div class="alert">
 <button type="button" class="close" data-dismiss="alert"></button>
 <strong>警告!</strong>你输入的项目不合法!
</div>

下拉菜单:在button按钮上添加data-toggle=”dropdown”属性,单机按钮时,默认隐藏的dropdown-menu会显示

//例子:下拉菜单.html
<div class="btn-group">
 <button type="button" class="btn btn-default" data-toggle="dropdown">
 我的书籍<span class="caret"></span>
 </button>
 <ul class="dropdown-menu">
 <li><a href="#">编程</a></li>
 <li><a href="#">设计</a></li>
 <li><a href="#">深入</a></li>
 </ul>
</div>

1.2 JavaScript实现步骤(所有插件都遵循jQuery插件开发的标准步骤,所有事件保持统一的标准)

BootStrap中所有JavaScript插件走遵循统一的实现步骤,维护方便,自定义插件也方便,步骤如下:

1.声明立即调用函数,比如+function($){“use strict”;…}(jQuery);

参数中传入jQuery的对象,通过参数引入变量,好处是:1.函数内部的符变量代表了局部变量,而不是全局变量中代表jQuery的符变量,以达到防止变量污染的目的。2.内部的代码都是私有代码,外部代码无法访问。只能通过第三步,在.fn上设置了插件(比如.fn.alert=)的形式,通过符变量才能将整个插件通过唯一的借口$.fn.alert暴露出去,从而保护了内部代码。

//function前边的+,主要目的是防止前面有未正常结束的代码(比如遗漏了分号),导致前后代码被编译器认为是一体的,从而导致代码运行出错。

+function($){
 "use strict";

}(window.jQuery);

2.定义插件类(或者选择器)以及相关原型方法。比如Alert,prototype.close

定义插件类Alert,然后在定义一些原型函数,比如close函数方法。
先定义选择器,所有符合该自定义属性的元素可以触发下面的事件。

var dismiss = '[data-dismiss="alert"]';
var Alert = function(el) {
 //传入元素,如果元素内部有dismiss上设置的自定义属性,则click事件会触发原型上的close方法
 $(el).on('click',dismiss,this.close);
};
Alert.prototype.close = function(e) {

}

3.在jQuery上定义插件并重设插件构造函数,例如$.fn.alert.Constructor=Alert

在jQuery上定义插件,以便通过jQuery.插件名称的方式,也能够使用该插件。

function Plugin(option) {
 return this.each(function () {
 var $this = $(this)
 //获取存储的Alert对象,如果是第一次执行变量data的值为undefined 
 var data = $this.data('bs.alert')
 //缓存没有,就new一个alert对象,存储在元素的jQuery对象上的‘bs.alert'数据字段
 if (!data) $this.data('bs.alert', (data = new Alert(this)))
 //支持传入方法名参数,执行该方法,这里就是data.close()
 if (typeof option == 'string') data[option].call($this)
 })
}
//jQuery插件的定义使用了标准的方式,在fn上进行扩展,在jQuery上定义alert插件
//保留其他插件的$.fn.alert代码(如果定义)以便在noConflict之后,可以继续使用改旧代码
//先备份之前插件的旧代码,以便在后面防冲突的时候使用
var old = $.fn.alert

$.fn.alert  = Plugin
//在附加扩展之后,重新设置插件的构造器(即Constructor属性),这样就可以通过Constructor属性查询到插件的真实类函数,使用new操作符实例化的时候也不会出错
//js区分大小写,所以这里的Constructor只是一个普通属性,跟constructor不同,通过将作用域内的Alert类赋值给jQuery的alert对象的Constructor属性,在IIFE作用域外也可以使用Alert类
$.fn.alert.Constructor = Alert

不声明第三步的话,HTML声明式的方式也是可以用的。所以第三步是专门为某些喜欢用js代码触发事件的人所准备的。需要注意的是,如果第三步不需要,第四步的方冲突的功能也就没办法用了~

4.防冲突处理(noConflict),例如$.fn.alert.noConflict

目的是让BootStrap插件和其他UI库的同名插件并存。

$.fn.alert.noConflict = function() {
 //恢复以前的代码
 $.fn.alert = old
 //将$.fn.alert.noConflict()设置为BootStrap的alert插件
 return this
}

比如A库中有个同名.fn.alert插件,则BootStrap在执行之前就通过old先备份了,然后执行.fn.alert.noConflict后就会还原该old对象插件
而使用BootStrap的alert插件的话,则通过var alert = $.fn.alert.noConflict()的形式,将BootStrap的alert插件转移到另外一个变量上,从而继续使用。

5.绑定各种触发事件(data-api)

由于已经为jQuery提供了默认的$.fn.alert扩展插件功能,就可以手工编写js代码来触发事件了。
这里主要是为声明式的HTML触发事件。即:在HTML文档里已经按照布局规则声明了相关的自定义属性(比如data-dismiss=”alert”),然后通过这里的代码初始化默认的单击事件行为。

/*
ALERT DATA-API
这段JavaScript代码将click委托事件监听器绑定在document元素上,并给click事件赋予命名空间
jQuery将事件绑定在document文档对象上的好处,就是js事件代理的优点
 */
$(document).on('click.bs.alert.data-api',dismiss,Alert.prototype.close)

命名空间的话好处:http://suqing.iteye.com/blog/1533123,具体如下

jQuery1.7开始,jQuery引入了全新的事件绑定机制,jQuery .on() 和 off() 两个函数统一处理事件绑定,也是jQuery触发DOM元素事件的最佳方法。有时候既要trigger手动触发事件,也要从DOM元素上解绑事件,比如:

$('.item').on('click', doThisCoolThing); 
$('.item').on('click', doThisOtherCoolThing); 
$('.item').trigger('click'); // 两个click事件都触发 
$('.item').off('click'); // 两个click事件都解绑

使用事件命名空间我们可以在创建事件的时候指派名称到事件处理器,并在使用trigger()和off()时通过这个名称指定到特定的函数。调用的时候就可以通过使用不同的命名空间灵活的指派事件. 比如:

$('.item').on('click.navigate', doThisCoolThing); 
$('.item').on('click.notify', doThisOtherCoolThing); 
$('.item').trigger('click.navigate'); // 只有带有navigate这个命名空间的方法才会触发 
$('.item').off('click.notify'); // 只有带有notify这个命名空间的方法才会解绑

也可以使用多个命名空间,无论使用哪个名字都会生效,通过命名空间代码规范(产品.模块.事件)让事件的层次更清晰:

$('.item').on('click.navigate.notify', doThisCoolThing); 
$('.item').trigger('click.navigate'); // 将触发click事件 
$('.item').off('click.notify'); // 将解绑click事件

参考资料:
http://www.andismith.com/blog/2011/11/on-and-off/
http://www.andismith.com/blog/2013/02/jquery-on-and-off-namespacing/

1.3 插件调用方法(插件使用方式可以是HTML声明式或者调用式)

1.插件可以js代码调用,都提供多种调用方式(无参数传递,传递对象字面量,直接传入一个需要执行的方法名称字符串)

$("#myModal").modal();
$("#myModal").modal({keyboard:false});
$("#myModal").modal('show');

每个插件都有一个Constructor属性,表示原始的构造函数,比如fn.alert.Constructor也可以通过(‘选择器').data(‘bs.插件名称')获取特定插件的实例

2.html声明式就是直接在html中进行声明data-* 自定义属性即可

若想禁用方法

//命名空间为data-api的全部事件禁用
$(document).off('.data-api');
//禁用特定插件的默认行为,禁用该插件所在命名空间下事件即可
$(document).off('.alert.data-api');
//禁用该alert插件的click事件
$(document).off('click.alert.data-api');

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
很可爱的输入框
Aug 03 Javascript
仅Firefox中链接A无法实现模拟点击以触发其默认行为
Jul 31 Javascript
分析Node.js connect ECONNREFUSED错误
Apr 09 Javascript
浏览器打开层自动缓慢展开收缩实例代码
Jul 04 Javascript
JS 如何获取radio选中后的值及不选择取radio的值
Oct 28 Javascript
jquery map方法使用示例
Apr 23 Javascript
Javascript验证用户输入URL地址是否为空及格式是否正确
Oct 09 Javascript
jQuery实现简单的间隔向上滚动效果
Mar 09 Javascript
Bootstrap Fileinput文件上传组件用法详解
May 10 Javascript
使用vue-cli+webpack搭建vue开发环境的方法
Dec 22 Javascript
讲解vue-router之什么是动态路由
May 28 Javascript
如何安装控制器JavaScript生成插件详解
Oct 21 Javascript
如何解决hover在ie6中的兼容性问题
Dec 15 #Javascript
Bootstrap整体框架之CSS12栅格系统
Dec 15 #Javascript
Bootstrap CSS布局之列表
Dec 15 #Javascript
BootStrap整体框架之基础布局组件
Dec 15 #Javascript
JS弹性运动实现方法分析
Dec 15 #Javascript
JS经典正则表达式笔试题汇总
Dec 15 #Javascript
javascript中闭包概念与用法深入理解
Dec 15 #Javascript
You might like
模仿OSO的论坛(四)
2006/10/09 PHP
PHP实现多图片上传类实例
2014/07/26 PHP
ThinkPHP模板标签eq if 中区分0,null,false的方法
2017/03/24 PHP
Laravel 模型关联基础教程详解
2019/09/17 PHP
Laravel创建数据库表结构的例子
2019/10/09 PHP
如何解决PHP获取不到SESSION信息之一般情况
2019/10/10 PHP
jQuery Ajax 全解析
2009/02/08 Javascript
ie8模式下click无反应点击option无反应的解决方法
2014/10/11 Javascript
Jquery实现顶部弹出框特效
2015/08/08 Javascript
Node.js与MySQL交互操作及其注意事项
2016/10/05 Javascript
Vue.js组件tabs实现选项卡切换效果
2016/12/01 Javascript
JQuery.validationEngine表单验证插件(推荐)
2016/12/10 Javascript
详解如何较好的使用js
2016/12/16 Javascript
简单的vue-resourse获取json并应用到模板示例
2017/02/10 Javascript
Node学习记录之cluster模块
2017/05/31 Javascript
JavaScript监听手机物理返回键的两种解决方法
2017/08/14 Javascript
Three.js利用dat.GUI如何简化试验流程详解
2017/09/26 Javascript
AngularJS实现的省市二级联动功能示例【可对选项实现增删】
2017/10/26 Javascript
Vue项目webpack打包部署到Tomcat刷新报404错误问题的解决方案
2018/05/15 Javascript
原生js实现form表单序列化的方法
2018/08/02 Javascript
详解在Node.js中发起HTTP请求的5种方法
2019/01/10 Javascript
Vue实现浏览器打印功能的代码
2020/04/17 Javascript
vue 组件间的通信之子组件向父组件传值的方式
2020/07/29 Javascript
Django中使用第三方登录的示例代码
2018/08/20 Python
浅析python的优势和不足之处
2018/11/20 Python
pytorch实现用CNN和LSTM对文本进行分类方式
2020/01/08 Python
PyCharm设置注释字体颜色以及是否倾斜的操作
2020/09/16 Python
CSS3为背景图设置遮罩并解决遮罩样式继承问题
2020/06/22 HTML / CSS
EJB的基本架构
2016/09/22 面试题
什么是会话Bean
2015/05/14 面试题
酒店拾金不昧表扬信
2014/01/18 职场文书
六个一活动实施方案
2014/03/21 职场文书
手机被没收的检讨书
2014/10/04 职场文书
vue实现列表拖拽排序的示例代码
2022/04/08 Vue.js
Spring Data JPA框架Repository自定义实现
2022/04/28 Java/Android
Nginx开源可视化配置工具NginxConfig使用教程
2022/06/21 Servers