// ==UserScript== // @license MIT // @name JSON Viewer // @namespace http://tampermonkey.net/ // @version 0.4.9 // @note v0.4.9 布局修改,增加保存JSON/脑图为文件,增加JSON过滤,鼠标移入key提示json-path // @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_getValue // @grant GM_setValue // @grant unsafeWindow // @grant GM_setClipboard // @grant GM_getResourceText // @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.min.js // @require https://unpkg.com/jsmind@0.8.5/es6/jsmind.js // @require https://unpkg.com/layer-src@3.5.1/dist/layer.js // @require https://unpkg.com/dom-to-image@2.6.0/dist/dom-to-image.min.js // @require https://unpkg.com/jsmind@0.8.5/es6/jsmind.screenshot.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 // @downloadURL none // ==/UserScript== (function() { 'use strict'; const Utils = { // 检查字符串是否为URL isUrl: function (string) { var regexp = /^(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?/; return regexp.test(string); }, // 检查是否是图片链接 isImg: function (pathImg) { // var regexp = /^(http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?\/([\w#!:.?+=&%@!\-\/])*\.(gif|jpg|jpeg|png|GIF|JPG|PNG)([\w#!:.?+=&%@!\-\/])?/; let regexp = /\.(ico|bmp|gif|jpg|jpeg|png|svg|webp|GIF|JPG|PNG|WEBP|SVG)([\w#!:.?+=&%@!\-\/])?/i return regexp.test(pathImg); }, // 检验内容是否是json格式的内容 isJSON: function (str) { try { JSON.parse(str) return true } catch(e) { console.log("is not json", e) return false } }, // 获取数据类型 getType: function (value){ return Object.prototype.toString.call(value).match(/\s(.+)]/)[1].toLowerCase(); }, // JSON 过滤 filterJson: function(json, filter) { if(!filter){ return json } filter = filter.toLowerCase() let newJSON = Utils.getType(json) == 'array' ? [] : {} for (let key in json) { let val = json[key] if (typeof val === 'object') { let subJSON = this.filterJson(val, filter); if (Object.keys(subJSON).length > 0) { newJSON[key] = subJSON; } }else{ if(key.toLowerCase().includes(filter.toLowerCase())){ newJSON[key] = val } if(val !== null && val.toString().toLowerCase().includes(filter.toLowerCase())){ newJSON[key] = val } } } return newJSON; } } // jquery.json-viewer 插件 开始 // 解决和原网页jquery版本冲突 var _jQuery = jQuery.noConflict(true); (function($){ /** * 检查 arg 是否为至少包含 1 个元素的数组或至少包含 1 个键的字典 */ function isCollapsable(arg) { return arg instanceof Object && Object.keys(arg).length > 0; } /** * 将 JSON 对象转换为 HTML 表示形式 * @return string */ function json2html(json, parentPath = '') { let html = '', type = Utils.getType(json) switch(type){ case 'array': case 'object': let len = json.length || Object.keys(json).length; if (len > 0) { html += ''; html += type === 'array' ? '[
    ' : '{
]' }else{ html += '}' } }else{ html += '' html += (type === 'array') ? '[]' : '{}' html += '' } break default: /* Escape tags */ json = type === 'string' ? json.replace(/&/g, '&').replace(//g, '>') : json if (Utils.isUrl(json)){ html += `"${json}"`; }else{ json = type === 'string' ? `"${json}"` : json html += `${json}`; } break } return html; } $.fn.jsonViewer = function(json, jsonpFun) { return this.each(function() { /* Transform to HTML */ var html = json2html(json); /** is JSONP */ if(jsonpFun !== undefined && jsonpFun !== null){ html = `
${jsonpFun}(
${html}
)
` } /* Insert HTML in target DOM element */ $(this).html(html); /* Bind click on toggle buttons */ $(this).off('click'); $(this).on('click', 'a.json-toggle', function() { var target = $(this).toggleClass('collapsed').siblings('ul.json-object, ol.json-array'); target.toggle(); if (target.is(':visible')) { target.siblings('.json-placeholder').remove(); }else { var count = target.children('li:not([class*="hidden"])').length; var placeholder = count + (count > 1 ? ' items' : ' item'); target.after('' + placeholder + ''); } return false; }); /* Simulate click on toggle button when placeholder is clicked */ $(this).on('click', 'a.json-placeholder', function() { $(this).siblings('a.json-toggle').click(); $(this).siblings('a.json-placeholder').remove(); return false; }); }); }; })(_jQuery); // jquery.json-viewer 插件 结束 (function($){ var source = $('pre[style="word-wrap: break-word; white-space: pre-wrap;"]').first(); if(source.length === 0){ return } let rawText = source.text() if(!rawText){ return } // 判断是否为jsonp格式 let jsonpFun = null, tokens = rawText.match(/^([^\s(]*)\s*\(([\s\S]*)\)\s*;?$/) if (tokens && tokens[1] && tokens[2]) { jsonpFun = tokens[1] rawText= tokens[2] } if(!Utils.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(GM_getResourceText('treetableStyle')) $("head").append(``) GM_addStyle(` body, html{ margin: 0; padding: 0; font-size: 14px; } td{ font-size: 14px; } li::marker { content: ''; } .hidden{ display: none !important; } .scroll-top{ width: 48px; height: 48px; z-index: 999; position: fixed; right: 30px; bottom: 30px; background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAAAXNSR0IArs4c6QAAA39JREFUaEPtmV2ITVEUx39rJjT5KPKC5DPKK6UGZZ7Eq0whNUiKFPfcKW9mnmjm7ssLaSLygEx5xItMESnKC4V8FV4IJUkyS+fMHZ07zjl3733PvT6a+3S6Z629/r+99sfa+wgpPw1YDtxLe9/k/1eI4X5STMkSokXWNlloYjgpMZSmIxPgbxBfS8M4QK0eavT78Qw0uodrtd+wDGjAMqBcEVAQw6NaYnzeNwRAi2xBOQlMrYj6jLJTygz6iMzyyR1Ai+xCGUgMqnTmDZErgBYoIJjMXhY2S4mLeWUiNwAt0INwyEqY0iNleq1saxjlAqAB64BrToKEHVLijJNPgnHdALqPaUziOsoKRzGfaKFD+nng6FdlXj+Ay9AZq1Q5L2W2/jEA3c8sWqOSe3aCiK/A3cr/K4G2FKEbxXDZF6KuDKROXKWXFvqlxJdQmBaZzDDdKZP8thhW/RmAgKfA4qrgSq+U6UkSlAostEuJOz4Q3hnQgPXAld+CCh1pB5DogKTcSBAalhpHmw1wGtgxJuhbMczJEqIBbxLmzFUxbGg2gCYE9AVADF6jwctJDzKd73xI7DG/IQQTmCFH+OiaBT+AAyykhWcpBZv7JA4bGmaRHOV5cwBqX7mc5Qe9coyX0TK6n/m0RnVSV4bA1KuTLCi/DBTYhHCpRm+Fe8Bo/b8JmJxp71lqOwNowB7guGuqLe33iuGEpW1k5gTgVDK7qIjbZmyESU1aA1TOuA99dTn5CQulxAsbH3uAeqpOGyXVNrvEcMrGzR4gIGnjsonhYzMkhg4bx3EAm17ysGlIBh4DSzzE+LgMiGG3jaPLEApv2Q7YNFq3jcOmZg9gt/u6aH8PzEx0aGWu9PHapjFrgKimCaIDTHiQqf4pNxHW2AT8ZaMEiZdgSreUKdm25QRQgRi7nIZzI7xZcPmeNkAL5xjmVpVQx1049HUGiCAKFBH6K8GjFUP3MIW2CGJpjd4bFEPnmM54grA761tYWpteAJXgy1A6w6p09Opcu1nED7ZlAcQP/BqwGZjORAblMO9sh03czhsgLZgW6EL4JoYL0b0RTArPBfFnH6G5ZyAVYKTkGBlWQVR2bxDDgvjzvwQQXqGsDQ/sGkTXKdHzOECsB3LtjdjKMjqE/qMMjJwn5olh+98+hM6gvAqXy0aN+4Yuo/HG/weAPmC1GNrzHDbxtn4Coc0pQNdM3UAAAAAASUVORK5CYII=) } /** 工具栏样式 START **/ .flex-container{ height: 100vh; display: flex; flex-direction: column; } .tabs, .toolbar{ display: flex; line-height: 28px; background: #f3f3f3; border-bottom: 1px solid #e0e0e2; } .toolbar{ line-height: 23px; box-shadow: 0px 3px 5px 0 #ddd; } .searchbox{ display: flex; flex-grow: 1; } .toolbar input{ flex-grow: 1; border: none; outline: none; font-size: 12px; padding-left: 23px; background-size: 12px; background-repeat: no-repeat; background-position: 7px center; background-image: url(data:image/svg+xml;base64,PCEtLSBUaGlzIFNvdXJjZSBDb2RlIEZvcm0gaXMgc3ViamVjdCB0byB0aGUgdGVybXMgb2YgdGhlIE1vemlsbGEgUHVibGljCiAgIC0gTGljZW5zZSwgdi4gMi4wLiBJZiBhIGNvcHkgb2YgdGhlIE1QTCB3YXMgbm90IGRpc3RyaWJ1dGVkIHdpdGggdGhpcwogICAtIGZpbGUsIFlvdSBjYW4gb2J0YWluIG9uZSBhdCBodHRwOi8vbW96aWxsYS5vcmcvTVBMLzIuMC8uIC0tPgo8c3ZnIGZpbGw9InJnYmEoMTM1LCAxMzUsIDEzNywgMC45KSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2aWV3Qm94PSIwIDAgMTIgMTIiPgogIDxwYXRoIGZpbGw9ImNvbnRleHQtZmlsbCIgb3BhY2l0eT0iLjQiIGQ9Ik01IDkuMmwyIDEuNlY2LjFMOC41NSA0aC01LjFMNSA2LjF2My4xeiIvPgogIDxwYXRoIGZpbGw9ImNvbnRleHQtZmlsbCIgZD0iTTEuMTggMi42QTEgMSAwIDAgMSAyIDFIMTBhMSAxIDAgMCAxIC44IDEuNkw4IDYuNHY0LjgyYzAgLjYzLS43Mi45OC0xLjIyLjZsLTIuNS0xLjk5QS43NS43NSAwIDAgMSA0IDkuMjVWNi40MUwxLjE4IDIuNnpNMiAyTDUgNi4wOXYzLjA0bDIgMS41OVY2LjA5TDEwLjAxIDJIMnoiLz4KPC9zdmc+Cg==); } .clear { flex: 0 0 auto; align-self: center; margin: 0 4px; padding: 0; border: 0; width: 16px; height: 16px; background-color: transparent; background-image: url(data:image/svg+xml;base64,PCEtLSBUaGlzIFNvdXJjZSBDb2RlIEZvcm0gaXMgc3ViamVjdCB0byB0aGUgdGVybXMgb2YgdGhlIE1vemlsbGEgUHVibGljCiAgIC0gTGljZW5zZSwgdi4gMi4wLiBJZiBhIGNvcHkgb2YgdGhlIE1QTCB3YXMgbm90IGRpc3RyaWJ1dGVkIHdpdGggdGhpcwogICAtIGZpbGUsIFlvdSBjYW4gb2J0YWluIG9uZSBhdCBodHRwOi8vbW96aWxsYS5vcmcvTVBMLzIuMC8uIC0tPgo8c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjE2IiBoZWlnaHQ9IjE2IiB2aWV3Qm94PSIwIDAgMTYgMTYiIGZpbGw9ImNvbnRleHQtZmlsbCIgZmlsbC1vcGFjaXR5PSJjb250ZXh0LWZpbGwtb3BhY2l0eSI+CiAgPHBhdGggZD0iTTYuNTg2IDhsLTIuMjkzIDIuMjkzYTEgMSAwIDAgMCAxLjQxNCAxLjQxNEw4IDkuNDE0bDIuMjkzIDIuMjkzYTEgMSAwIDAgMCAxLjQxNC0xLjQxNEw5LjQxNCA4bDIuMjkzLTIuMjkzYTEgMSAwIDEgMC0xLjQxNC0xLjQxNEw4IDYuNTg2IDUuNzA3IDQuMjkzYTEgMSAwIDAgMC0xLjQxNCAxLjQxNEw2LjU4NiA4ek04IDBhOCA4IDAgMSAxIDAgMTZBOCA4IDAgMCAxIDggMHoiLz4KPC9zdmc+Cg==); } .tabs-item, .toolbar-item{ cursor: pointer; padding: 0 10px; font-size: 12px; border-top: 2px solid #f3f3f3; } .tabs-item.active{ color: #0060df; border-top: 2px solid #0060df !important; background: #e9e9e9; } .tabs-item:hover{ background: #e9e9e9; border-top: 2px solid #c3c3c6; } .toolbar-item:hover{ background: #e9e9e9; border-top: 2px solid #e9e9e9; } /** 工具栏样式 END **/ /** JSON 格式化样式 START **/ ul.json-object, ul.json-array { list-style-type: none; margin: 0 0 0 2px; border-left: 1px dotted #5D6D7E; padding-left: 24px; } .json-brackets { font-weight: 700; } .json-key { /* color: #A31515;*/ color: #910F93; cursor: pointer; } .json-string, .json-string a{ /* color: #0b7500;*/ color: #4B8A4C; } .json-number{ /* color: #164FF0;*/ color: #1a01cc; font-weight: 600; } .json-boolean{ 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: 12px; padding: 0 1em; text-decoration: none; } a.json-placeholder:hover { text-decoration: underline; } /** JSON 格式化样式 END **/ /** 脑图样式 START **/ #jmContainer{ width: 100vw; height: calc(100vh - 57px); /* background:#F7F7F7 */ } 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; } /** 脑图样式 END **/ .layui-layer-tips{ width: auto !important; } .mind-array{ opacity: 0.5; font-size: 12px; padding-left: 5px; } /** 容器样式 START **/ .tabs-container{ overflow: auto; line-height: 1.5; font-family: monospace; } .tabs-container > div{ display: none; } .tabs-container > div.active{ display: block; } .tabs-container #formater{ padding: 10px; } .tabs-container #rawText{ padding: 0 10px; } .tabs-container #rawText pre{ display: block !important; } /** 容器样式 END **/ table.treetable{ border: none; } .treetable tbody tr td { line-height: 16px; } table.treetable .indenter a { width: 20px; display: inline-block; text-decoration: none; } table.treetable tr:hover{ background: #f0f9fe; } table.treetable tr.selected td, table.treetable tr.selected td a{ color: #fff !important; background-color: #3875d7 !important; } table.treetable tbody tr td:first-child{ width: 100px; } table.treetable tr.branch{ background: none; } table.treetable span.json-brackets{ padding: 0; } `) source.hide() // 将内容用eval函数处理下 const jsonObject = eval('(' + rawText + ')'); $("body").append(`
JSON格式化
JSON脑图
原始数据
保存
复制
全部折叠
全部展开
`) let btnEvent = { isFormater: false, $rawText: $('#rawText'), /** * 保存为文件 */ download: { download: function(content, filename) { const link = document.createElement("a") link.href = content link.download = filename link.click() }, saveJSON: function (text) { // 创建一个 Blob 对象,包含要下载的文本内容 const blob = new Blob([text], { type: "text/plain;charset=utf-8" }); const url = URL.createObjectURL(blob) let filename = new Date().getTime() + '.json'; this.download(url, filename) URL.revokeObjectURL(url); }, savePNG: () => jm.shoot(), }, saveJson:function(){ if($('#jmContainer').is(':visible')){ this.download.savePNG() }else{ this.download.saveJSON(this.$rawText.text()) } }, // 复制JSON文本内容 copyJson: function(){ GM_setClipboard(this.$rawText.text()) layer.msg('复制成功', {time: 1500}) }, // 全部折叠 collapseAll: function(){ if($('#formater').is(':visible')){ try{ $('.json-toggle').not('.collapsed').click() }catch(e){} }else{ jm.collapse_all() } }, // 全部展开 expandAll: function(){ if($('#formater').is(':visible')){ try{ $('a.json-placeholder').click().remove() }catch(e){} }else{ jm.expand_all() jm.scroll_node_to_center(jm.get_root()) } }, formaterJSON: function(){}, // 显示JSON脑图 showMind: function(){}, // 查看原始JSON内容 switchRawText: function(){ this.$rawText.html(source.clone()) }, // 美化 formaterRawText: function(){ this.isFormater = !this.isFormater if(this.isFormater){ this.$rawText.find('pre').text(JSON.stringify(jsonObject, null, 2)) }else{ this.switchRawText() } }, init: function(){ this.switchRawText() // 按钮点击事件 $('.btn').click(e => { const target = e.target, id = target.id if(target.classList.contains('tabs-item')){ let index = $(target).index() $(target).addClass('active').siblings().removeClass("active") $('.tabs-container > div').removeClass("active").eq(index).addClass('active') let rEl = $('#formaterRawText'), fEl= $('.searchbox'), cEl= $('#copyJson'), aEl = $('#collapseAll, #expandAll') id === 'formaterJSON' ? fEl.show(): fEl.hide() id === 'showMind' ? cEl.hide(): cEl.show() id === 'switchRawText' ? (rEl.show() && aEl.hide()) : (rEl.hide() && aEl.show()) } this[id](target) }) return this } }, jsonMind = { // JSON数据转换为jsMind所需要的数据结构 convert: function(json){ let children = [] if(typeof json === 'object'){ for(let key in json){ let val = json[key], isArray = Array.isArray(val) children.push({ isArray, chain: key, id: key + '_' + Math.random(), topic: isArray ? `${key}[${val.length}]` : `${key}`, // children: this.convert(val) children: isArray ? this.convert(val[0]) : this.convert(val) }) } } return children; }, // 脑图节点调用链 mindChain: function (node){ let chain = node.data.chain if(!node.parent){ return chain } let parent = node.parent, parentChain = this.mindChain(parent) chain = parent.data.isArray ? `${parentChain}[0].${chain}` : `${parentChain}.${chain}` return chain }, // 显示脑图 show: function(json, isArr){ jm.show({ "meta":{ "name":"JSON脑图", "author":"1220301855@qq.com", "version":"1.0" }, "format":"node_tree", /* 数据内容 */ "data": { "id": "root", "topic": 'Response', "direction": "left", "children": this.convert(json), "chain": isArr ? 'Response[0]' : 'Response' } }) setTimeout(() => jm.scroll_node_to_center(jm.get_root()), 300) return this }, // 脑图节点事件 event:function(){ $("jmnode").on('dblclick mouseover mouseout', function(event){ let that = $(this), node = jm.get_node(that.attr('nodeid')) if(!node.parent){ return } switch(event.type){ case 'dblclick': GM_setClipboard(jsonMind.mindChain(node)) layer.msg('节点路径复制成功', {time: 1500}) break; case 'mouseover': let s = `节点路径(双击复制)
${jsonMind.mindChain(node)}` layer.tips(s, that, { time: 0, tips: [2, '#1e2732'] }); break; default: layer.closeAll() break; } }) return this }, init: function(json){ let isArr = Array.isArray(json); if(isArr){ if(typeof json[0] !== 'object'){ layer.msg('数据结构无法生成脑图', {time: 1000}) return } json = json[0] } if(!window.jm){ window.jm = new jsMind({ mode :'side', editable: false, container:'jmContainer', view: { hmargin: 50, // 思维导图距容器外框的最小水平距离 vmargin: 50, // 思维导图距容器外框的最小垂直距离 engine: 'svg', // 思维导图各节点之间线条的绘制引擎 draggable: true, // 当容器不能完全容纳思维导图时,是否允许拖动画布代替鼠标滚动 support_html : false, line_color: '#C4C9D0', }, layout: { vspace: 7, // 节点之间的垂直间距 hspace: 150, // 节点之间的水平空间 }, }); } this.show(json, isArr).event() } }, otherOperate = { // 过滤 JSON filterJSON: function(filter) { if(!filter){ $('li').removeClass('hidden') return } let chainSet= new Set() /** * JSON key * 假如 filter === i, querySelectorAll得到DOM节点 * 得到:['/feedList/0/images/0/user_id', '/feedList/0/images/0', '/feedList/0/images', '/feedList/0', '/feedList'] */ document.querySelectorAll('#formater *[json-path]').forEach(el => { let chain = $(el).attr('json-path') if(!chain){ return } let newChain = chain.substr(chain.lastIndexOf('.')) if(!newChain.toLowerCase().includes(filter.toLowerCase())){ return } chainSet.add(chain) while(chain = chain.substr(0, chain.lastIndexOf('.'))){ chainSet.add(chain) } }) /** * JSON value */ document.querySelectorAll("#formater *[class*='json-']:not([class*='json-key']):not([class*='json-brackets'])") .forEach(el =>{ let target = $(el), chain = target.parent().attr('json-path') if(!chain){ return } let text = target.text() if(!text.toLowerCase().includes(filter.toLowerCase())){ return } chainSet.add(chain) while(chain = chain.substr(0, chain.lastIndexOf('.'))){ chainSet.add(chain) } }) $('li').addClass('hidden') chainSet.forEach(chain => { $(`*[json-path="${chain}"]`).removeClass('hidden') }) }, // JSON 过滤 input: function(){ let that = this $('input').on('input', function(){ let val = $(this).val() val === '' ? $('.clear').attr('hidden', true) : $('.clear').attr('hidden', false) that.filterJSON(val) }) return that }, // 清空输入框内容 clear: function(){ let that = this $('.clear').click(function(){ that.filterJSON() $('input').val('') $(this).attr('hidden', true) }) return this }, // 返回顶部 scrollTop: function(){ $('.scroll-top').click(function(){ $('.tabs-container').animate({ scrollTop: '0' }, 1000); }) return this }, urlHover:function(){ // 所有a标签,看是否是图片,是图片生成预览图 $("a.json-string[href]").hover(function(){ var that = $(this), href = that.attr('href') if(Utils.isImg(href)){ layer.tips(``, that, { time: 0, anim: 5, maxWidth: 500, tips: [3, '#d9d9d9'] }); } }, () => layer.closeAll()) return this }, jsonKeyHover: function(){ $(".json-key").hover(function(){ var that = $(this), jsonPath = that.parent().attr('json-path') if(jsonPath){ layer.tips(jsonPath, that, { time: 0, anim: 5, maxWidth: 500, tips: [1, '#1e2732'] }); } }, () => layer.closeAll()) return this }, init:function(){ this.input().clear().scrollTop().urlHover().jsonKeyHover() } } $('#formater').jsonViewer(jsonObject, jsonpFun) btnEvent.init() otherOperate.init() jsonMind.init(jsonObject) })(_jQuery) })();