1、将下面两个文件拷贝到自己的代码目录中
component/jsonFormat/index.js:
import CollapsedImg from '../../assets/images/collapsed.gif';
import ExpandedImg from '../../assets/images/expanded.gif';
export default function JsonFormatter(opt) {
this.options = {
dom: '',
tabSize: 2,
singleTab: ' ',
quoteKeys: true,
imgCollapsed: CollapsedImg,
imgExpanded: ExpandedImg,
isCollapsible: true,
...opt,
};
this.isFormated = false;
this.obj = {
_dateObj: new Date(),
_regexpObj: new RegExp(),
};
this.init();
}
JsonFormatter.prototype = {
init() {
this.tab = this.multiplyString(this.options.tabSize, this.options.singleTab);
},
doFormat(jsonStr) {
let html;
try {
html = this.ProcessObject(JSON.parse(jsonStr), 0, false, false, false);
this.options.dom.innerHTML = `<pre class='jf-CodeContainer'>${html}</pre>`;
this.isFormated = true;
this.bindEvent();
} catch (e) {
alert(`JSON数据格式不正确:\n${e.message}`);
this.options.dom.innerHTML = '';
this.isFormated = false;
}
},
bindEvent() {
const that = this;
const elements = document.getElementsByClassName('imgToggle');
Array.prototype.forEach.call(elements, (el) => {
const element = el;
element.onclick = function callback() {
if (!that.isFormated) {
return;
}
that.makeContentVisible(this.parentNode.nextElementSibling, !parseInt(this.getAttribute('data-status'), 10));
};
});
},
getRow(indent, data, isPropertyContent) {
let tabs = '';
let newData = data;
if (!isPropertyContent) {
tabs = this.multiplyString(indent, this.tab);
}
if (data && data.length > 0 && data.charAt(data.length - 1) !== '\n') {
newData = `${data}\n`;
}
return tabs + newData;
},
formatLiteral(literal, quote, comma, indent, isArray, style) {
let newLiteral = literal;
if (typeof literal === 'string') {
newLiteral = literal.split('<').join('<').split('>').join('>');
}
let str = `<span class='jf-${style}'>${quote}${newLiteral}${quote}${comma}</span>`;
if (isArray) str = this.getRow(indent, str);
return str;
},
multiplyString(num, str) {
let result = '';
for (let i = 0; i < num; i += 1) {
result += str;
}
return result;
},
makeContentVisible(element, visible) {
const img = element.previousElementSibling.querySelectorAll('img')[0];
if (visible) {
element.style.display = '';
img.setAttribute('src', this.options.imgExpanded);
img.setAttribute('data-status', 1);
} else {
element.style.display = 'none';
img.setAttribute('src', this.options.imgCollapsed);
img.setAttribute('data-status', 0);
}
},
ProcessObject(obj, indent, addComma, isArray, isPropertyContent) {
let html = '';
const comma = addComma ? "<span class='jf-Comma'>,</span> " : '';
const type = typeof obj;
let clpsHtml = '';
if (Array.isArray(obj)) {
if (obj.length === 0) {
html += this.getRow(indent, `<span class='jf-ArrayBrace'>[ ]</span>${comma}`, isPropertyContent);
} else {
clpsHtml = this.options.isCollapsible
? `<span><img class='imgToggle' data-status='1' src='${this.options.imgExpanded}'/></span><span class='jf-collapsible'>`
: '';
html += this.getRow(indent, `<span class='jf-ArrayBrace'>[</span>${clpsHtml}`, isPropertyContent);
for (let i = 0; i < obj.length; i += 1) {
html += this.ProcessObject(obj[i], indent + 1, i < obj.length - 1, true, false);
}
clpsHtml = this.options.isCollapsible ? '</span>' : '';
html += this.getRow(indent, `${clpsHtml}<span class='jf-ArrayBrace'>]</span>${comma}`);
}
} else if (type === 'object') {
if (!obj) {
html += this.formatLiteral('null', '', comma, indent, isArray, 'Null');
} else {
const numProps = Object.keys(obj).length;
if (numProps === 0) {
html += this.getRow(indent, `<span class='jf-ObjectBrace'>{ }</span>${comma}`, isPropertyContent);
} else {
clpsHtml = this.options.isCollapsible
? `<span><img class='imgToggle' data-status='1' src='${this.options.imgExpanded}'/></span><span class='jf-collapsible'>`
: '';
html += this.getRow(indent, `<span class='jf-ObjectBrace'>{</span>${clpsHtml}`, isPropertyContent);
let j = 0;
Object.keys(obj).forEach((prop) => {
const quote = this.options.quoteKeys ? '"' : '';
j += 1;
html += this.getRow(
indent + 1,
`<span class='jf-PropertyName'>${quote}${prop}${quote}</span>: ${this.ProcessObject(
obj[prop],
indent + 1,
j < numProps,
false,
true,
)}`,
);
});
clpsHtml = this.options.isCollapsible ? '</span>' : '';
html += this.getRow(indent, `${clpsHtml}<span class='jf-ObjectBrace'>}</span>${comma}`);
}
}
} else if (type === 'number') {
html += this.formatLiteral(obj, '', comma, indent, isArray, 'Number');
} else if (type === 'boolean') {
html += this.formatLiteral(obj, '', comma, indent, isArray, 'Boolean');
} else if (type === 'undefined') {
html += this.formatLiteral('undefined', '', comma, indent, isArray, 'Null');
} else {
html += this.formatLiteral(
obj.toString().split('\\').join('\\\\').split('"').join('\\"'),
'"',
comma,
indent,
isArray,
'String',
);
}
return html;
},
};
component/jsonFormat/index.css:
@charset "utf-8";
/* CSS Document */
.jf-ObjectBrace {
color: #00aa00;
font-weight: bold;
}
.jf-ArrayBrace {
color: #0033ff;
font-weight: bold;
}
.jf-PropertyName {
color: #cc0000;
font-weight: bold;
}
.jf-String {
color: #007777;
}
.jf-Number {
color: #aa00aa;
}
.jf-Boolean {
color: #0000ff;
}
.jf-Null {
color: #0000ff;
}
.jf-Comma {
color: #000000;
font-weight: bold;
}
pre.jf-CodeContainer {
margin-top: 0;
margin-bottom: 0;
text-align: left;
}
2、使用
// demo.tsx
import JsonFormatter from '../../components/JsonFormatter';
import '../../components/JsonFormatter/index.css';
const reqDom = document.getElementById('reqformatter');
const reqOptions = {
dom: reqDom,
};
const req = new JsonFormatter(reqOptions);
if (detailData?.main_req) {
req.doFormat(detailData?.main_req);
}
<span id="reqformatter" />
3、效果图