所謂組合模式,就是把一堆結構分解出來,組成在一起,現實中很多這樣的例子,如: 1、肯德基套餐就是一種組合模式, 比如雞腿堡套餐,一般是是由一個雞腿堡,一包薯條,一杯可樂等組成的 2、組裝的台式機同理,由主板,電源,記憶體條,顯卡, 機箱,顯示器,外設等組成的 把一個成型的產品組成部件,分成一個個獨立的 ...
所謂組合模式,就是把一堆結構分解出來,組成在一起,現實中很多這樣的例子,如:
1、肯德基套餐就是一種組合模式, 比如雞腿堡套餐,一般是是由一個雞腿堡,一包薯條,一杯可樂等組成的
2、組裝的台式機同理,由主板,電源,記憶體條,顯卡, 機箱,顯示器,外設等組成的
把一個成型的產品組成部件,分成一個個獨立的部件,這種方式可以做出很多靈活的產品,這就是組合模式的優勢
比如:家用台式機電腦,要求配置比較低, 這個時候只需要主板+電源+記憶體條+機箱+顯示器+外設就可以了,不需要配置獨立顯卡
雞腿堡+雞翅+紫薯+可樂可以配置出另外一種套餐。
而在我們的前端領域,經常要接觸的就是排版,通過不同的html結構+css樣式組合成不用絢麗多彩的網頁,我們也可以通過組合模式來完成的,
有人可能要問,為什麼要用js來生成,直接寫html和css不是很省事嗎?是的,但是用組合模式做成不同的套餐(模塊),是不是可以非常快的生成出不同的模板呢? 大大提高網頁編寫的速度?
本文我們來實戰一個最基本的列表新聞模塊,看看怎麼使用組合模式?先看下要做出來的效果:
這個是一個無序列表加一個a標簽,非常簡單的套餐(模塊)
1、首先,我們定義父類,2個屬性,3個方法
1 /***************父類開始***********************/ 2 var Layout = function () { 3 this.children = []; 4 this.element = null; 5 } 6 Layout.prototype = { 7 init: function () { 8 throw new Error('該方法需要重寫'); 9 }, 10 add: function () { 11 throw new Error('該方法需要重寫'); 12 }, 13 getElement: function () { 14 throw new Error('該方法需要重寫'); 15 } 16 } 17 /***************父類結束***********************/
this.element用來存儲當前的元素,this.children用來存儲當前元素下麵的子元素
init方法:用來初始化元素的標簽,屬性,樣式
add方法:把子節點添加在父節點下麵
getElement: 獲取當前的節點
2、這裡我們需要用到寄生組合繼承
1 function object(o) { 2 var G = function () { 3 }; 4 G.prototype = o; 5 return new G(); 6 } 7 function inheritPrototype(subObj, superObj) { 8 var proObj = object(superObj.prototype); //複製父類superObj的原型對象 9 proObj.constructor = subObj; //constructor指向子類構造函數 10 subObj.prototype = proObj; //再把這個對象給子類的原型對象 11 }
3,由於這個新聞模塊最外層是ul,所以我們要封裝一個生成ul元素的容器類
1 /***************列表容器類開始***********************/ 2 var UlContainer = function (id, parent) { 3 Layout.call(this); 4 this.id = id; 5 this.parent = parent; 6 this.init(); 7 } 8 inheritPrototype(UlContainer, Layout); 9 UlContainer.prototype.init = function () { 10 this.element = document.createElement("ul"); 11 this.element.id = this.id; 12 this.element.className = 'news-list'; 13 } 14 UlContainer.prototype.add = function (child) { 15 this.children.push(child); 16 this.element.appendChild(child.getElement()); 17 return this; 18 } 19 UlContainer.prototype.getElement = function () { 20 return this.element; 21 } 22 UlContainer.prototype.show = function () { 23 this.parent.appendChild(this.element); 24 } 25 /***************列表容器類結束***********************/
採用寄生組合繼承,把父類的方法重寫,父類的屬性通過子類的借用構造函數複製到子類實例上,新增了一個show方法,這個方法的目的就是,把最終的模板顯示出來
4、生成li元素
1 /***************列表項li開始***********************/ 2 var LiTag = function (cName) { 3 Layout.call(this); 4 this.className = cName || ''; 5 this.init(); 6 } 7 inheritPrototype(LiTag, Layout); 8 LiTag.prototype.init = function () { 9 this.element = document.createElement("li"); 10 this.element.className = this.className; 11 } 12 LiTag.prototype.add = function (child) { 13 this.children.push(child); 14 this.element.appendChild(child.getElement()); 15 return this; 16 } 17 LiTag.prototype.getElement = function () { 18 return this.element; 19 } 20 /***************列表項li結束***********************/
5、生成圖片與a標簽組合的方式
1 /***************圖片新聞開始*******************/ 2 var ImageMsg = function (url, href, cName) { 3 Layout.call(this); 4 this.url = url || ''; 5 this.href = href || '#'; 6 this.className = cName || 'default'; 7 this.init(); 8 } 9 inheritPrototype(ImageMsg, Layout); 10 ImageMsg.prototype.init = function () { 11 this.element = document.createElement("a"); 12 var oImg = new Image(); 13 oImg.src = this.url; 14 this.element.appendChild(oImg); 15 this.element.className = 'img-Layout ' + this.className; 16 this.element.href = this.href; 17 } 18 ImageMsg.prototype.add = function () { 19 } 20 ImageMsg.prototype.getElement = function () { 21 return this.element; 22 } 23 /***************圖片新聞結束*******************/
6,生成單純的a標簽和內容這種組合
1 /***************簡單新聞開始*******************/ 2 var ATag = function (text, href, cName) { 3 Layout.call(this); 4 this.href = href || '#'; 5 this.className = cName || 'default'; 6 this.text = text || ''; 7 this.init(); 8 } 9 inheritPrototype(ATag, Layout); 10 ATag.prototype.init = function () { 11 this.element = document.createElement("a"); 12 this.element.href = this.href; 13 this.element.innerHTML = this.text; 14 } 15 ATag.prototype.add = function () { 16 } 17 ATag.prototype.getElement = function () { 18 return this.element; 19 } 20 /***************簡單新聞結束*******************/
7,生成帶分類的新聞標題
1 /***************分類新聞開始*******************/ 2 var TypeMsg = function (text, href, type, cName, pos) { 3 Layout.call(this); 4 this.text = text || ''; 5 this.href = href || '#'; 6 this.type = type || ''; 7 this.pos = pos || 'left'; 8 this.className = cName || ''; 9 this.init(); 10 } 11 inheritPrototype(TypeMsg, Layout); 12 TypeMsg.prototype.init = function () { 13 this.element = document.createElement("a"); 14 if (this.pos === 'left') { 15 this.element.innerHTML = '[' + this.type + '] ' + this.text; 16 } else { 17 this.element.innerHTML = this.text + ' [' + this.type + ']'; 18 } 19 this.element.href = this.href; 20 this.element.className = this.className; 21 } 22 TypeMsg.prototype.add = function () { 23 } 24 TypeMsg.prototype.getElement = function () { 25 return this.element; 26 } 27 /***************分類新聞結束*******************/
8、大功告成,開始調用生成最後的模塊
1 window.onload = function () { 2 var oUlContainer = new UlContainer('Layout', document.body); 3 oUlContainer.add( 4 new LiTag('default').add( 5 new TypeMsg('es6系列教程 - 新的類語法實戰選項卡', 'http://www.cnblogs.com/ghostwu/p/7465066.html', 'js高手之路-ghostwu', 'default', 'left') 6 ) 7 ).add( 8 new LiTag('default').add( 9 new TypeMsg('設計模式系列課程-單例模式實現模態框', 'http://www.cnblogs.com/ghostwu/p/7460301.html', 'js高手之路-ghostwu', 'default', 'left') 10 ) 11 ).add( 12 new LiTag('default').add( 13 new TypeMsg('HTML標簽解釋成DOM節點', 'http://www.cnblogs.com/ghostwu/p/7455184.html', 'js高手之路-ghostwu', 'default', 'left') 14 ) 15 ).add( 16 new LiTag('default').add( 17 new TypeMsg('HTML標簽解釋成DOM節點', 'http://www.cnblogs.com/ghostwu/p/7455184.html', 'js高手之路-ghostwu', 'default', 'left') 18 ) 19 ).add( 20 new LiTag('default').add( 21 new ATag('構造函數的基本特性與優缺點', 'http://www.cnblogs.com/ghostwu/p/7434609.html', 'js高手之路-ghostwu' ) 22 ) 23 ).show(); 24 }