编写jQueryUI插件(widget)

最近在做一个项目的时候,要实现动态渲染弹出框的样式,所以用到widget编写插件。学习一下。

使用Jquery ui 的widget来写插件,比较以实现,因为widget已经实现了一些基本的方法,如_create(),destroy(),其次是踏实单例的。

基本语法:

(function($){

function foo(){}

$.widget("命名空间.插件名",$.继承插件的命名空间.插件名,{/snip/})

})(jQuery);

一般来说工具函数写在widget外面比较合适,但如果你想要这些工具函数被子类继承,则需要写在widget里面。

写在widget里面的,就有public和private之分,规则是:

public方法首字符不是_

private方法首字符是_


当调用方法时,会先判断是否以_开头,如果是则不执行调用。

如果我非要在外面调用private方法,该怎么做?并非一点办法也没有:

var instance = $('<div>');
instance.mywidget('publicFunction'); // work
instance.mywidget('_privateFunction'); // silently fail
instance.data('mywidget')._privateFunction(); // work
$.mynamespace.mywidget.prototype._privateFunction(); // work


Jquery的官方文档中对此写的很清晰。一般来说,jquery ui都是继承自jquery.ui.widget.js这个文件的。这个文件提供了一个工厂方法来创建widget对象。其方法是$.widget(String name, Options prototype).下面简单介绍下这个类提供的方法和属性。在创建widget的时候将重写这些。

destroy():将widget实例从dom对象上移除,在开发widget的时候一般此方法是必须的。就是移除你自己在dom element上添加的样式和行为以及dom结构

options:在这里面保存的是widget的配置信息,在创建widget的时候需要设置一些配置参数。

element:就是widget作用的dom对象。

enable()和disable()这两个方法就是禁用和启用widget的。其实是修改options.disabled。

还有两个私有方法是创建widget的时候要重写的。

_create() 这个方法就是创建widget的方法,在页面调用widget的时候,就会执行此方法,来构建widget。Widget的绝大大多数行为和结构都是在这里创建的。

_init() 这个方法大多数时候不会被重写,这个方法在构建widget的时候在_create后执行。从相关的文档上查询到:

_create()方法在widget构建的时候执行,而_init()方法在构建和重新初始化的时候执行。而destroy方法则是在移除widget的时候被执行。在widget中,所有的私有方法都将加以"_"前缀

_setOption():此方法提供了options的属性的设置,一般情况下如果options里面的参数不需要特殊处理(校验,类型转换,以及设置属性的时候触发某一操作等)的时候不需要对此方法进行重写

事件

如果有自定义的事件,可以采用widget为我们封装好的方法来处理_trigger()这个方法来处理,其调用方法 this._trigger(type, event, data),第一个参数为时间类型,第二个参数为事件event对象,第三个参数为事件要传递的参数。

接下来会写一个简单的jquery ui widget来说明如何开发widget

代码Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/-->$(function(){
 
    // _create() 和 _init() 在第一次调用的时候被执行
    $("div").mywidget();
 
    // widget已经实例化到div上了,此时只执行_init()方法
 /*
 * jQuery Mobile Framework : plugin to provide a dialogs Widget. ver2
 * Copyright (c) JTSage
 * CC 3.0 Attribution.  May be relicensed without permission/notifcation.
 * https://github.com/jtsage/jquery-mobile-simpledialog
 */
 
(function($, undefined ) {
  $.widget( "mobile.simpledialog2", $.mobile.widget, {
	options: {
		version: '1.0.1-2012022700', // jQueryMobile-YrMoDaySerial
		mode: 'blank', // or 'button'
		themeDialog: 'b',
		themeInput: false,
		themeButtonDefault: false,
		themeHeader: 'a',
		
		fullScreen: false,
		fullScreenForce: false,
		dialogAllow: false,
		dialogForce: false,
		
		headerText: false,
		headerClose: false,
		buttonPrompt: false,
		buttonInput: false,
		buttonPassword: false,
		blankContent: false,
		
		resizeListener: true,
		safeNuke: true,
		forceInput: true,
		showModal: true,
		animate: true,
		transition: 'pop',
		clickEvent: 'click',
		zindex: '500',
		width: '580px',
		left: false,
		top: false,
		
		callbackOpen: false,
		callbackOpenArgs: [],
		callbackClose: false,
		callbackCloseArgs: []
	},
	_eventHandler: function(e,p) {
		// Handle the triggers
		var self = e.data.widget,
			o = e.data.widget.options;
		
		if ( ! e.isPropagationStopped() ) {
			switch (p.method) {
				case 'close':
					self.close();
					break;
				case 'html':
					self.updateBlank(p.source);
					break;
			}
		}
	},
	_create: function () {
		var self = this,
			o = $.extend(this.options, this.element.jqmData('options')),
			initDate = new Date(),
			content = $("<div class='ui-simpledialog-container ui-overlay-shadow ui-corner-all ui-simpledialog-hidden " + 
					((o.animate === true) ? o.transition : '') + " ui-body-" + o.themeDialog + "'></div>");
			
		if ( o.themeButtonDefault === false ) { o.themeButtonDefault = o.themeDialog; }
		if ( o.themeInput === false ) { o.themeInput = o.themeDialog; }
		$.mobile.sdCurrentDialog = self;
		if ( typeof $.mobile.sdLastInput !== 'undefined' ) { delete $.mobile.sdLastInput; }
		self.internalID = initDate.getTime();
		self.displayAnchor = $.mobile.activePage.children('.ui-content').first();
		
		self.dialogPage = $("<div data-role='dialog' class='ui-simpledialog-dialog' data-theme='" + o.themeDialog + "'><div data-role='header'></div><div data-role='content'></div></div>");
		self.sdAllContent = self.dialogPage.find('[data-role=content]');
		
		content.appendTo(self.sdAllContent);
		
		self.sdIntContent = self.sdAllContent.find('.ui-simpledialog-container');
		self.sdIntContent.css('width', o.width);
		
		if ( o.headerText !== false || o.headerClose !== false ) {
			self.sdHeader = $('<div style="margin-bottom: 0px;background-color:black;" class="ui-header win-title ui-bar-'+o.themeHeader+'"></div>');
			if ( o.headerClose === true ) {
				$("<a class='ui-btn-right' rel='close' href='#'>Close</a>").appendTo(self.sdHeader).buttonMarkup({ theme  : o.themeHeader, icon   : 'delete', iconpos: 'notext', corners: true, shadow : true });
			}
			$('<h1 class="ui-title">'+((o.headerText !== false)?o.headerText:'')+'</h1>').appendTo(self.sdHeader);
			self.sdHeader.appendTo(self.sdIntContent);
		}
		
		if ( o.mode === 'blank' ) {
			if ( o.blankContent === true ) {
				o.blankContent = self.element.html();
			}
			$(o.blankContent).appendTo(self.sdIntContent);
		} else if ( o.mode === 'button' ) {
			self._makeButtons().appendTo(self.sdIntContent);
		}
		
		self.sdIntContent.appendTo(self.displayAnchor.parent());
		
		self.dialogPage.appendTo( $.mobile.pageContainer )
			.page().css('minHeight', '0px').css('zIndex', o.zindex);
			
		if ( o.animate === true ) { self.dialogPage.addClass(o.transition); }
		
		self.screen = $("<div>", {'class':'ui-simpledialog-screen ui-simpledialog-hidden'})
			.css('z-index', (o.zindex-1))
			.appendTo(self.displayAnchor.parent())
			.bind(o.clickEvent, function(event){
				if ( !o.forceInput ) {
					self.close();
				}
				event.preventDefault();
			});

		if ( o.showModal ) { self.screen.addClass('ui-simpledialog-screen-modal'); }
		
		$(document).bind('simpledialog.'+self.internalID, {widget:self}, function(e,p) { self._eventHandler(e,p); });
	},
	_makeButtons: function () {
		var self = this,
			o = self.options,
			buttonHTML = $('<div></div>'),
			pickerInput = $("<div class='ui-simpledialog-controls'><input class='ui-simpledialog-input ui-input-text ui-shadow-inset ui-corner-all ui-body-"+o.themeInput+"' type='"+((o.buttonPassword===true)?"password":"text")+"' name='pickin' /></div>"),
			pickerChoice = $("<div>", { "class":'ui-simpledialog-controls' });
			
		
		if ( o.buttonPrompt !== false ) {
			self.buttonPromptText = $("<p class='ui-simpledialog-subtitle'>"+o.buttonPrompt+"</p>").appendTo(buttonHTML);
		}
		
		if ( o.buttonInput !== false ) {
			$.mobile.sdLastInput = "";
			pickerInput.appendTo(buttonHTML);
			pickerInput.find('input').bind('change', function () {
				$.mobile.sdLastInput = pickerInput.find('input').first().val();
				self.thisInput = pickerInput.find('input').first().val();
			});
		}
		
		pickerChoice.appendTo(buttonHTML);
		
		self.butObj = [];
		
		$.each(o.buttons, function(name, props) {
			props = $.isFunction( props ) ? { click: props } : props;
			props = $.extend({
				text   : name,
				id     : name + self.internalID,
				theme  : o.themeButtonDefault,
				icon   : 'check',
				iconpos: 'left',
				corners: 'true',
				shadow : 'true',
				args   : [],
				close  : true
			}, props);
			
			self.butObj.push($("<a href='#'>"+name+"</a>")
				.appendTo(pickerChoice)
				.attr('id', props.id)
				.buttonMarkup({
					theme  : props.theme,
					icon   : props.icon,
					iconpos: props.iconpos,
					corners: props.corners,
					shadow : props.shadow
				}).unbind("vclick click")
				.bind(o.clickEvent, function() {
					if ( o.buttonInput ) { self.sdIntContent.find('input [name=pickin]').trigger('change'); }
					//var returnValue = props.click.apply(self.element[0], arguments);
					var returnValue = props.click.apply(self, $.merge(arguments, props.args));
					if ( returnValue !== false && props.close === true ) {
						self.close();
					}
				})
			);
		});
		
		return buttonHTML;
	},
	_getCoords: function(widget) {
		var self = widget,
			docWinWidth   = $.mobile.activePage.width(),
			docWinHighOff = $(window).scrollTop(),
			docWinHigh    = $(window).height(),
			diaWinWidth   = widget.sdIntContent.innerWidth(),
			diaWinHigh    = widget.sdIntContent.outerHeight(),
			
			coords        = {
				'high'    : $(window).height(),
				'width'   : $.mobile.activePage.width(),
				'fullTop' : $(window).scrollTop(),
				'fullLeft': $(window).scrollLeft(),
				'winTop'  : docWinHighOff + ((widget.options.top !== false) ? widget.options.top : (( docWinHigh / 2 ) - ( diaWinHigh / 2 ) )),
				'winLeft' : ((widget.options.left !== false) ? widget.options.left : (( docWinWidth / 2 ) - ( diaWinWidth / 2 ) ))
			};
			coords.winTop = 40;
		//if ( coords.winTop < 55 ) { coords.winTop = 40; }
		return coords;
	},
	_orientChange: function(e) {
		var self = e.data.widget,
			o = e.data.widget.options,
			coords = e.data.widget._getCoords(e.data.widget);
		
		e.stopPropagation();
		
		if ( self.isDialog === true ) {
			return true;
		} else {
			if ( o.fullScreen === true && ( coords.width < 400 || o.fullScreenForce === true ) ) {
				self.sdIntContent.css({'border': 'none', 'position': 'absolute', 'top': coords.fullTop, 'left': coords.fullLeft, 'height': coords.high, 'width': coords.width, 'maxWidth': coords.width }).removeClass('ui-simpledialog-hidden');
			} else {
				self.sdIntContent.css({'position': 'absolute', 'top': coords.winTop, 'left': coords.winLeft}).removeClass('ui-simpledialog-hidden');
			}
		}
	},
	repos: function() {
		var bsEvent = { data: {widget:this}, stopPropagation: function () { return true; }};
		this._orientChange(bsEvent);
	},
	open: function() {
		var self = this,
			o = this.options,
			coords = this._getCoords(this);
		
		self.sdAllContent.find('.ui-btn-active').removeClass('ui-btn-active');
		self.sdIntContent.delegate('[rel=close]', o.clickEvent, function (e) { e.preventDefault(); self.close(); });
		
		if ( ( o.dialogAllow === true && coords.width < 400 ) || o.dialogForce ) {
			self.isDialog = true;
			
			if ( o.mode === 'blank' ) { // Custom selects do not play well with dialog mode - so, we turn them off.
				self.sdIntContent.find('select').each(function () {
					$(this).jqmData('nativeMenu', true);
				});
			}
			
			self.displayAnchor.parent().unbind("pagehide.remove");
			self.sdAllContent.append(self.sdIntContent);
			self.sdAllContent.trigger('create');
			if ( o.headerText !== false ) {
				self.sdHeader.find('h1').appendTo(self.dialogPage.find('[data-role=header]'));
				self.sdIntContent.find('.ui-header').empty().removeClass();
			}
			if ( o.headerClose === true ) {
				self.dialogPage.find('.ui-header a').bind('click', function () {
					setTimeout("$.mobile.sdCurrentDialog.destroy();", 500);
				});
			} else {
				self.dialogPage.find('.ui-header a').remove();
			}
			
			self.sdIntContent.removeClass().css({'top': 'auto', 'width': 'auto', 'left': 'auto', 'marginLeft': 'auto', 'marginRight': 'auto', 'zIndex': o.zindex});
			$.mobile.changePage(self.dialogPage, {'transition': (o.animate === true) ? o.transition : 'none'});
		} else {
			self.isDialog = false;
			self.selects = [];
			
			if ( o.fullScreen === false ) {
				if ( o.showModal === true && o.animate === true ) { self.screen.fadeIn('slow'); }
				else { self.screen.removeClass('ui-simpledialog-hidden'); }
			}
			
			self.sdIntContent.addClass('ui-overlay-shadow in').css('zIndex', o.zindex).trigger('create');
			
			if ( o.fullScreen === true && ( coords.width < 400 || o.fullScreenForce === true ) ) {
				self.sdIntContent.removeClass('ui-simpledialog-container').css({'border': 'none', 'position': 'absolute', 'top': coords.fullTop, 'left': coords.fullLeft, 'height': coords.high, 'width': coords.width, 'maxWidth': coords.width }).removeClass('ui-simpledialog-hidden');
			} else {
				self.sdIntContent.css({'position': 'absolute', 'top': coords.winTop, 'left': coords.winLeft}).removeClass('ui-simpledialog-hidden');
			}
			
			$(document).bind('orientationchange.simpledialog', {widget:self}, function(e) { self._orientChange(e); });
			if ( o.resizeListener === true ) {
				$(window).bind('resize.simpledialog', {widget:self}, function (e) { self._orientChange(e); });
			}
		}
		if ( $.isFunction(o.callbackOpen) ) {
			o.callbackOpen.apply(self, o.callbackOpenArgs);
		}
	},
	close: function() {
		if($("#chioceDramaScope_" + g_currentPage)){
			$("#chioceDramaScope_" + g_currentPage).hide();
		}
		if(searchTextHidden==1){
			$("#searchText_searchResult").css("visibility","visible");
			searchTextHidden = 0;
		}
		if(searchTextHidden==2){
			$("#searchText_searchResult2").css("visibility","visible");
			searchTextHidden = 0;
		}
		var self = this, retty;
		
		if ( $.isFunction(self.options.callbackClose) ) {
			retty = self.options.callbackClose.apply(self, self.options.callbackCloseArgs);
			if ( retty === false ) { return false; }
		}
		
		if ( self.isDialog ) {
			$(self.dialogPage).dialog('close');
			self.sdIntContent.addClass('ui-simpledialog-hidden');
			self.sdIntContent.appendTo(self.displayAnchor.parent());
			if ( $.mobile.activePage.jqmData("page").options.domCache != true ) {
				$.mobile.activePage.bind("pagehide.remove", function () {
					$(this).remove();
				});
			}
		} else {
			if ( self.options.showModal === true && self.options.animate === true ) {
				self.screen.fadeOut('slow');
			} else {
				self.screen.addClass('ui-simpledialog-hidden');
			}
			self.sdIntContent.addClass('ui-simpledialog-hidden').removeClass('in');
			$(document).unbind('orientationchange.simpledialog');
			if ( self.options.resizeListener === true ) { $(window).unbind('resize.simpledialog'); }
		}
		
		$.mobile.activePage.find('.ui-btn-active').removeClass('ui-btn-active');
		
		if ( self.isDialog === true || self.options.animate === true ) {			
			setTimeout("$.mobile.sdCurrentDialog.destroy();", 700);//update 2012-6-17 by wyx wo
		} else {
			self.destroy();
		}
	},
	destroy: function() {
		var self = this,
			ele = self.element;
		
		if ( self.options.mode === 'blank' ) {
			$.mobile.sdCurrentDialog.sdIntContent.find('select').each(function() {
				if ( $(this).data('nativeMenu') == false ) {
					$(this).data('selectmenu').menuPage.remove();
					$(this).data('selectmenu').screen.remove();
					$(this).data('selectmenu').listbox.remove();
				}
			});
		}
		
		$(self.sdIntContent).remove();
		$(self.dialogPage).remove();
		$(self.screen).remove();
		$(document).unbind('simpledialog.'+self.internalID);
		delete $.mobile.sdCurrentDialog;
		$.Widget.prototype.destroy.call(self);
		if ( self.options.safeNuke === true && $(ele).parents().length === 0 && $(ele).contents().length === 0 ) {
			ele.remove();
		}
	},
	updateBlank: function (newHTML) {
		var self = this,
			o = this.options;
			
		self.sdIntContent.empty();
			
		if ( o.headerText !== false || o.headerClose !== false ) {
			self.sdHeader = $('<div style="background-color:black" class="ui-header win-title ui-bar-'+o.themeHeader+'"></div>');
			if ( o.headerClose === true ) {
				$("<a class='ui-btn-right' rel='close' href='#'>Close</a>").appendTo(self.sdHeader).buttonMarkup({ theme  : o.themeHeader, icon   : 'delete', iconpos: 'notext', corners: true, shadow : true });
			}
			$('<h1 class="ui-title">'+((o.headerText !== false)?o.headerText:'')+'</h1>').appendTo(self.sdHeader);
			self.sdHeader.appendTo(self.sdIntContent);
		}
		
		$(newHTML).appendTo(self.sdIntContent);
		self.sdIntContent.trigger('create');
		$(document).trigger('orientationchange.simpledialog');
	},
	_init: function() {
		this.open();
	}
  });
})( jQuery );


    $("div").mywidget();
 
    // 销毁widget
    $("div").mywidget("destroy");
 
    // 因为widget已经被销毁,此时_create()和_init()方法都将被执行
    $("div").mywidget();
 
});
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值