本文将使用原生js,来将dom树中的一个dom对象,转化为json。包含有属性值!!
目录
代码
function dom2json(id) {
let dom1 = document.getElementById(id)
let domStr = dom1.outerHTML
let _2json = function (str) {
let nodes = []
let res = null
let children = []
let reg = new RegExp(/<(\w+)( [^>]+)*>([\w\W]*)<\/\1>/g)
res = reg.exec(str);
if (res === null) {
return str
}
while (res !== null) {
nodes.push({
tag: res[1],
attribute: res[2]?res[2].split(' ').reduce((prev, cur, ind)=>{
let kv = cur.split('=')
if(kv.length===2){
prev[kv[0]] = kv[1].replace(/\"/g, "")
}
return prev
},{}):null,
children: _2json(res[3])
})
res = reg.exec(str);
}
return nodes
}
return _2json(domStr)
}
使用案例
使用方法,给定一个元素id 值,之后调用 dom2json(id), 就
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Document</title>
</head>
<body>
<h1 id="a" class="124">
<div>
<div>hhasd1</div>
<p>
<img src="sad12" />
</p>
</div>
<p>1243</p>
</h1>
<script>
function dom2json(id) {
let dom1 = document.getElementById(id)
let domStr = dom1.outerHTML
let _2json = function (str) {
let nodes = []
let res = null
let reg = new RegExp(/<(\w+)( [^>]+)*>([\w\W]*)<\/\1>/g)
res = reg.exec(str);
if (res === null) {
return str
}
while (res !== null) {
nodes.push({
tag: res[1],
attribute: res[2] ? res[2].split(' ').reduce((prev, cur, ind) => {
let kv = cur.split('=')
if (kv.length === 2) {
prev[kv[0]] = kv[1].replace(/\"/g, "")
}
return prev
}, {}) : null,
children: _2json(res[3])
})
res = reg.exec(str);
}
return nodes
}
return _2json(domStr)[0]
}
console.log(JSON.stringify(dom2json("a"), null, '\t'))
</script>
</body>
</html>
控制台输出结果!!
(!观察上图,此代码暂不支持单标签!仅供参考,生产环境使用需谨慎)
关键点讲解
1. 正则匹配一个双标签
let reg = new RegExp(/<(\w+)( [^>]+)*>([\w\W]*)<\/\1>/g)
// <(\w+)( [^>]+)*> : 会匹配到<a> 或者 <a class="sad">
// ( [^>]+)* 可以匹配到非 > 的所有内容,也就是属性们
// ([\w\W]*) 是标签里的内容,注意这里要匹配到换行!
// <\/\1> 是匹配闭合标签, \1 表示于第一个()匹配的内容相同,也就是和(\w+)一样
2. exec() 函数
为了直观的认识,我们可以按下F12
打开控制台,运行一下以下代码
str = "<h1>asdsa</h1><h2 class=”123“>214</h2>"
let reg = new RegExp(/<(\w+)( [^>]+)*>([\w\W]*)<\/\1>/g)
console.log(reg.exec(str));
console.log(reg.exec(str));
console.log(reg.exec(str));
console.log(reg.exec(str));
console.log(reg.exec(str));
console.log(reg.exec(str));
console.log(reg.exec(str));
输出如下,可见reg.exec(str),每次执行,结果是一次匹配成功的结果,当扫描完整条语句,返回null值,又从头开始匹配!!
(内部实现:当 RegExpObject 是全局正则表达式时,exec()会在 RegExpObject 的 lastIndex 属性指定的字符处开始检索字符串 string。当 exec() 找到了与表达式相匹配的文本时,在匹配后,它将把 RegExpObject 的 lastIndex 属性设置为匹配文本的最后一个字符的下一个位置。这就是说,您可以通过反复调用 exec() 方法来遍历字符串中的所有匹配文本。当 exec() 再也找不到匹配的文本时,它将返回 null,并把 lastIndex 属性重置为 0。【引用:https://www.w3school.com.cn/js/jsref_exec_regexp.asp】)
3. 属性字符串转json
res[2].split(' ').reduce((prev, cur, ind) => {
let kv = cur.split('=')
if (kv.length === 2) {
prev[kv[0]] = kv[1].replace(/\"/g, "")
}
return prev
}, {})
正则匹配的结果中res[2]
(数组的第三个元素)为属性字符串,将他以空格分割,再以"="
分割就获取了最后的键值对形式!之后就是将他们添加到一个{}
了。使用Arrange.reduce((prev, cur, ind)=>{return prev}, init)
可以同时完成对数组的遍历和结果的构造,其中init
为结果的初始值,prev
表示结果再遍历是的累计量,cur
表示当前元素,ind
表示他的索引,或者说遍历的次数-1。执行起来等价于
prev = init
Arrange.forEach( cur,ind =>{
// 对prev 的操作,如 prev = prev + cur ...
return prev
})
4、json格式化输出
JSON.stringify(your_json, null, '\t')