最近开发了一个chrome插件,需要找一个轻量级的可视化编辑json的组件。当然使用ace这一类组件是完全可以的,但是个人感觉比较重量。于是查阅了一些资料,整理如下。
对于一个json字符串,通过javascript的如下方法可以很方便的对其格式化:
var jsonObj = JSON.parse(json_val) //把json字符串转为json对象
var formattedStr = JSON.stringify(jsonObj, null, 4);
将formattedStr字符串可以输出到textarea组件中。这种方法简单粗暴,缺少了json的折叠、高亮等功能;更进一步,可以通过以下两个组件实现可视化展示json数据:
- jquery.json-viewer.js:jquery的一个可视化json插件,项目地址 https://www.jqueryscript.net/other/jQuery-Plugin-For-Easily-Readable-JSON-Data-Viewer.html
- JSONView:可视化json组件,github地址:https://github.com/yesmeck/jquery-jsonview
更多见:https://blog.csdn.net/liuxiao723846/article/details/103774795
以上,是如何可视化展示json数据的方法,而这次的需求不光是要可视化展示,还要可以编辑json数据,于是在github上找到了这个代码(https://github.com/dblate/jquery.json-editor),在demo页面(https://dblate.github.io/jquery.json-editor/)中试用了一下,感觉已经满足了我的需求(可编辑+小巧)。
阅读源码发现该项目的代码非常简单,简单到几乎没有任何实现,完全依赖底层的jquery.json-viewer.js库(上面已介绍)。所以,接下来我们就直接使用jquery.json-viewer.js这个库来实现可以编辑的json格式化组件。
先上例子:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="https://cdn.jsdelivr.net/npm/[email protected]/json-viewer/jquery.json-viewer.css" rel="stylesheet">
</head>
<style type="text/css">
#json-display {
border: 1px solid #000;
margin: 0;
padding: 8px 15px;
min-height: 300px;
background: #1c2833;
color: #fff;
}
</style>
<body>
<div style="padding: 40px 20px 0px 20px;">
<div>
<pre id="json-display" contenteditable="true"></pre>
</div>
<br>
<input type="button" id="format_btn" value="格式化" onclick="format_btn();" />
</div>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/[email protected]/json-viewer/jquery.json-viewer.js"></script>
<script>
$(document).ready(function(){
var jsonObj = {"a":1,"b":"test"};
$("#json-display").jsonViewer(jsonObj,{withQuotes: true});//格式化展示
});
function format_btn() {
var jsonval = $("#json-display").text();
var jsonObj = JSON.parse(jsonval); //把json字符串转为json对象
$("#json-display").jsonViewer(jsonObj,{withQuotes: true});//格式化展示
}
</script>
</body>
</html>
效果如下图:
1、如何做到的可编辑?
contenteditable 属性是 HTML5 中的新属性;该属性规定元素内容是否可编辑。那么通过该数据,就可以对jquery.json-viewer.js中的<pre>节点进行编辑了。例如:
<!DOCTYPE HTML>
<html>
<body>
<div contenteditable="true">这是一段可编辑的段落。请试着编辑该文本。</div>
</body>
</html>
2、复制时去掉格式:
通过contenteditable属性,将<pre>变成可编辑的,当把网页中的json数据复制到编辑框中,发现会把格式也复制进去,例如:
解决方案:
$(document).ready(function(){
//paste clean format
$("#json-display").on("paste", function (e) {
textInit(e)
});
});
function textInit(e) {
e.preventDefault();
var text;
var clp = (e.originalEvent || e).clipboardData;
if (clp === undefined || clp === null) {
text = window.clipboardData.getData("text") || "";
if (text !== "") {
if (window.getSelection) {
var newNode = document.createElement("span");
newNode.innerHTML = text;
window.getSelection().getRangeAt(0).insertNode(newNode);
} else {
document.selection.createRange().pasteHTML(text);
}
}
} else {
text = clp.getData('text/plain') || "";
if (text !== "") {
document.execCommand('insertText', false, text);
}
}
}
3、遇到问题一:
输入如下的json数据进行格式化,格式化后c节点的value值没有被引号包裹:
{"a":1,"b":"test","c":"http://test.com"}
结果如下:(这样会破坏了原始json数据)
说明:对于json数据结构的标准,key是必须要有双引号;value则根据类型,如果是字符串需要使用双引号。json-viewer.js库可以通过如下属性,设置key是否使用引号:
$("#json-display").jsonViewer(jsonObj,{withQuotes: true});
解决方法:
从json-viewer.js源码可以发现,源码中会判断value是否是url,如果是则直接输出
所以,可以直接修改源码,添加上双引号。
4、遇到问题二:
输入如下json数据进行格式化,格式化后extra节点的value值也被当作了json,再次被格式化:
{"a":1,"extra":"{\n \"circles\" : [\n \"史莱姆\"\n ],\n \"tags\" : [\n \"危险的她\"\n ],\n \"topics\" : [\n \"好久不见\"\n ]\n}"}
结果如下:(破坏了原始json 数据)
解决方法:
使用JSON.stringify方法保留字符串中的\n等,然后直接输出:
if (typeof json === 'string') {
// Escape tags and quotes
json = json.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
if (options.withLinks && isUrl(json)) {
html += '<a href="' + json + '" class="json-string" target="_blank">"' + json + '"</a>';
} else {
json = JSON.stringify(json);//保留字符串中的\n等
let len = json.length -1;
if (json.indexOf("\"") ===0 && json.lastIndexOf("\"") ===len) {
html += '<span class="json-string">' + json + '</span>';
} else {
html += '<span class="json-string">"' + json + '"</span>';
}
}
}
效果:
5、遇到问题三:
格式化后,可以点击左侧的三角进行折叠,这时该如何获取<pre>节点下的原始json数据?
1)json-viewer原理:
从源码可以看到json-viewer格式化展示json数据的原理是,将json数据结构解析,放到<ul><li>中,对于每个ul节点可以进行toggle操作,从而实现了折叠效果。折叠后,json-viewer会增加一个<a>标签,记录折叠的字节点个数,如下:
2)如何获取纯文本数据?
在jquery中,获取“容器”中的内容有两种方式:html()和text(),前者返回的数据中包括html标签,后者获取的是纯文本数据。text()方法的原理是,使用正则表达式,去除所有html标签。
function delHtmlTag(str) {
return str.replace(/<[^>]+>/g,"");//去掉所有的html标记
}
3)json-viewer格式化json后如何获取纯json数据?
我们知道,当折叠互后json-viewer会增加<a>标签,即使使用text()方法获取到纯文本数据,这里面也包含了“n items”的字符串,那么该如何去除掉这些字符串呢?
思路:使用jquery拷贝<pre>节点,然后remove那些折叠的节点数据(<a href="" class="json-placeholder">2 items</a>)
$("#format_btn").click(function(){
var my_json_val = $("#json-display").clone(false);
my_json_val.find("a.json-placeholder").remove();
var json_val = my_json_val.text();
if(json_val){
try {
var jsonObj = JSON.parse(json_val); //把json字符串转为json对象
$("#json-display").jsonViewer(jsonObj,{withQuotes: true});
} catch(err) {
$("#json-display").html(json_val+"<br><font color='red'>"+err.message+"</font>");
}
}
});
6、如何让<pre>保持一个初始高度,并随着内容增加而变化?
可以使用min-height属性。https://blog.csdn.net/u013063153/article/details/52424255