Skip to content

Instantly share code, notes, and snippets.

@legend80s
Created June 17, 2018 13:04
Show Gist options
  • Save legend80s/e3a08a7d3d85fbe49754c5fa56139ff1 to your computer and use it in GitHub Desktop.
Save legend80s/e3a08a7d3d85fbe49754c5fa56139ff1 to your computer and use it in GitHub Desktop.
compile string to DOM
/**
* 将字符串编译为 DOM 结构
* @deprecated 请注意,不要用该函数,因为 compile('<div></div><p></p>') 会编译成嵌套结构:<p><div></div></p>
* @public
* @param {String} domString
* @return {HTMLElement}
* @throws {Error} 如果输入不是合法的 DOM 字符串
*
* @example
* compile('<div><p><a><em></em></a></p></div>')
* // =>
* <div>
* <p>
* <a>
* <em></em>
* </a>
* </p>
* </div>
*
* @example
* compile('<div></p>')
* // => Uncaught Error: DOM string invalid
*/
function compile(domString) {
var validated = validate(domString);
if (!validated) {
throw new Error('DOM string invalid');
}
const compiled = assemble(validated);
return compiled;
}
/**
* 检测是否是合法的 DOM 字符串
* @private
*
* @param {String} domString
* @return {String[]|false} 若合法则返回标签名数组,否则返回 false
*
* @example
* validate('<div></div>')
* // => ['div']
*
* @example
* validate('<div></p>')
* // => false
*
* @example
* validate('<div><p><a><em></em></a></p></div>')
* // => ['div', 'p', 'a', 'em']
*/
function validate(domString) {
const beginTagPattern = /^<(\w+)>/;
const closeTagPattern = /^<\/(\w+)>/;
const stack = [];
const tags = [];
let testString = domString;
let delta = 1;
while (testString.length > 0) {
const beginTagMatches = testString.match(beginTagPattern);
const closeTagMatches = testString.match(closeTagPattern);
let matches;
if (beginTagMatches) {
matches = beginTagMatches;
stack.push(matches[1]);
// console.log('after push stack:', stack);
} else if (closeTagMatches) {
matches = closeTagMatches;
if (stack[stack.length - 1] === matches[1]) {
const tag = stack.pop();
tags.push(tag);
// console.log('after pop stack:', stack);
}
} else {
break;
}
delta = matches[0].length + matches.index;
testString = testString.slice(delta);
}
// console.log('final stack:', stack);
return stack.length === 0 ? tags.reverse() : false;
}
/**
* 将标签组装为嵌套的 DOM 结构
* @private
* @param {String[]} tags
* @return {HTMLElement}
*
* @example
* assemble(['div', 'p', 'a', 'em'])
* // => <div><p><a><em></em></a></p></div>
*/
function assemble(tags) {
const elements = tags.map((tag) => document.createElement(tag));
elements.forEach((element, index, elements) => {
// console.log('element:', element);
if (index !== elements.length - 1) {
element.appendChild(elements[index + 1]);
}
});
return elements[0];
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment