1. Opening analysis
Hi, do you still remember the previous article? It mainly tells how a "Tab" plugin organizes code and implements it, and how process design is combined with object-oriented thinking design is
How to design a plug-in? The two methods have their own advantages and disadvantages to learn from each other's strengths and weaknesses. This series of articles is learning-oriented, and everyone decides how to use the specific scenarios. From this article, we still focus on that "Tab" instance.
Continue to expand related functions. Hehehe, say less nonsense, get to the point. Directly on the actual renderings:
You have seen it, and a new feature has been added. If the number of entries of our module configuration information item when we are initializing is greater than what we specify, it will be displayed in "More Modules"
In the hidden list of operation items, our initialization parameter configuration has also been newly adjusted, such as an additional "displayMax" to specify the number of entries at initialization, and an item attribute, "status"
During initialization, no configuration is required. Dynamic configuration is generated in the program, which increases program flexibility. Let’s analyze it in detail below.
(II), case analysis
(1) First, determine what this plugin does. Let’s take a look at the call method of the plug-in and the configuration parameter description. The following code:
The code copy is as follows:
{
buttonText: "Add module",
result: [
{
text : "Wizard prompt",
url : "help.html",
showClose : "0"
} ,
{
text : "Student Information",
url : "info.html",
showClose : "1"
} ,
{
text : "Student Classification",
url : "category.html",
showClose : "1"
} ,
{
text : "Big Bear {{bb}}",
url : "bb.html",
showClose : "1"
} ,
{
text : "Beta test module",
url : "test.html",
showClose : "1"
} ,
{
text : "Three Fatty Men",
url : "help.html",
showClose : "1"
} ,
{
text : "Four Bald Men",
url : "help.html",
showClose : "1"
}
],
displayMax : 5 // Maximum display items
}
"bigbear.ui.createTab" contains two parameters. The first is the dom node object and the second is the plug-in parameter option. "buttonText" represents the text description of the operation button in the "Tab" plug-in.
"result" is an array that contains the properties of the tab item, including text description, the URL used to request it when clicking the tab item, "showClose" represents whether the tab option displays the close button.
"status" is also removed during initialization and does not require configuration, and the configuration is generated dynamically in the program. There may be a closed state, which is expressed as: 1-default display, 0-off status, and 2-than the default number of entries.
(2) Functions are introduced in steps
1---, initialize the plug-in through optional parameters:
The code copy is as follows:
$(function(){
bigbear.ui.createTab($("#tab"),{
buttonText: "Add module",
result: [
{
text : "Wizard prompt",
url : "help.html",
showClose : "0"
} ,
{
text : "Student Information",
url : "info.html",
showClose : "1"
} ,
{
text : "Student Classification",
url : "category.html",
showClose : "1"
} ,
{
text : "Big Bear {{bb}}",
url : "bb.html",
showClose : "1"
} ,
{
text : "Beta test module",
url : "test.html",
showClose : "1"
} ,
{
text : "Three Fatty Men",
url : "help.html",
showClose : "1"
} ,
{
text : "Four Bald Men",
url : "help.html",
showClose : "1"
}
],
displayMax : 5 // Maximum display items
}) ;
}) ;
2---, render and complete time binding and related business logic, such as verification of the number of entries during initialization.
The code copy is as follows:
tabProto.init = function(){
if(this._isEmptyResult()){
this._setContent("No module yet!");
}
var that = this ;
this.getElem().find(".title .adder")
.text("+" + this.getOpts()["buttonText"])
.on("click",function(){
that.getElem().find(".console-panel").slideToggle(function(){
that._renderConsolePanel("0");
}) ;
}) ;
$.each(this.getOpts()["result"],function(i,item){
if(that._isDisplayMax(i + 1)){
that._saveOrUpdateStatus(item,"1");
}
else{
that._saveOrUpdateStatus(item,"2");
}
that._render(item);
}) ;
if(!that._isDisplayMax(this.getOpts()["result"].length)){
this.getElem().find(".title .more-mod").fadeIn(function(){
$(this).find(".tag").on("click",function(){
var root = $(this).next();
root.empty() ;
$.each(that._getItemListByStatus("2"),function(i,data){
$("<div></div>").text(data["text"])
.on("click",function(){
if(that._getItemListByStatus("1").length < that.getOpts()["displayMax"]){
that.getElem().find(".title .items div").eq(data["index"]).fadeIn(function(){
that._saveOrUpdateStatus(data,"1");
}) ;
}
else{
alert("No modules can be added, it is currently the maximum number!") ;
}
})
.appendTo(root);
}) ;
root.toggle() ;
}) ;
});
}
this.getElem().find(".title .items div")
.eq(0)
.trigger("click"); // Assume that there must be one, otherwise the plug-in will not make much sense!
} ;
3---, tab switching and data content rendering operations.
The code copy is as follows:
tabProto._setCurrent = function(index){
var items = this.getElem().find(".title .items div").removeClass("active");
items.eq(index).addClass("active");
var contents = this.getElem().find(".content .c").hide();
contents.eq(index).show();
} ;
The code copy is as follows:
item.on("click",function(){
that._setCurrent($(this).index()) ;
that._getContent(data["url"]).done(function(result){
that._setContent(result);
})
.fail(function(){
throw new Error("Net Error !");
});
})
The code copy is as follows:
tabProto._setContent = function(html){
this.getElem().find(".content").html(html);
} ;
tabProto._getContent = function(url){
return $.ajax({
url : url
}) ;
} ;
4---, the core auxiliary data operation method does not involve dom.
The code copy is as follows:
/* update time 2015 1/26 15:36 */
tabProto._isDisplayMax = function(size){
var displayMax = this.getOpts()["displayMax"] || 5;
return (size <= displayMax) ? true : false ;
} ;
tabProto._isEmptyResult = function(){
if(!this.getOpts()["result"].length){
return false ;
}
return true ;
} ;
tabProto._saveOrUpdateStatus = function(item,status){
item["status"] = status ;
} ;
tabProto._getItemListByStatus = function(status){
var list = [] ;
var result = this.getOpts()["result"] ;
$.each(result,function(i,item){
if(status == item["status"]){
list.push(item);
}
}) ;
return list ;
} ;
tabProto._getStatusByIndex = function(index){
var status = null ;
var result = this.getOpts()["result"] ;
$.each(result,function(i,item){
if(index == item["index"]){
status = item["status"] ;
}
}) ;
return status ;
} ;
(III), complete code for learning , this code has been tested, including directory structure and related files.
1, html
The code copy is as follows:
<body>
<div>
Big Bear {{bb}} - DXJ UI ------ Tab
</div>
<div>
<div id="tab">
<div>
<div>
+ Add student information
</div>
<div>
<!--<div><span>X</span>Welcome Page</div>
<div><span>X</span>User Management</div>
<div><span>X</span>Bigbear</div>-->
</div>
<div>
<div>More Modules</div>
<div>
</div>
</div>
</div>
<div>
</div>
<div>
<!--<div>
<div><span>Name:</span><input type="text" /></div>
<div><span>Note: </span><textarea></textarea></div>
</div> <div><input type="button" value="Save" /></div>
-->
</div>
</div>
</div>
</body>
2, css
The code copy is as follows:
.dxj-ui-hd {
padding:0px ;
margin : 0 auto;
margin-top:30px;
width:780px;
height:60px;
line-height: 60px;
background: #3385ff;
color:#ffff;
font-family: "Microsoft Yahei";
font-size: 28px;
text-align: center;
font-weight:bold;
}
.dxj-ui-bd {
padding:0px ;
margin : 0 auto;
width:778px;
padding-top : 30px ;
padding-bottom : 30px ;
overflow: hidden;
border:1px solid #3385ff;
}
.dxj-ui-bd #tab {
padding:0px ;
margin : 0 auto;
width:720px;
overflow: hidden;
position:relative;
}
.dxj-ui-bd #tab .title {
width:720px;
overflow: hidden;
border-bottom:2px solid #3385ff;
}
.dxj-ui-bd #tab .title .adder {
width:160px;
height:32px;
line-height: 32px;
background: #DC143C;
color:#ffff;
font-family: "Microsoft Yahei";
font-size: 14px;
text-align: center;
font-weight:bold;
float : left;
cursor:pointer;
}
.dxj-ui-bd #tab .title .more-mod {
overflow:hidden;
border:1px solid #DC143C;
width:70px;
position:absolute;
right:0;
margin-right:6px;
display:none;
}
.dxj-ui-bd #tab .title .more-mod .tag{
height:32px;
line-height:32px;
width:70px;
background: #DC143C;
color:#ffff;
font-family: arial ;
font-size: 12px;
text-align: center;
cursor:pointer;
}
.dxj-ui-bd #tab .title .more-mod .mods {
overflow:hidden;
width:70px;
display:none;
}
.dxj-ui-bd #tab .title .more-mod .mods div {
height:24px;
line-height:24px;
width:62px;
font-family: arial ;
font-size: 12px;
cursor:pointer;
padding-left:10px;
}
.dxj-ui-bd #tab .title .items {
height:32px;
width:480px;
overflow: hidden;
float : left;
}
.dxj-ui-bd #tab .title .items div {
padding:0px;
margin-left:10px;
width:84px;
height:32px;
line-height: 32px;
background: #3385ff;
color:#ffff;
font-family: arial ;
font-size: 12px;
text-align: center;
position:relative;
float : left;
cursor:pointer;
}
.dxj-ui-bd #tab .title .items div span.del {
width:16px;
height:16px;
line-height: 16px;
display:block;
background: #DC143C;
position:absolute;
right:0 ;
top:0;
cursor:pointer;
}
.dxj-ui-bd #tab .content {
width:716px;
padding-top:30px;
overflow: hidden;
border:2px solid #3385ff;
border-top:0px;
min-height:130px;
text-align:center;
}
.dxj-ui-bd #tab .content table {
margin : 0 auto ;
}
.dxj-ui-bd #tab .content div.c {
padding-top : 20px ;
padding-left:20px;
background:#eee;
height:140px;
}
.dxj-ui-bd #tab .content div.c .input-content {
margin-top : 10px ;
font-family: arial ;
font-size: 12px;
}
.dxj-ui-bd #tab .console-panel {
width:716px;
padding-top:20px;
padding-bottom:20px;
overflow: hidden;
border:2px solid #3385ff;
border-top:0px;
border-bottom:2px solid #3385ff;
background:#fff;
display:none;
}
.active {
font-weight:bold ;
}
3, bigbear.js
The code copy is as follows:
(function($){
var win = window;
var bb = win.bigbear = win.bigbear || {
ui : {}
} ;
var ui = bb.ui = {} ;
var Tab = function(elem,opts){
this.elem = elem ;
this.opts = opts ;
} ;
var tabProto = Tab.prototype;
/* update time 2015 1/26 15:36 */
tabProto._isDisplayMax = function(size){
var displayMax = this.getOpts()["displayMax"] || 5;
return (size <= displayMax) ? true : false ;
} ;
tabProto._isEmptyResult = function(){
if(!this.getOpts()["result"].length){
return false ;
}
return true ;
} ;
tabProto._saveOrUpdateStatus = function(item,status){
item["status"] = status ;
} ;
tabProto._getItemListByStatus = function(status){
var list = [] ;
var result = this.getOpts()["result"] ;
$.each(result,function(i,item){
if(status == item["status"]){
list.push(item);
}
}) ;
return list ;
} ;
tabProto._getStatusByIndex = function(index){
var status = null ;
var result = this.getOpts()["result"] ;
$.each(result,function(i,item){
if(index == item["index"]){
status = item["status"] ;
}
}) ;
return status ;
} ;
tabProto._renderConsolePanel = function(status){
var that = this ;
var root = that.getElem().find(".console-panel");
this._resetConsolePanel();
$.each(that._getItemListByStatus(status),function(i,item){
var elem = $("<div style='float:left';></div>").appendTo(root) ;
$("<input type='radio' name='addmod' />")
.data("item",item)
.appendTo(elem);
$("<span></span>").text(item["text"]).appendTo(elem);
}) ;
if(root.find("div").size()){
$("<input type='button' value='add module' style='margin-left:20px'/>")
.on("click",function(){
var data = root.find("input[type=radio]:checked").data("item");
if(that._getItemListByStatus("1").length < that.getOpts()["displayMax"]){
that.getElem().find(".title .items div").eq(data["index"]).fadeIn(function(){
that._saveOrUpdateStatus(data,"1");
})
.trigger("click");
}
else{
that._saveOrUpdateStatus(data,"2");
}
that.getElem().find(".title .adder").trigger("click");
})
.appendTo(root);
}
else{
root.text("No items to add yet!");
}
} ;
/* update time 2015 1/26 15:36 */
tabProto._setCurrent = function(index){
var items = this.getElem().find(".title .items div").removeClass("active");
items.eq(index).addClass("active");
var contents = this.getElem().find(".content .c").hide();
contents.eq(index).show();
} ;
tabProto.getElem = function(){
return this.elem ;
} ;
tabProto.getOpts = function(){
return this.opts ;
} ;
tabProto._resetContent = function(){
this.getElem().find(".content").html("");
} ;
tabProto._setContent = function(html){
this.getElem().find(".content").html(html);
} ;
tabProto._getContent = function(url){
return $.ajax({
url : url
}) ;
} ;
tabProto._deleteItem = function(elem){
var that = this ;
this.getElem().find(".title .items div")
.eq(elem.index())
.fadeOut(function(){
that._resetContent() ;
that._saveOrUpdateStatus(elem.data("item"),"0");
that._triggerItem(elem.index() + 1);
}) ;
} ;
tabProto._triggerItem = function(next){
var nextStatus = this._getStatusByIndex(next);
var items = this.getElem().find(".title .items div");
next = items.eq(next) ;
if(next.size() && "1" == nextStatus){ //The subsequent dom node exists
next.trigger("click");
}
else{
items.eq(0).trigger("click");
}
} ;
tabProto._resetConsolePanel = function(){
this.getElem().find(".console-panel").empty();
} ;
tabProto.init = function(){
if(this._isEmptyResult()){
this._setContent("No module yet!");
}
var that = this ;
this.getElem().find(".title .adder")
.text("+" + this.getOpts()["buttonText"])
.on("click",function(){
that.getElem().find(".console-panel").slideToggle(function(){
that._renderConsolePanel("0");
}) ;
}) ;
$.each(this.getOpts()["result"],function(i,item){
if(that._isDisplayMax(i + 1)){
that._saveOrUpdateStatus(item,"1");
}
else{
that._saveOrUpdateStatus(item,"2");
}
that._render(item);
}) ;
if(!that._isDisplayMax(this.getOpts()["result"].length)){
this.getElem().find(".title .more-mod").fadeIn(function(){
$(this).find(".tag").on("click",function(){
var root = $(this).next();
root.empty() ;
$.each(that._getItemListByStatus("2"),function(i,data){
$("<div></div>").text(data["text"])
.on("click",function(){
if(that._getItemListByStatus("1").length < that.getOpts()["displayMax"]){
that.getElem().find(".title .items div").eq(data["index"]).fadeIn(function(){
that._saveOrUpdateStatus(data,"1");
}) ;
}
else{
alert("No modules can be added, it is currently the maximum number!") ;
}
})
.appendTo(root);
}) ;
root.toggle() ;
}) ;
});
}
this.getElem().find(".title .items div")
.eq(0)
.trigger("click"); // Assume that there must be one, otherwise the plug-in will not make much sense!
} ;
tabProto._render = function(data){
var that = this ;
var item = $("<div></div>").text(data["text"]).appendTo(this.getElem().find(".title .items")));
data["index"] = item.index();
item.on("click",function(){
that._setCurrent($(this).index()) ;
that._getContent(data["url"]).done(function(result){
that._setContent(result);
})
.fail(function(){
throw new Error("Net Error !");
});
})
.data("item",data);
if("2" == data["status"]){
item.hide() ;
}
if("1" == data["showClose"]){
$("<span class='del'>X</span>")
.on("click",function(){
if(win.confirm("Does this item be deleted?")){
that._deleteItem(item);
return false ; // stop bubbles
}
})
.appendTo(item);
}
} ;
ui.createTab = function(elem,opts){
var tab = new Tab(elem,opts) ;
tab.init();
return tab ;
} ;
})(jQuery);
(IV), final summary
(1) A reasonable analysis of functional requirements in an object-oriented way of thinking.
(2), organize our plug-in logic in a class way.
(3) Continuously reconstruct the above examples, how to reasonably reconstruct that? Don’t over-design, be at ease. The recommended method is to combine process design with object-oriented thinking design.