代码要写成别人看不懂的样子(十九)

本篇文章参考书籍《JavaScript设计模式》–张容铭

文章目录

前言

  大家有没有遇到过操作大量节点的情况,比如我们在页面上想要创建一个展示区域,这块区域,需要跟不同的选项来展示不同结构的内容,那我们就需要根据选项来操作不同的节点。首先创建节点,然后创建节点内容,将节点内容插入到创建的节点中,最后将节点插入到父节点中。

  这一套操作下俩,一个节点就需要 4 步,如果节点比较多,那这性能消耗就有点遭不住了。

  为了解决这一个问题,我们可以使用简单模板方法。如果各位接触过模板字符串,那学起来易如反掌。

简单模板模式

  通过格式化字符串拼凑出视图避免创建视图时大量节点操作,优化内存开销

  举个例子,我们规定一个展示区容器,用来展示不同的信息。

//命名空间 单体对象
var A = A || [];
//主体展示容器区
A.root = document.getElementById('container');
//创建视图方法集合
A.strategy = {
    
    
	'listPart': function() {
    
    },
	'codePart': function() {
    
    },
	'onlyTitle': function() {
    
    },
	'guide': function() {
    
    }
	//.......
}
//创建视图入口
A.init = function(data) {
    
    
	//根据传输的试图类型创建视图
	this.strategy[data.type](data);
}

  接下来是实现 strategy 中的每一种创建算法。(下面代码粗略扫一眼就行)

//文字列表展示
'listPart': function(data) {
    
    
	var s = document.createElement('div'),          //模块容器
		h = document.createElement('h2'),           //标题容器
		p = document.createElement('p'),            //描述容器
		ht = document.createTextNode(data.data.h2), //标题内容
		pt = document.createTextNode(data.data.p),  //描述内容
		ul = document.createElement('ul'),          //列表容器
		ldata = data.data.li,                       //列表数据
		//li 列表项容器, strong 列表项标题,span 列表项解释,t 列表项标题内容, c 列表项解释内容
		li, strong, span, t, c;
	//有 id 设置模块 id
	data.id && (s.id = data.id);
	s.className = 'part'; //设置模块类名
	h.appendChild(ht);    //将标题内容放到标题容器
	p.appendChild(pt);    //将描述内容放到描述容器
	s.appendChild(h);     //将标题容器插入模块容器
	s.appendChild(p);     //将描述容器插入模板容器
	//遍历列表数据
	for(var i = 0, len = ldata.length; i < len; i++) {
    
    
		li = document.createElement('li');            //创建列表项容器
		strong = document.createElement('strong');    //创建列表项标题容器
		span = document.createElement('span');        //创建列表项解释容器
		t = document.createTextNode(ldata[i].strong); //创建列表项标题内容
		c = document.createTextNode(ldata[i].span);   //创建列表项解释内容
		strong.appendChild(t);       //向列表项标题容器中插入标题内容
		span.appendChild(c);         //向列表项解释容器中插入解释类容
		li.appendChild(strong);      //向列表项中插入列表项标题
		li.appendChild(span);        //向列表项中插入列表项解释
		ul.appendChild(li);          //向列表项中插入列表项
	}
	s.appendChild(ul);     //向模块中插入列表
	A.root.appendChild(s); //展现模块
}

  大家有没有觉得上面的代码,阅读起来总是看串行,虽然整整齐齐,但是看着就头大。这就是我们一开始说的操作各种节点。写起来费劲,读起来费劲,浏览器运行起来也费劲。

  为了解决上面的问题,我们可以试着创建一个模板,用数据去格式化字符串来渲染视图并插入到容器里,这样实现的方案性能上会提高很多,首先需要一个渲染器,比如想用数据对象 ‘{demo: ‘this is a demo’}’ 去格式化 ‘<a>{#demo#}</a>+’ 字符串模板,得到 ‘<a>this is a demo</a>’ 渲染后的模板,便可插入到页面中,不过先要一个渲染模板引擎的方法 formateString 方法,将字符串模板中的 {#demo#} 替换成数据对象中的 demo 属性值。

//渲染模板方法
A.formateString = function(str, data) {
    
    
	return str.replace(/\{#(\w+)#\}/g, function(match, key) {
    
    return typeof data[key] === undefined ? '' : data[key]});
}

  有了这个方法,我们就可以通过简单模板来渲染出我们需求的视图了。

扫描二维码关注公众号,回复: 13049106 查看本文章
//文字列表展示
'listPart': function(data) {
    
    
	var s = document.creatElement('div'),   //容器模块
		ul = '',                            //列表字符串
		ldata = data.data.li,               //列表数据
		//模块模板
		tpl = [
			'<h2>{#h2#}</h2>',
			'<p>{#p#}</p>',
			'<ul>{#ul#}</ul>'
		].join(''),
		//列表项模板
		liTpl = [
			'<li>',
				'<strong>{#strong#}</strong>',
				'<span>{#span#}</span>',
			'</li>'
		].join('');
	//有 id 设置模块 id
	data.id && (s.id = data.id);
	//遍历列表数据
	for(var i = 0, len = ldata.length; i < len; i++) {
    
    
		//如果有列表项数据
		if(ldata[i].em || ldata[i].span) {
    
    
			//列表字符串追加一项列表项
			ul += A.formateString(liTpl, ldata[i]);
		}
	}
	//装饰列表数据
	data.data.ul = ul;
	//渲染模块并插入模块中
	s.innerHTML = A.formateString(tpl, data.data);
	//渲染模块
	A.root.appendChild(s);
}

  这样我们的模板就完成了,一行的渲染工作,便完成了上面那么多节点操作。不过这个版本还能优化, tpl 这个模板内部相似的地方还可以提取,这样我们创建一个模板生成器,我们只要传入不同的标签名就可以了。

//模板生成器 name: 标识
A.view = function(name) {
    
    
	//模板库
	var v = {
    
    
		//代码模板
		code: '<pre><code>{#code#}</code></pre>',
		//图片模板
		img: '<img src="{#src#}" alt="{#alt#}" title="{#title#}" />',
		//带有id和类的模块模板
		part: '<div id="{#id#}" class="{#class#}">{#part#}</div>',
		//组合模板
		theme: [
			'<div>',
				'<h1>{#title#}</h1>',
				'{#content#}',
			'</div>'
		].join('')
	}
	//如果参数是一个数组,则返回多行模板
	if(Object.prototype.toString.call(name) === '[object Array]') {
    
    
		//模板缓存器
		var tpl = '';
		for(var i = 0, len = name.length; i < len; i++) {
    
    
			//模板缓存器追加模板
			tpl += arguments.callee(name[i]);
		}
		//返回最终模板
		return tpl;
	} else {
    
    
		//如果模板库中有该模板则返回该模板,否则返回建议模板
		return v[name] ? v[name] : ('<' + name + '>{#' + name +'#}</' + name + '>');
	}
}

  有了这个小型模板生成器,我们先获取一个模板就简单多了,比如我们想获取一个 ‘<span>{#span#}</span>’ ,就可以通过 A.view(‘span’) 方式来获取。有了它,完成我们的需求就容易多了。

//文字列表展示
'listPart': function(data) {
    
    
	//......
		//模块模板
		tpl = A.view(['h2', 'p', 'ul']),
		//列表项模板
		liTpl = A.formateString(A.view('li'), {
    
    li: A.view(['strong', 'span'])}),
	//......
}

  模板字符串的应用其实非常广泛,大家一定要好好熟悉这部分内容。




猜你喜欢

转载自blog.csdn.net/EcbJS/article/details/111316357