您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
格式化显示JSON使数据看起来更加漂亮,支持折叠/展开格式化后的数据,支持JSON脑图让调用层级看着更清晰,支持复制JSON脑图节点路径
当前为
- // ==UserScript==
- // @license MIT
- // @name JSON Viewer
- // @namespace http://tampermonkey.net/
- // @version 0.4.8
- // @note v0.4.8 代码优化
- // @note v0.4.7 增加对JSONP的判断,代码优化
- // @note v0.4.6 增加复制按钮,JSON脑图CSS样式细节优化,JSON脑图增加收起/展开子节点按钮
- // @note v0.4.5 在json-viewer-updated原基础上进行了一些修改,主要有CSS样式修改,新增折叠/展开全部功能,新增JSON脑图功能,脑图节点点击显示调用路径
- // @description 格式化显示JSON使数据看起来更加漂亮,支持折叠/展开格式化后的数据,支持JSON脑图让调用层级看着更清晰,支持复制JSON脑图节点路径
- // @author Feny
- // @match *://*/*
- // @grant GM_addStyle
- // @grant GM_getResourceText
- // @grant GM_setClipboard
- // @icon data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAeAB4AAD/4QAiRXhpZgAATU0AKgAAAAgAAQESAAMAAAABAAEAAAAAAAD/2wBDAAIBAQIBAQICAgICAgICAwUDAwMDAwYEBAMFBwYHBwcGBwcICQsJCAgKCAcHCg0KCgsMDAwMBwkODw0MDgsMDAz/2wBDAQICAgMDAwYDAwYMCAcIDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAz/wAARCAAgACADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD9wvjF8bLX4ZrHZx+XNqlwnmKjH5YUyRvb6kEAd8H058d1b47XV5Ir3eoN++bagaXYrN6KOBn2FfPPx5/aEutX8a+KNWhIubhruZLSNj8u1WMcIOP4QoXOOwNS/wDBM79lDTfjh8YNe+IXj63TxRdeHfKjsE1KMTxtdSbmMmxvlAiVV2IBsUybgAyKR9ZTy6lhsM69Xovm2+iPmKmOqYjEKjT6v5WXU9e8beKrjxZpp/s/xFrfhjWIwWs9X0q42z2kmPlZo2zDcxjqYZ0eNv7obDDf/YL/AG8L745eJNc+G3xCttP0n4qeEWZZ2sVZNP8AENsu0rd2ysS0ZKPG7RMSQsisCcukWd+3x4RtfhpqGk+JNPjS0g1mV7a8iT5UM4XesgHYsofdjglQepJPxwPE1x4V/au8LePtNkeK40ma0lmdDgyorvHMhPo9uxjP+y1bUcHRxmGbS1adn1TXT0/4fcipiqmExCi3pfVdGn19f+GLni/w7ceGf2wPFXga+Vo5rW/vDbI3WWI/v4HA/wBqBg3tk+lfWX7AXia1+F/iDV9B1CRbWHXjFLayyHannpuUxk+rqy4zxlMdWAPQft7fsL33x91nQfiD4DutP0r4oeDXVrT7cWWx1y3UsTZ3LKCyAh5FEigkLLIpHzBk5vwj4JuvE2kLJfeHdY8N6lGAl5pepwBZrOT+JRIuYp0ByBNCzxPg4bIICqYyljMKot62Sa6prr6P/gBDC1MLiHJLS90+jT6ev/Dnmn/BVP8Aaw0nxv4/8P8Aw18KXK69qmk3MlxqEdiRMwuivlpbrtPLopkMnZNy5IIYLyPwa/Z8vvEmv+HtHu4/Ovr+5iS6KDcqAtukwe6om7nuEJxX0XoH7PK/bJG0vRoY5rr/AFslvbLGZf8AfcAf+PGvafgv8CbX4byNqFyI5tWmXYCoytsh6qvqx7t+A4yWiWYUsLhlRpbr72318kVHA1MTiHVqbP7kl0P/2Q==
- // @require https://code.jquery.com/jquery-3.4.1.min.js
- // @require https://unpkg.com/layer-src@3.5.1/dist/layer.js
- // @require https://unpkg.com/jsmind@0.8.5/es6/jsmind.js
- // @resource swalStyle https://unpkg.com/jsmind@0.8.5/style/jsmind.css
- // @resource layerStyle https://unpkg.com/layer-src@3.5.1/dist/theme/default/layer.css
- // ==/UserScript==
- /*随机字符串*/
- function randomString(e) {
- var e = e || 32,
- t = "ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678",
- a = t.length,
- n = "";
- for (i = 0; i < e; i++){
- n += t.charAt(Math.floor(Math.random() * a));
- }
- return n
- }
- /*检查是否是图片链接*/
- function isImg(pathImg) {
- var regexp = /^(http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?\/([\w#!:.?+=&%@!\-\/])*\.(gif|jpg|jpeg|png|GIF|JPG|PNG)([\w#!:.?+=&%@!\-\/])?/;
- return regexp.test(pathImg);
- }
- /** 检验内容是否是json格式的内容*/
- function isJSON(str) {
- if (typeof str == 'string') {
- try {
- var obj = JSON.parse(str);
- if(typeof obj == 'object' && obj ){
- console.log("is json")
- return true;
- }else{
- console.log("is not json")
- return false;
- }
- } catch(e) {
- console.log("is not json", e)
- return false;
- }
- }
- }
- // jquery.json-viewer 插件 开始
- // 解决和原网页jquery版本冲突
- var jq = jQuery.noConflict(true);
- (function(jq){
- /**
- * 检查 arg 是否为至少包含 1 个元素的数组或至少包含 1 个键的字典
- */
- function isCollapsable(arg) {
- return arg instanceof Object && Object.keys(arg).length > 0;
- }
- /**
- * 检查字符串是否为URL
- */
- function isUrl(string) {
- var regexp = /^(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?/;
- return regexp.test(string);
- }
- /**
- * 将 JSON 对象转换为 HTML 表示形式
- * @return string
- */
- function json2html(json) {
- var html = '';
- if (typeof json === 'string') {
- /* Escape tags */
- json = json.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
- if (isUrl(json)){
- html += `<a href="${json}" class="json-string">"${json}"</a>`;
- }
- else{
- html += `<span class="json-string">"${json}"</span>`;
- }
- }
- else if (typeof json === 'number') {
- html += `<span class="json-number ">${json}</span>`;
- }
- else if (typeof json === 'boolean') {
- html += `<span class="json-bool ">${json}</span>`;
- }
- else if (json === null) {
- html += '<span class="json-null">null</span>';
- }
- else if (json instanceof Array) {
- if (json.length > 0) {
- html += '<span class="b">[</span><ol class="json-array">';
- for (var i = 0; i < json.length; ++i) {
- html += '<li>';
- /* Add toggle button if item is collapsable */
- if (isCollapsable(json[i])) {
- html += '<a href class="json-toggle"></a>';
- }
- html += json2html(json[i]);
- /* Add comma if item is not last */
- if (i < json.length - 1) {
- html += ',';
- }
- html += '</li>';
- }
- html += '</ol><span class="b">]</span>';
- }
- else {
- html += '[]';
- }
- }
- else if (typeof json === 'object') {
- var key_count = Object.keys(json).length;
- if (key_count > 0) {
- html += '<span class="b">{</span><ul class="json-dict">';
- for (var key in json) {
- if (json.hasOwnProperty(key)) {
- html += '<li>';
- /* Add toggle button if item is collapsable */
- if (isCollapsable(json[key])) {
- html += '<a href class="json-toggle"></a>';
- }
- html += `<span class="json-key">"${key}"</span>: ${json2html(json[key])}`;
- /* Add comma if item is not last */
- if (--key_count > 0){
- html += ',';
- }
- html += '</li>';
- }
- }
- html += '</ul><span class="b">}</span>';
- }
- else {
- html += '{}';
- }
- }
- return html;
- }
- jq.fn.jsonViewer = function(json, jsonpFunctionName) {
- return this.each(function() {
- /* Transform to HTML */
- var html = json2html(json);
- /** is JSONP */
- if(jsonpFunctionName !== undefined && jsonpFunctionName !== null){
- html = `<div class="jsonp">${jsonpFunctionName}(</div>${html}<div class="jsonp">)</div>`
- }
- /* Insert HTML in target DOM element */
- jq(this).html(html);
- /* Bind click on toggle buttons */
- jq(this).off('click');
- jq(this).on('click', 'a.json-toggle', function() {
- var target = jq(this).toggleClass('collapsed').siblings('ul.json-dict, ol.json-array');
- target.toggle();
- if (target.is(':visible')) {
- target.siblings('.json-placeholder').remove();
- }
- else {
- var count = target.children('li').length;
- var placeholder = count + (count > 1 ? ' items' : ' item');
- target.after('<a href class="json-placeholder">' + placeholder + '</a>');
- }
- return false;
- });
- /* Simulate click on toggle button when placeholder is clicked */
- jq(this).on('click', 'a.json-placeholder', function() {
- jq(this).siblings('a.json-toggle').click();
- jq(this).siblings('a.json-placeholder').remove();
- return false;
- });
- });
- };
- })(jq);
- // jquery.json-viewer 插件 结束
- (function() {
- 'use strict';
- var source = jq('pre[style="word-wrap: break-word; white-space: pre-wrap;"]').first();
- // 根据上面这一点没办法确定是需要添加json格式化工具,再加上对内容进行判断是不是json格式的内容
- let rawText = source.html()
- if(!rawText){
- return
- }
- // 判断是否为jsonp格式
- let tokens = rawText.match(/^([^\s(]*)\s*\(([\s\S]*)\)\s*;?$/),
- jsonpFunctionName = null;
- if (tokens && tokens[1] && tokens[2]) {
- jsonpFunctionName = tokens[1]
- rawText= tokens[2]
- }
- // 如果是直接打开的json接口地址才需要格式化插件
- if(source.length == 0 || !isJSON(rawText)){
- return
- }
- // 随机rgb颜色
- let rgbaColor = `${Math.random()*256}, ${Math.random()*256}, ${Math.random()*256}`
- // 添加样式
- GM_addStyle(GM_getResourceText('swalStyle'))
- GM_addStyle(GM_getResourceText('layerStyle'))
- GM_addStyle(`
- #json-renderer {
- line-height: 1.5;
- font-size: 14px;
- display: block;
- font-family: monospace;
- margin: 15px 30px;
- }
- .btnGroup, .jmBtnGroup{
- position: fixed;
- top: 30px;
- right: 30px;
- }
- .btn {
- border: 1px solid rgb(218, 220, 224);
- box-sizing: border-box;
- color: rgb(26, 115, 232);
- cursor: pointer;
- line-height: 28px;
- float: left;
- display: inherit;
- padding: 0 10px;
- }
- .btn:hover {
- background-color: rgb(210, 227, 252);
- }
- ul.json-dict,
- ol.json-array {
- list-style-type: none;
- margin: 0 0 0 2px;
- border-left: 1px dotted #5D6D7E;
- padding-left: 24px;
- }
- .b {
- font-weight: 700;
- }
- .jsonp{
- margin-left: -30px;
- }
- .json-key {
- /* color: #A31515;*/
- color: #910F93;
- }
- .json-string {
- /* color: #0b7500;*/
- color: #4B8A4C;
- }
- .json-number {
- /* color: #164FF0;*/
- color: #1a01cc;
- font-weight: 600;
- }
- .json-bool{
- color: #905;
- font-weight: 600;
- }
- .json-null {
- /* color: #F1592A;*/
- color: #0031BC;
- font-weight: 600;
- }
- a.json-toggle {
- position: relative;
- color: inherit;
- opacity: 0.2;
- text-decoration: none;
- }
- a.json-toggle:hover {
- opacity: 0.35;
- }
- a.json-toggle:active {
- opacity: 0.5;
- }
- a.json-toggle:focus {
- outline: none;
- }
- a.json-toggle:before {
- top: 2.5px;
- left: -15px;
- position: absolute;
- content: "";
- display: block;
- width: 0;
- height: 0;
- border-style: solid;
- border-width: 5px 0 5px 8px;
- border-color: transparent transparent transparent currentColor;
- transform: rotate(90deg);
- }
- a.json-toggle.collapsed:before {
- transform: rotate(0deg);
- }
- a.json-placeholder {
- color: #aaa;
- font-size: 13px;
- padding: 0 1em;
- text-decoration: none;
- }
- a.json-placeholder:hover {
- text-decoration: underline;
- }
- #jsmind_container{
- position: fixed;
- z-index: 999;
- top: 0;
- left: 0;
- display: none;
- width: 100vw;
- height: 100%;
- background:#F7F7F7
- }
- .jmBtnGroup{
- z-index: 9999;
- display: none;
- }
- /**脑图自定义样式*/
- jmnode{
- display: flex;
- align-items: center;
- padding: 0 7px 0 22px;
- }
- jmnode{
- color: #475872 !important;
- box-shadow: none !important;
- background-color: transparent !important;
- }
- jmnode:hover{
- text-shadow: 1px 1px 1px currentColor;
- }
- jmnode.root {
- padding: 0;
- color: transparent !important;
- }
- jmnode:not(.root)::before, jmnode.root::before{
- content: " ";
- top: 50%;
- position: absolute;
- border-radius: 50%;
- transform: translateY(-50%);
- }
- jmnode:not(.root)::before{
- left: 0;
- width: 15px;
- height: 15px;
- background: rgba(${rgbaColor}, 0.5);
- }
- jmnode.root::before{
- left: 50%;
- width: 18px;
- height: 18px;
- transform: translate(-18px, -50%);
- background: rgba(${rgbaColor}, 0.7);
- }
- jmexpander{
- margin-top: 1px;
- line-height: 9px;
- }
- .layui-layer-tips{
- width: auto !important;
- }
- .mind-array{
- opacity: 0.5;
- font-size: 12px;
- padding-left: 5px;
- }
- `)
- source.attr("id", "json-source").hide()
- // 将内容用eval函数处理下
- var jsonObject = eval('(' + rawText + ')');
- // 添加一个格式化显示的per元素
- jq("body").append('<div id="json-renderer"></div>')
- .append(`<div class="btnGroup"><input class="btn" type="button" value="复制" id="copyJson"/>
- <input class="btn" type="button" value="折叠全部" id="collapseJson"/>
- <input class="btn" type="button" value="JSON脑图" id="showMind"/>
- <input class="btn" type="button" value="原文本" id="switchRawText"/></div>`)
- // JSON脑图相关
- .append(`<div id="jsmind_container"></div>
- <div class="jmBtnGroup"><input class="btn" type="button" value="收起节点" id="collapseNode"/>
- <input class="btn" type="button" value="展开节点" id="expandNode"/>
- <input class="btn" type="button" value="返回" id="closeMind"/></div>`);
- // 调用格式化方法
- jq('#json-renderer').jsonViewer(jsonObject, jsonpFunctionName);
- let btnEvent = {
- // 复制JSON文本内容
- copyJson: function(){
- GM_setClipboard(JSON.stringify(jsonObject))
- layer.msg('复制成功', {time: 1500})
- },
- // 折叠全部的JSON结构
- collapseJson: function(e){
- var that = jq(e), v = that.val();
- if(v === "折叠全部"){
- jq('.json-toggle').not('.collapsed').click()
- }else{
- jq('a.json-placeholder').click().remove();
- }
- that.val(v === "折叠全部" ? "展开全部" : "折叠全部")
- },
- // 查看原始/格式化JSON内容
- switchRawText: function(e){
- var that = jq(e), v = that.val();
- that.val(v === '原文本' ? "格式化" : "原文本")
- jq('#json-source, #json-renderer').toggle();
- },
- // 显示JSON脑图
- showMind: function(){
- let isArr = false;
- if(Array.isArray(jsonObject)){
- if(typeof jsonObject[0] !== 'object'){
- layer.msg('数据结构无法生成脑图', {time: 1000})
- return
- }
- isArr = true
- jsonObject = jsonObject[0]
- }
- jq('.jmBtnGroup').show()
- jq('#jsmind_container').fadeToggle(200);
- document.documentElement.style.overflow='hidden';
- if(!window.jm){
- window.jm = new jsMind({
- mode :'side',
- editable: false,
- container:'jsmind_container',
- view: {
- hmargin: 50, // 思维导图距容器外框的最小水平距离
- vmargin: 50, // 思维导图距容器外框的最小垂直距离
- engine: 'svg', // 思维导图各节点之间线条的绘制引擎
- draggable: true, // 当容器不能完全容纳思维导图时,是否允许拖动画布代替鼠标滚动
- support_html : false,
- line_color: '#C4C9D0',
- },
- layout: {
- vspace: 7, // 节点之间的垂直间距
- hspace: 150, // 节点之间的水平空间
- },
- });
- jm.show({
- "meta":{
- "name":"JSON脑图",
- "author":"1220301855@qq.com",
- "version":"1.0"
- },
- "format":"node_tree",
- /* 数据内容 */
- "data": {
- "id": "root",
- "topic": 'Response',
- "direction": "left",
- "children": convertToMind(jsonObject),
- "chain": isArr ? 'Response[i]' : 'Response'
- }
- });
- // 脑图节点事件
- jq("jmnode").on('dblclick mouseover mouseout', function(event){
- let that = jq(this),
- node = jm.get_node(that.attr('nodeid'))
- if(!node.parent){
- return
- }
- switch(event.type){
- case 'dblclick':
- GM_setClipboard(mindChain(node))
- layer.msg('节点路径复制成功', {time: 1500})
- break;
- case 'mouseover':
- let s = `<b>节点路径(双击复制)</b><br/>${mindChain(node)}`
- layer.tips(s, that, {
- time: 0,
- tips: [2, '#1e2732']
- });
- break;
- default:
- layer.closeAll()
- break;
- }
- })
- }
- },
- // 收起节点
- collapseNode: () => jm.collapse_all(),
- // 展开节点
- expandNode: () => jm.expand_all(),
- // 关闭JSON脑图
- closeMind: function(){
- jq('.jmBtnGroup').hide()
- jq('#jsmind_container').fadeToggle(200);
- document.documentElement.style.overflow='';
- },
- }
- // 按钮点击事件
- jq('.btn').click(e => btnEvent[e.target.id](e.target))
- // 所有a标签,看是否是图片,是图片生成预览图
- jq("a.json-string").hover(function(){
- var that = jq(this), href = that.attr('href');
- if(isImg(href)){
- layer.tips(`<img src="${href}" />`, that, {
- time: 0,
- anim: 5,
- maxWidth: 500,
- tips: [2, '#d9d9d9']
- });
- }
- }, () => layer.closeAll())
- })();
- /** JSON数据转换为jsMind所需要的数据结构 */
- function convertToMind(json){
- let children = []
- if(typeof json === 'object'){
- for (let i = 0, keys = Object.keys(json); i < keys.length; i++){
- let val = json[keys[i]];
- if(val === null || ['string', 'number', 'boolean', 'undefined'].includes(typeof val)){
- children.push({
- id: keys[i] + '-' + randomString(10),
- topic: `${keys[i]}`,
- chain: keys[i]
- })
- } else if(Array.isArray(val)){
- children.push({
- id: keys[i] + '-' + randomString(10),
- topic: `${keys[i]}<span class="mind-array">[${val.length}]</span>`,
- chain: keys[i],
- isArray: true,
- children: convertToMind(val[0], keys[i])
- })
- } else if(typeof val === 'object'){
- children.push({
- id: keys[i] + '-' + randomString(10),
- topic: `${keys[i]}`,
- chain: keys[i],
- children: convertToMind(val, keys[i])
- })
- }
- }
- }
- return children;
- }
- // 脑图节点调用链
- function mindChain(node){
- let s = node.data.chain
- if(!node.parent){
- return s
- }
- let p = node.parent, r = mindChain(p)
- s = p.data.isArray ? `${r}[i].${s}` : `${r}.${s}`
- return s
- }
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址