仿照vue实现简易的MVVM框架(二)

实现文本插值与s-for循环模版。

对于文本插值的实现,我采用正则去匹配还原这个dom节点,以插值{{text}}形式为分界,将这个dom节点的文本分割成多个字符串,存储在this.muscha中,再者,将普通文本字符串以数组形式存储在string属性中,将插值存放在text属性值。当然,拼接的时候要明白先从string还是先从text开始拼接,我采用的方法是设置标志值,tag属性为0时,从text开始,为1时从string开始,存储完成后,解析拼接时只会出现这么几种情况:字串文本在前插值(1个或者多个)在后、只出现插值(1个或者多个)、前面后面插值中间为字串,前面后面为字串中间为插值。这些都可以分别处理,this.muscha函数如下:

this.muscha = function(value) {
	var temp = {
		string: [],
		text: [],
		tag: 0
	};

	var reg = /{{((?:.|\n)+?)}}/g;

	if (!reg.test(value)) {
	    	return null;
	}

	var match;
	
	var lastIndex = reg.lastIndex = 0;
	var index;

	while(match = reg.exec(value)) {
		
		index = match.index;

		if (index > lastIndex) {
			temp.tag = 1;
			temp.string.push(value.slice(lastIndex, index));
		}
	
			temp.text.push(match[1]);
		lastIndex = index + match[0].length;
	}
	
	if (lastIndex < value.length) {
		temp.string.push(value.slice(lastIndex));
	}
	return temp;
}

拼接字串的方式如下:

this.strSplit = function(item) {
	var str = '';

	if (!item.muscha.tag) {
		var len = item.muscha.string.length;
		switch(len) {
			case 0:
				for (var i = 0; i < item.muscha.text.length; i++) {
					str += data[item.muscha.text[i]];
				}
				break;
			case 1:
				str = data[item.muscha.text[0]] + item.muscha.string[0];
				break;
			default:
				for (var i = 0; i < len; i++) {
					str = data[item.muscha.text[i]] + item.muscha.string[i];
				}
				str += data[item.muscha.text[i]];
		}
	} else {
		var len = item.muscha.text.length;
		switch(len) {
			case 1:
				//console.log(data[item.muscha.text[0]]);
				str = item.muscha.string[0] + data[item.muscha.text[0]];
				break;
			default:
				for (var j = 0; j < len; j++) {
					str = item.muscha.string[j] + data[item.muscha.text[j]];
				}
				str += item.muscha.string[j];
		}
	}
	return str;	
}

进一步,实现循环模版。带有非根元素(代码中的最外层节点)的父元素的循环节点处理起来相对容易,只需要将父元素先清理干净(parentNode.innerHTML = ''),循环数据后插入相应的dom节点即可。只是花了不少的时间在父元素为根节点的循环模版上,如果采用相同的方法,页面结构必然会被破坏,当我们重写这个节点后对节点的引用也就失效了,于是上一种的情况采用父节点来辅助,于是在这就联想到,我是否可以借助兄弟元素来实现呢?当然,各种各样的问题也在这里出现,加深了对dom节点操作的知识(唉,太渣!),倒腾了不久,终于写出了代码!(但是就是丑~)。代码如下:

case 's-for':
	var items = data[item.list];
	var fragment = document.createDocumentFragment();
	if (content) {
		for (var i = 0, len = items.length; i < len; i++) {
			var dom = document.createElement(item.node
				.nodeName.toLowerCase());
			dom.innerHTML = items[i][content];
			if (item.event) {
				for (var j = 0; j < item.event.length; j++) {
					dom.addEventListener(item.event[j].type, that.eventProcess(methods[item.event[j].event]), false);
				}
			}
			fragment.appendChild(dom);
		}
		if (item.parentNode) {
			var dom = document.createElement(item.node
				.nodeName.toLowerCase());
			item.parentNode.innerHTML = '';
			item.parentNode.appendChild(fragment);
		} else{
			if (item.nextElementSibling === undefined) {
				item.nextElementSibling = item.node.nextElementSibling;
				if (item.node.nextElementSibling === null) {
					item.node.parentNode.insertBefore(fragment, item.node);
					//console.log(item.node.parentNode.lastElementChild);
					item.node.parentNode.removeChild(item.node.parentNode.lastElementChild);
				} else { 
					item.node.nextElementSibling.parentNode.insertBefore(fragment, item.node);
					item.node.nextElementSibling.parentNode.removeChild(item.node);
				}
			}
		}
	}
	break;

};

好了,暂时就实现这么点,插值的供能是很强大的,这里实现的功能也只是一部分~

原文地址:https://www.cnblogs.com/susantong/p/6958788.html