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 相关文章推荐
获取css样式表内样式的js函数currentStyle(IE),defaultView(FF)
Feb 14 Javascript
javascript之典型高阶函数应用介绍二
Jan 10 Javascript
JS中数组Array的用法示例介绍
Feb 20 Javascript
jQuery EasyUI实现右键菜单变灰不可用效果
Sep 24 Javascript
jQuery弹出窗口简单实现代码
Mar 09 Javascript
实例详解display:none与visible:hidden的区别
Mar 30 Javascript
js弹性势能动画之抛物线运动实例详解
Jul 27 Javascript
vue中axios实现数据交互与跨域问题
May 12 Javascript
Vue内部渲染视图的方法
Sep 02 Javascript
vux-scroller实现移动端上拉加载功能过程解析
Oct 08 Javascript
vuex页面刷新导致数据丢失的解决方案
Dec 10 Vue.js
使用Cargo工具高效创建Rust项目
Aug 14 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
动易数据转成dedecms的php程序
2007/04/07 PHP
PHP Google的translate API代码
2008/12/10 PHP
PHP查询数据库中满足条件的记录条数(两种实现方法)
2013/01/29 PHP
PHP实现HTTP断点续传的方法
2015/06/17 PHP
PHP实现对xml的增删改查操作案例分析
2017/05/19 PHP
laravel 判断查询数据库返回值的例子
2019/10/11 PHP
jQuery 定时局部刷新(setInterval)
2010/11/19 Javascript
jQuery ready函数滥用分析
2011/02/16 Javascript
php跨域调用json的例子
2013/11/13 Javascript
javascript校验价格合法性实例(必须输入2位小数)
2014/05/05 Javascript
浅谈JavaScript中定义变量时有无var声明的区别
2014/08/18 Javascript
jquery的总体架构分析及实现示例详解
2014/11/08 Javascript
JavaScript获取Url里的参数
2014/12/18 Javascript
JavaScript数据类型之基本类型和引用类型的值
2015/04/01 Javascript
JS实现自动固定顶部的悬浮菜单栏效果
2015/09/16 Javascript
分类解析jQuery选择器
2016/11/23 Javascript
jQuery选择器实例应用
2017/01/05 Javascript
Vue form 表单提交+ajax异步请求+分页效果
2017/04/22 Javascript
详解vue.js 开发环境搭建最简单攻略
2017/06/12 Javascript
vue实现搜索功能
2019/05/28 Javascript
Layui实现数据表格中鼠标悬浮图片放大效果,离开时恢复原图的方法
2019/09/11 Javascript
JQuery使用属性addClass、removeClass和toggleClass实现增加和删除类操作示例
2019/11/18 jQuery
[40:29]2018DOTA2亚洲邀请赛 4.7总决赛 LGD vs Mineski 第一场
2018/04/10 DOTA
numpy matrix和array的乘和加实例
2018/06/28 Python
解决安装pycharm后不能执行python脚本的问题
2019/01/19 Python
python中使用while循环的实例
2019/08/05 Python
python实现的生成word文档功能示例
2019/08/23 Python
图解python全局变量与局部变量相关知识
2019/11/02 Python
pymysql模块使用简介与示例
2020/11/17 Python
浅谈Python xlwings 读取Excel文件的正确姿势
2021/02/26 Python
惠普新加坡官方商店:HP Singapore
2020/04/17 全球购物
如何进行Linux分区优化
2016/09/13 面试题
食品厂厂长岗位职责
2014/01/30 职场文书
十佳护士先进事迹
2014/05/08 职场文书
面试必问:圣杯布局和双飞翼布局的区别
2021/05/13 HTML / CSS
vue ant design 封装弹窗表单的使用
2022/06/01 Vue.js