问题
因为在工作中需要经常写小程序的页面, 但是在写一个页面的时候通常会写完html结构再去写css, 在过程中免不了忘记了元素的类名, 便会在两个文件中不时的切换来切换去, 但若直接用行内样式的写法, 会有什么不好大家都懂... 于是对我来说若能既采用行内样式的写法, 又能分离出html和css的需求就出来了, 所以便花了几个小时写了个小工具: https://www.npmjs.com/package/onetotwo. (还不完善, 只能暂时满足我最基础的需求, 忘大屌们见谅.)
介绍
所以这边一个需要解决的常见问题便是如何解析html结构, 并转换为我所想要的数据结构, 以下为简易版实现(诸多情况尚未考虑):, 主要实现便是一个个读取html字符串, 如果遇到了<
符号变把它当做标签解析, 并记录该标签全部内容, 直到遇到了>
字符, 便开始解析出标签中的style和class属性, 代码如下:
const [Node, Tree] = require('./tree');
function parse(html, _callback) {
// 先去除html中的注释与空白字符
html = html.replace(/<!--[\s\S]*?-->/g, '');
html = html.replace(/>\s+([^\s<]*)\s+</g, '>$1<').trim();
var parseHTML = (function () {
var __i = 0,
__currentFn = parse_text, // 对当前字符的处理函数
__tag = '',
__tag_all_content = '',
__have_root = false,
__tree = new Tree(),
__current_node = null,
__stack = [];
// 处理标签
function parse_tag(token) {
if (token === '/') {
return parse_end_tag;
}
__i --; // 开始处理标签的时候索引需要回退1位
return parse_begin_tag;
}
// 处理开始标签
function parse_begin_tag(token) {
if (token === '>') {
const style_regex = /\bstyle\s*=\s*(?:"([^"]*)"|'([^']*)'|([^'">\s]+))/ig;
const class_regex = /\bclass\s*=\s*(?:"([^"]*)"|'([^']*)'|([^'">\s]+))/ig;
const class_result = class_regex.exec(__tag_all_content);
const style_result = style_regex.exec(__tag_all_content);
const tag_name = __tag_all_content.replace(/\s.*/g, '');
const class_name = class_result && (class_result[1] || class_result[2] || class_result[3]);
const style = style_result && (style_result[1] || style_result[2] || style_result[3]);
if (!__have_root) {
__tree.root = { tag: tag_name, parent: null, child: [], hierarchy: 0 };
__current_node = __tree.root;
__have_root = true;
}else {
let new_node = { tag: tag_name, parent: __current_node, child: [], hierarchy: __stack.length};
__current_node.child.push(new_node);
__current_node = new_node;
}
class_name && (__current_node.class_name = class_name);
style && (__current_node.style = style);
__stack.push(__current_node);
__tag_all_content = '';
return parse_text;
}
__tag_all_content += token;
return parse_begin_tag;
}
// 处理结束标签
function parse_end_tag(token) {
if (token === '>') {
if (__current_node.tag !== __tag) {
console.log('\x1b[31m >>>' + 'Wrong closed tag at char ' + __i + '\x1b[39m');
}
__tag = '';
__stack.pop();
__current_node = __current_node.parent;
return parse_text;
}
__tag += token;
return parse_end_tag;
}
function parse_text(token) {
if (token === '<') {
return parse_tag;
}
return parse_text;
}
return function (html) {
for (; __i < html.length; __i++) {
__currentFn = __currentFn(html[__i]);
}
return __tree;
}
})();
_callback(parseHTML(html))
}
网友评论