[js高手之路]设计模式系列课程-组合模式+寄生组合继承实战新闻列表

所谓组合模式,就是把一堆结构分解出来,组成在一起,现实中很多这样的例子,如:

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 }
时间: 2024-10-13 22:51:23

[js高手之路]设计模式系列课程-组合模式+寄生组合继承实战新闻列表的相关文章

[js高手之路]设计模式系列课程-委托模式实战微博发布功能

在实际开发中,经常需要为Dom元素绑定事件,如果页面上有4个li元素,点击对应的li,弹出对应的li内容,怎么做呢?是不是很简单? 大多数人的做法都是:获取元素,绑定事件 1 <ul> 2 <li>跟着ghostwu学习javascript设计模式的应用1</li> 3 <li>跟着ghostwu学习javascript设计模式的应用2</li> 4 <li>跟着ghostwu学习javascript设计模式的应用3</li&g

[js高手之路]设计模式系列课程-发布者,订阅者重构购物车

发布者订阅者模式,是一种很常见的模式,比如: 一.买卖房子 生活中的买房,卖房,中介就构成了一个发布订阅者模式,买房的人,一般需要的是房源,价格,使用面积等信息,他充当了订阅者的角色 中介拿到卖主的房源信息,根据手头上掌握的客户联系信息(买房的人的手机号),通知买房的人,他充当了发布者的角色 卖主想卖掉自己的房子,就需要告诉中介,把信息交给中介发布 二,网站订阅信息的用户 订阅者角色:需要订阅某类信息的网民,如某个网站的javascript类型文章 发布者角色:邮箱服务器,根据网站收集到的用户订

[js高手之路]设计模式系列课程-单例模式实现模态框

什么是单例呢? 单,就是一个的意思.例:就是实例化出来的对象,那合在一起就是保证一个构造函数只能new出一个实例,为什么要学习单例模式呢?或者说单例模式有哪些常见的应用场景.它的使用还是很广泛,比如:弹出一个模态框,一般来说在网站中弹出的模态框,不停的一直点击,一般只能创建一个.还有后台的数据库连接,一般都是保证一个连接等等.今天的主题就是单例在模态框中的应用,我们先要搞清楚,怎么弄个单例出来. 我们先看下普通的构造函数加原型方式.下面这种是常见的方式 1 function Singleton

[js高手之路] es6系列教程 - 迭代器与生成器详解

什么是迭代器? 迭代器是一种特殊对象,这种对象具有以下特点: 1,所有对象都有一个next方法 2,每次调用next方法,都会返回一个对象,该对象包含两个属性,一个是value, 表示下一个将要返回的值.另一个是done,他是一个布尔值,用来表示该迭代器是否还有数据可以返回. 3,迭代器还会保存一个内部指针指向当前集合中的值 设计模式中有个迭代模式,跟迭代器是差不多的,我之前有写过2篇文章关于迭代模式: [js高手之路] 设计模式系列课程 - 迭代器(1) [js高手之路] 设计模式系列课程 -

[js高手之路] es6系列教程 - 迭代器,生成器,for...of,entries,values,keys等详解

接着上文[js高手之路] es6系列教程 - 迭代器与生成器详解继续. 在es6中引入了一个新的循环结构for ....of, 主要是用来循环可迭代的对象,那么什么是可迭代的对象呢? 可迭代的对象一般都有Symbol.iterator属性,你可以在控制台中用console.dir打印数组,Map,Set,在他们的原型对象(prototype)上面就能找到.这个属性与迭代器密切相关,通过该函数可以返回一个迭代器,下文,我会举一个例子.一般来说所有的集合对象(数组,Set,Map 以及字符串)都是可

[js高手之路] es6系列教程 - promise常见用法详解(resolve,reject,catch,then,all,race)

关于promise我在之前的文章已经应用过好几次,如[js高手之路]Node.js+jade+express+mongodb+mongoose+promise实现todolist,本文就来讲解下promise的常见用法. 为什么会有promise,他的作用是什么? promise主要是为了解决js中多个异步回调难以维护和控制的问题. 什么是promise? 从图中,我们可以看出,Promise是一个函数,这个函数上有在项目中常用的静态方法:all, race, reject,resolve等,原

[js高手之路] es6系列教程 - new.target属性与es5改造es6的类语法

es5的构造函数前面如果不用new调用,this指向window,对象的属性就得不到值了,所以以前我们都要在构造函数中通过判断this是否使用了new关键字来确保普通的函数调用方式都能让对象复制到属性 1 function Person( uName ){ 2 if ( this instanceof Person ) { 3 this.userName = uName; 4 }else { 5 return new Person( uName ); 6 } 7 } 8 Person.proto

[js高手之路] es6系列教程 - var, let, const详解

function show( flag ){             console.log( a );             if( flag ){                 var a = 'ghostwu';                 return a;             } else {                 console.log( a );                 return null;             }         } 我们从e

[js高手之路] es6系列教程 - Map详解以及常用api

ECMAScript 6中的Map类型是一种存储着许多键值对的有序列表.键值对支持所有的数据类型. 键 0 和 ‘0’会被当做两个不同的键,不会发生强制类型转换. 如何使用Map? let map = new Map(); 常用方法: set( 键,值 ):  添加新的键值对元素 get( 键 ): 获取键对应的值,如果这个值不存在,返回undefined 1 let map = new Map(); 2 map.set( '0', 'ghostwu' ); 3 map.set( 0, 'gho