Created
June 17, 2018 13:04
-
-
Save legend80s/e3a08a7d3d85fbe49754c5fa56139ff1 to your computer and use it in GitHub Desktop.
compile string to DOM
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* 将字符串编译为 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