1. Opening analysis
What do we say in this article today? Hehehehe. We then reconstructed the shortcomings in the previous article and analyzed them step by step in an easy-to-understand way, so that everyone can improve step by step. Less nonsense, get to the point. Let's first review the previous one
The Js part code is as follows:
The code copy is as follows:
function ItemSelector(elem,opts){
this.elem = elem ;
this.opts = opts ;
} ;
var ISProto = ItemSelector.prototype;
ISProto.getElem = function(){
return this.elem ;
} ;
ISProto.getOpts = function(){
return this.opts ;
} ;
/* data manip*/
ISProto._setCurrent = function(current){
this.getOpts()["current"] = current ;
} ;
ISProto.getCurrentValue = function(current){
return this.getOpts()["current"] ;
} ;
/* data manip*/
ISProto.init = function(){
var that = this ;
this.getOpts()["current"] = null ; // Data cursor
this._setItemValue(this.getOpts()["currentText"]);
var itemsElem = that.getElem().find(".content .items");
this.getElem().find(".title div").on("click",function(){
itemsElem.toggle();
}) ;
this.getElem().find(".title span").on("click",function(){
itemsElem.toggle();
}) ;
$.each(this.getOpts()["items"],function(i,item){
item["id"] = (new Date().getTime()).toString();
that._render(item);
}) ;
} ;
ISProto._setItemValue = function(value){
this.getElem().find(".title div").text(value)
} ;
ISProto._render = function(item){
var that = this ;
var itemElem = $("<div></div>")
.text(item["text"])
.attr("id",item["id"]);
if("0" == item["disabled"]){
itemElem.on("click",function(){
var onChange = that.getOpts()["change"] ;
that.getElem().find(".content .items").hide();
that._setItemValue(item["text"]) ;
that._setCurrent(item);
onChange && onChange(item);
})
.mouseover(function(){
$(this).addClass("item-hover");
})
.mouseout(function(){
$(this).removeClass("item-hover");
}) ;
}
else{
itemElem.css("color","#ccc").on("click",function(){
that.getElem().find(".content .items").hide();
that._setItemValue(item["text"]) ;
}) ;
}
itemElem.appendTo(this.getElem().find(".content .items")));
} ;
The effect is shown in the figure below:
a)--------Non-operable state
b)------operable state
(II) Open up your ideas and reconstruct
It is not difficult for you to see from the code that it has been effectively organized in an object-oriented manner through the syntax characteristics in "Js", which is much better than the loose process-based organization method, but you will still find many shortcomings.
(1) There are too many repetitions in it
(2) The division of responsibilities is unclear
(3) The process is not complete
We have effectively refactored based on the above points. First, we need to sort out the requirements of this component, and the functional points are as follows:
(1) Initialize the configuration component
The code copy is as follows:
$(function(){
var itemSelector = new ItemSelector($("#item-selector"),{
currentText : "Please Choose Item",
items: [
{
text : "JavaScript",
value : "js",
disabled : "1"
} ,
{
text : "Css",
value : "css",
disabled : "0"
} ,
{
text : "Html",
value : "html",
disabled : "0"
}
],
}) ;
itemSelector.init();
}) ;
This code is very clear and does not require any modifications, but you can extend the functions based on the above configuration, such as adding the configuration item "mode" to support multiple options. For example: "checkbox check mode".
Next is to complete the initialization logic, as follows:
The code copy is as follows:
ISProto.init = function(){
var that = this ;
this.getOpts()["current"] = null ; // Data cursor
this._setItemValue(this.getOpts()["currentText"]);
var itemsElem = that.getElem().find(".content .items");
this.getElem().find(".title div").on("click",function(){
itemsElem.toggle();
}) ;
this.getElem().find(".title span").on("click",function(){
itemsElem.toggle();
}) ;
$.each(this.getOpts()["items"],function(i,item){
item["id"] = (new Date().getTime()).toString();
that._render(item);
}) ;
} ;
This code has many problems, unclear responsibilities, and the initialization logic contains detailed implementations of functional points.
Continue to see the rendering code:
The code copy is as follows:
ISProto._render = function(item){
var that = this ;
var itemElem = $("<div></div>")
.text(item["text"])
.attr("id",item["id"]);
if("0" == item["disabled"]){
itemElem.on("click",function(){
var onChange = that.getOpts()["change"] ;
that.getElem().find(".content .items").hide();
that._setItemValue(item["text"]) ;
that._setCurrent(item);
onChange && onChange(item);
})
.mouseover(function(){
$(this).addClass("item-hover");
})
.mouseout(function(){
$(this).removeClass("item-hover");
}) ;
}
else{
itemElem.css("color","#ccc").on("click",function(){
that.getElem().find(".content .items").hide();
that._setItemValue(item["text"]) ;
}) ;
}
itemElem.appendTo(this.getElem().find(".content .items")));
} ;
The problem is obvious. Repeatable operations have been found, and reasonable abstraction should be carried out, and the purpose of reuse has been achieved.
The entire construction process includes initialization, rendering (event binding), and related data operation methods and auxiliary methods of dom operations.
To sum up, after a simple sorting, we should establish the operational purpose of the function and the task assignment of the main line of the process, each of which will be responsible for its own responsibilities.
So the purpose of our reconstruction is very clear, right! It is to abstract functional points and divide responsibilities with friendly division, so how do we achieve that?
The first step is to establish process functions: (Method interface)
The code copy is as follows:
ISProto.init = function(){
// put you code here!
} ;
ISProto._render = function(){
// put you code here!
} ;
Part 2: Establish an abstract method interface:
The code copy is as follows:
ISProto._fnItemSelectorDelegateHandler = function(){
// put you code here!
} ;
ISProto._fnTriggerHandler = function(){
// put you code here!
} ;
ISProto._addOrRemoveClass = function(){
// put you code here!
} ;
The third step is to establish a data operation interface:
The code copy is as follows:
ISProto._setCurrent = function(){
// put you code here!
} ;
ISProto._getCurrent = function(){
// put you code here!
} ;
There are also some references to the complete source code below, which is just the idea mentioned here.
(III), the complete code is for learning, this code has been tested
The code copy is as follows:
function ItemSelector(elem,opts){
this.elem = elem ;
this.opts = opts ;
this.current = -1 ; // Data cursor
} ;
var ISProto = ItemSelector.prototype;
/* getter api*/
ISProto.getElem = function(){
return this.elem ;
} ;
ISProto.getOpts = function(){
return this.opts ;
} ;
ISProto._getCurrent = function(){
return this.current ;
} ;
/* getter api*/
/* data manip*/
ISProto._setCurrent = function(current){
this.current = current ;
} ;
ISProto._setItemText = function(text){
this.getElem().find(".title div").text(text) ;
} ;
/* data manip*/
/* update on 2015 1/31 23:38 */
ISProto._fnTriggerHandler = function(index,text,value){
if(this._isDisabled(value)){
index = -1;
text = this.getOpts()["currentText"] ;
}
this._setItemText(text) ;
this._setCurrent(index);
this.getElem().find(".content .items").hide();
} ;
ISProto._addOrRemoveClass = function(elem,className,addIs){
if(addIs){
elem.addClass(className);
}
else{
elem.removeClass(className);
}
} ;
ISProto._fnItemSelectorDelegateHandler = function(){
var that = this ;
this.getElem().on("click","[data-toggle]",function(){
that.getElem().find(".content .items").toggle();
}) ;
} ;
ISProto._isDisabled = function(value){
return ("1" == value) ? true : false ;
} ;
/* update on 2015 1/31 23:38 */
ISProto.init = function(){
var that = this ;
this._fnItemSelectorDelegateHandler();
$.each(this.getOpts()["items"],function(i,item){
item["index"] = i ;
that._render(item);
}) ;
this._fnTriggerHandler(this._getCurrent(),this.getOpts()["currentText"],"1");
} ;
ISProto._render = function(item){
var that = this ;
var itemElem = $("<div></div>").text(item["text"]).attr("id",item["index"]) ;
var activeClass = ("0" == item["disabled"]) ? "item-hover" : "item-disabled-hover" ;
itemElem.on("click",function(){
that._fnTriggerHandler(item["index"],item["text"],item["disabled"]) ;
})
.mouseover(function(){
that._addOrRemoveClass($(this),activeClass,true);
})
.mouseout(function(){
that._addOrRemoveClass($(this),activeClass,false);
}) ;
itemElem.appendTo(this.getElem().find(".content .items")));
} ;
(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.
(4) The following article will expand related functions, such as the property "mode". When it is "1", it supports checkbox multi-select mode, but now it is just the default drop-down mode.
Looking at my article, is it much better than the previous code? Friends should think about and do more projects by themselves and try to make their own code more reasonable.