这几天老师让我看一下DWZ,看了一下给的文档,发现是一头雾水,只讲了怎么用,但是却不知道它是怎么个流程来实现的,于是便自己对着demo看了一下具体的实现过程,下面给大家分析一下。
先贴一下我仿照demo写的一个小例子的代码。
<body>
<div id="leftside"> <!-- 左边的div用来存储树状的菜单结构 -->
<div id="sidebar">
<div id="toggleCollapse"><h2>主菜单</h2><span>收缩</span></div>
<div class="accordion" fillSpace="sidebar">
<div class="accordionHeader">
<h2><span>Folder</span>界面组件</h2>
</div>
<div class="accordionContent">
<ul class="tree treeFolder">
<li><a href="liuwei.html" target="navTab">主面板框架</a>
<ul>
<li><a href="liuwei.html" target="navTab" rel="liuwei">刘伟页面</a></li>
<li><a href="ningqin.html" target="navTab" rel="ningqin">宁琴页面</a></li>
</ul>
</li>
</ul>
</div>
</div>
</div>
</div>
<div id="container">
<div id="navTab" class="tabsPage">
<div class="tabsPageHeader"> <!-- 右边容器头部应该包含tab标签 -->
<div tabsPageHeaderContent>
<ul class="navTab-tab">
<!-- 开始的时候并没有标签 -->
</ul>
</div>
<div class="tabsLeft">left</div>
<div class="tabsRight">right</div>
<div class="tabsMore">more</div>
</div>
<ul class="tabsMoreList"> <!-- 点击更多时,应该会显示 这个链表-->
</ul>
<div class="navTab-panel tabsPageContent layoutBox">
<div class="page unitBox">
</div>
</div>
</div>
</div>
</body>
DWZ号称只需要我们写html文件,尽量不需要我们写js代码(一个合格的程序员不会写js代码岂不可笑)。所以他给的我们那些demo,
尽是一些html文件,却没有相应的响应属性的声明(onclick属性)。这是我们就可能会疑惑了,没有事件声明
怎么来处理事件呢?
实质上,他是有响应事件的声明,只不过,它把这些事件的声明通过js代码来执行。比如说看demo中的
如下代码:
$(function(){
DWZ.init("dwz.frag.xml", {
loginUrl:"login_dialog.html", loginTitle:"登录", // 弹出登录对话框
// loginUrl:"login.html", // 跳到登录页面
statusCode:{ok:200, error:300, timeout:301}, //[可选]
pageInfo:{pageNum:"pageNum", numPerPage:"numPerPage", orderField:"orderField", orderDirection:"orderDirection"}, //[可选]
keys: {statusCode:"statusCode", message:"message"}, //[可选]
ui:{hideMode:'offsets'}, //[可选]hideMode:navTab组件切换的隐藏方式,支持的值有’display’,
//’offsets’负数偏移位置的值,默认值为’display’
debug:false, // 调试模式 [true|false]
callback:function(){
initEnv();
$("#themeList").theme({themeBase:"themes"}); // themeBase 相对于index页面的主题base路径
}
});
});
这里定义了一个自执行函数,也就是文档加载完的时候会自动执行的函数,在这个函数中有一个回调函数,里面有调用initEnv()方法。在这个initEnv方法中有对各种元素组件的响应事件的声明。其中initEnv()函数的声明在dwz.ui.js文件中,下面是initEnv()方法的源码:
function initEnv() {
$("body").append(DWZ.frag["dwzFrag"]);
$(window).resize(function(){
initLayout();
$(this).trigger(DWZ.eventType.resizeGrid);
});
var ajaxbg = $("#background,#progressBar");
ajaxbg.hide();
$(document).ajaxStart(function(){
ajaxbg.show();
}).ajaxStop(function(){
ajaxbg.hide();
});
if ($.fn.jBar) $("#leftside").jBar({minW:150, maxW:700});
if ($.taskBar) $.taskBar.init();
if ($.fn.switchEnv) $("#switchEnvBox").switchEnv();
if ($.fn.navMenu) $("#navMenu").navMenu();
setTimeout(function(){
initLayout();
if (window.navTab)
navTab.init();
// 注册DWZ插件。
DWZ.regPlugins.push(initUI); //第三方jQuery插件注册方法:DWZ.regPlugins.push(function($p){});
// 首次初始化插件
$(document).initUI(); //在initUI中有对各种插件的初始化,例如navTab啥的
// navTab styles
var jTabsPH = $("div.tabsPageHeader");
jTabsPH.find(".tabsLeft").hoverClass("tabsLeftHover");
jTabsPH.find(".tabsRight").hoverClass("tabsRightHover");
jTabsPH.find(".tabsMore").hoverClass("tabsMoreHover");
$(document).trigger(DWZ.eventType.initEnvAfter);
}, 10);
}
在这个方法中,有指明在文档加载完之后的延迟指定对插件的初始化,也就是使得当前网页调用initUI()方法。在initUI()方法中有对各种存在的插件的初始化,其中对<a target="natTab">的初始化代码如下:
// navTab
$("a[target=navTab]", $p).each(function(){ //从这里开始的,对于每一个target=navTab的<a>
$(this).click(function(event){
var $this = $(this); //得到<a>
var title = $this.attr("title") || $this.text();
var tabid = $this.attr("rel") || "_blank"; //默认_blank或者指定为rel
var fresh = eval($this.attr("fresh") || "true"); //是否要刷新
var external = eval($this.attr("external") || "false");
var url = unescape($this.attr("href")).replaceTmById($(event.target).parents(".unitBox:first"));
DWZ.debug(url);
if (!url.isFinishedTm()) {
alertMsg.error($this.attr("warn") || DWZ.msg("alertSelectMsg"));
return false;
}
navTab.openTab(tabid, url,{title:title, fresh:fresh, external:external}); //调用navTab对象中的方法
event.preventDefault();
});
});
在这个代码中,接受了从<a>标签传过来的各种信息,包括需要打开的url地址,以及新打开的tab的id。接着他就会去调用dwz.natTab.js文件中的navTab对象的openTab()方法来打开相应的url地址。我们接着去看dwz.natTab.js中的一些代码。先着重了解一下navTab的定义的变量和init()方法,下面是源码:
var navTab = { //navTab对象,在其他文件中可直接调用里面的方法
componentBox: null, // tab component. contain tabBox, prevBut, nextBut, panelBox
_tabBox: null,
_prevBut: null,
_nextBut: null,
_panelBox: null,
_moreBut:null,
_moreBox:null,
_currentIndex: 0,
_op: {id:"navTab", stTabBox:".navTab-tab", stPanelBox:".navTab-panel", mainTabId:"main",
close$:"a.close", prevClass:"tabsLeft", nextClass:"tabsRight", stMore:".tabsMore", stMoreLi:"ul.tabsMoreList"},
init: function(options){
if ($.History) $.History.init("#container");
var $this = this;
$.extend(this._op, options);
this.componentBox = $("#"+this._op.id); //找到id为navTab的容器
this._tabBox = this.componentBox.find(this._op.stTabBox); //在这个容器中寻找class为navTab-tab的容器
this._panelBox = this.componentBox.find(this._op.stPanelBox); //在这个容器中寻找class为navTab-panel的容器
this._prevBut = this.componentBox.find("."+this._op.prevClass); //找到左边的那个tab标签
this._nextBut = this.componentBox.find("."+this._op.nextClass); //找到右边的那个标签
this._moreBut = this.componentBox.find(this._op.stMore); //找到class为tabsMore的元素
this._moreBox = this.componentBox.find(this._op.stMoreLi); //找到ul.tabsMoreList标签,也就是显示更多
this._prevBut.click(function(event) {$this._scrollPrev()});
this._nextBut.click(function(event) {$this._scrollNext()});
this._moreBut.click(function(){
$this._moreBox.show();
return false;
});
$(document).click(function(){$this._moreBox.hide()});
this._contextmenu(this._tabBox);
this._contextmenu(this._getTabs());
this._init();
this._ctrlScrollBut();
},
未完,下面还有其他方法
}
在这个方法中它定义了为某个div重新载入相应的url链接页面所需要的参数。比如说实现显示各种tab的tab链表及相应的内容的panel 的容器,以及显示tab链表的容器,显示tab对应的文本内容的容器,然后在init()方法中对这些 需要的参数进行的初始化赋值。注意, 上面这些初始化赋值都是通过选择器来根据class类别来找到相应的容器来实现的,所以我们在用dwz的时候,一定要保证和上面_op变量中那些class名保持一致,不然的话,就无法使用dwz。你可以看我贴出的demo代码,里面的各种容器名字和_op变量中保持一致。比如class="navTab-tab",class="navTab-panel"等等等等,说白了,我们用dwz,就是根据它的一些约束,来帮我们实现一些js代码来实现的功能,所以才号称我们不用写js代码。
最后我们再看一下openTab()方法,其源码如下:
openTab: function(tabid, url, options){ //if found tabid replace tab, else create a new tab.
var op = $.extend({title:"New Tab", type:"GET", data:{}, fresh:true, external:false}, options); //用于合并对象
var iOpenIndex = this._indexTabId(tabid);
if (iOpenIndex >= 0){ //如果这个tab已经存在
var $tab = this._getTabs().eq(iOpenIndex); //找到natTab-tab下对应的那个<li>标签
var span$ = $tab.attr("tabid") == this._op.mainTabId ? "> span > span" : "> span"; //找到<li>标签的tabid属性对应的tabid名
$tab.find(">a").attr("title", op.title).find(span$).html(op.title);
var $panel = this._getPanels().eq(iOpenIndex); //找到navTab-panel下对应的div
if(url && (op.fresh || $tab.attr("url") != url)) {
$tab.attr("url", url);
if (op.external || url.isExternalUrl()) {
$tab.addClass("external");
navTab.openExternal(url, $panel);
} else {
$tab.removeClass("external");
$panel.ajaxUrl({
type:op.type, url:url, data:op.data, callback:function(){
navTab._loadUrlCallback($panel); //向那个div中重新载入信息
}
});
}
}
this._currentIndex = iOpenIndex;
} else { //如果不存在,则直接新建一个,需要在navTab-tab中新建一个<li>标签,
//以及在navTab-panel中新加一个div
var tabFrag = '<li tabid="#tabid#"><a href="javascript:" title="#title#" class="#tabid#"><span>#title#</span></a>
<a href="javascript:;" class="close">close</a></li>';
this._tabBox.append(tabFrag.replaceAll("#tabid#", tabid).replaceAll("#title#", op.title));
this._panelBox.append('<div class="page unitBox"></div>');
this._moreBox.append('<li><a href="javascript:" title="#title#">#title#</a></li>'.replaceAll("#title#", op.title));
var $tabs = this._getTabs();
var $tab = $tabs.filter(":last");
var $panel = this._getPanels().filter(":last");
if(url) {
if (op.external || url.isExternalUrl()) {
$tab.addClass("external");
navTab.openExternal(url, $panel);
} else {
$tab.removeClass("external");
$panel.ajaxUrl({
type: op.type, url: url, data: op.data, callback: function () {
navTab._loadUrlCallback($panel); //也是重新载入信息
}
});
}
}
if ($.History) {
setTimeout(function(){
$.History.addHistory(tabid, function(tabid){
var i = navTab._indexTabId(tabid);
if (i >= 0) navTab._switchTab(i);
}, tabid);
}, 10);
}
this._currentIndex = $tabs.size() - 1;
this._contextmenu($tabs.filter(":last").hoverClass("hover"));
}
this._init();
this._scrollCurrent();
this._getTabs().eq(this._currentIndex).attr("url", url);
}
这样就实现了通过点击相应的tab来重新载入相应的内容。