Write in front
We must face the fact that many programmers do not plan their JS code. We often write code, run it, and submit it quickly. But when we continue to develop and encounter variables and functions and have to look back again to see what they represent, the trouble starts here. Similarly, we will encounter similar errors when we obtain scripts from other programmers. Therefore, when we say "this is done, I can go on" it is best to do the following 5 things with the script.
Problem Description
Now we want to add hyperlink A inside each DIV with the class attribute of collapsible to show and hide the DIV.
The following is the implementation code written using module functions:
var collapser = (function(){
var secs = document.getElementsByTagName('div');
for(var i=0;iif(secs[i].className.indexOf('collapsible')!= =-1){
var p = document.createElement('p');
var a = document.createElement('a');
a.setAttribute('href','#') ;
a.onclick = function(){
var sec = this.parentNode.nextSibling;
if(sec.style.display === 'none'){
sec.style.display = 'block';
this.firstChild.nodeValue = 'collapse'
} else {
sec.style.display = 'none';
this.firstChild.nodeValue = 'expand'
}
return false;
};
a.appendChild(document.createTextNode('expand'));
p.appendChild(a);
secs[i].style. display = 'none';
secs[i].parentNode.insertBefore(p,secs[i]);
}
}
})();
The above code has accurately achieved the results we want. But we can further refactor the above code.
Step 1: Separate style (CSS) and behavior (JavaScript)
We can add a CSS class selector to eliminate the style set in JS. This phenomenon is often encountered among novices.
var collapser = (function(){
var secs = document.getElementsByTagName('div');
for(var i=0;iif(secs[i].className.indexOf('collapsible')!= =-1){
secs[i].className = ' ' 'collapsed';
var p = document.createElement('p');
var a = document.createElement('a') ;
a.setAttribute('href','#');
a.onclick = function(){
var sec = this.parentNode.nextSibling;
if(sec.className.indexOf ('collapsed')!==-1){
sec.className = sec.className.replace('collapsed','');
this.firstChild.nodeValue = 'collapse'
} else {
sec.className = ' ' 'collapsed';
this.firstChild.nodeValue = 'expand'
}
return false;
}
a.appendChild(document.createTextNode ('expand'));
p.appendChild(a);
secs[i].parentNode.insertBefore(p,secs[i]);
}
}
}) ();
Step 2: Further performance optimization of the code
We can do two things here: 1. The length attribute of secs in the loop statement can be saved in a variable. 2. Create reusable functions for event handlers. The advantage is to reduce the number of event handlers and reduce memory usage.
var collapser = (function(){
var secs = document.getElementsByTagName('div');
for(var i=0,j=secs.length;iif(secs[i].className.indexOf('collapsible ')!==-1){
secs[i].className = ' ' 'collapsed';
var p = document.createElement('p');
var a = document.createElement( 'a');
a.setAttribute('href','#');
a.onclick = toggle;
a.appendChild(document.createTextNode('expand'));
p.appendChild(a);
secs[i].parentNode.insertBefore(p,secs[i]);
}
}
function toggle(){
var sec = this .parentNode.nextSibling;
if(sec.className.indexOf('collapsed')!==-1){
sec.className = sec.className.replace('collapsed','');
this.firstChild.nodeValue = 'collapse'
} else {
sec.className = ' ' 'collapsed';
this.firstChild.nodeValue = 'expand'
}
return false ;
}
})();
Step 3: Add configuration object
Use configuration objects to store hard-coding in the code, such as used text labels or custom attribute names. Conducive to subsequent maintenance.
var collapser = (function(){
var config = {
indicatorClass : 'collapsible',
collapsedClass : 'collapsed',
collapseLabel : 'collapse',
expandLabel : 'expand'
}
var secs = document.getElementsByTagName('div');
for(var i=0,j=secs.length;iif(secs[i].className.indexOf(config.indicatorClass)!==-1){
secs[i].className = ' ' config.collapsedClass;
var p = document.createElement('p');
var a = document.createElement('a');
a.setAttribute('href','#');
a.onclick = toggle;
a.appendChild(document.createTextNode(config.expandLabel));
p.appendChild(a);
secs[i].parentNode.insertBefore(p,secs[i]);
}
}
function toggle(){
var sec = this.parentNode.nextSibling;
if(sec.className.indexOf(config.collapsedClass)!==-1){
sec.className = sec.className.replace(' ' config.collapsedClass,'');
this.firstChild.nodeValue = config.collapseLabel
} else {
sec.className = ' ' config.collapsedClass;
this.firstChild.nodeValue = config.expandLabel
}
return false;
}
})();
第四步:为变量和函数起有含义的名字
var collapser = (function(){
var config = {
indicatorClass : 'collapsible',
collapsedClass : 'collapsed',
collapseLabel : 'collapse',
expandLabel : 'expand'
}
var sections = document.getElementsByTagName('div');
for(var i=0,j=sections.length;iif(sections[i].className.indexOf(config.indicatorClass) !== -1){
sections[i].className = ' ' config.collapsedClass;
var paragraph = document.createElement('p');
var trigger = document.createElement('a');
trigger.setAttribute('href','#');
trigger.onclick = toggleSection;
trigger.appendChild(document.createTextNode(config.expandLabel));
paragraph.appendChild(trigger);
sections[i].parentNode.insertBefore(paragraph,sections[i]);
}
}
function toggleSection(){
var section = this.parentNode.nextSibling;
if(section.className.indexOf(config.collapsedClass) !== -1){
section.className = section.className.replace(' ' config.collapsedClass,'');
this.firstChild.nodeValue = config.collapseLabel
} else {
section.className = ' ' config.collapsedClass;
this.firstChild.nodeValue = config.expandLabel
}
return false;
}
})();
第五步:添加必要的注释
// Collapse and expand section of the page with a certain class
// written by Christian Heilmann, 07/01/08
var collapser = (function(){
// Configuration, change CSS class names and labels here
var config = {
indicatorClass : 'collapsible',
collapsedClass : 'collapsed',
collapseLabel : 'collapse',
expandLabel : 'expand'
}
var sections = document.getElementsByTagName('div');
for(var i=0,j=sections.length;iif(sections[i].className.indexOf(config.indicatorClass) !== -1){
sections[i].className = ' ' config.collapsedClass;
var paragraph = document.createElement('p');
var trigger = document.createElement('a');
trigger.setAttribute('href','#');
trigger.onclick = toggleSection;
trigger.appendChild(document.createTextNode(config.expandLabel));
paragraph.appendChild(trigger);
sections[i].parentNode.insertBefore(paragraph,sections[i]);
}
}
function toggleSection(){
var section = this.parentNode.nextSibling;
if(section.className.indexOf(config.collapsedClass) !== -1){
section.className = section.className.replace(' ' config.collapsedClass,'');
this.firstChild.nodeValue = config.collapseLabel
} else {
section.className = ' ' config.collapsedClass;
this.firstChild.nodeValue = config.expandLabel
}
return false;
}
})();