您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
格式化显示JSON使数据看起来更加漂亮,支持折叠/展开格式化后的数据,支持JSON脑图让调用层级看着更清晰,支持复制JSON脑图节点路径
当前为
- // ==UserScript==
- // @license MIT
- // @name JSON Viewer
- // @namespace http://tampermonkey.net/
- // @version 0.5.4
- // @note v0.5.4 单击复制修改为CTRL+单击复制JSONPath功能,JSON格式化风格增加table格式
- // @note v0.5.3 增加暗黑主题色
- // @note v0.5.2 单击JSON格式化的key可复制JSONPath
- // @note v0.5.1 修复JSONPath提示有误
- // @note v0.5.0 解决chrome 120+以上内核JSON格式化不执行和引入layer报错问题
- // @note v0.4.9 布局修改,增加保存JSON/脑图为文件,增加JSON过滤,鼠标移入key提示JSONPath
- // @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/dom-to-image@2.6.0/dist/dom-to-image.min.js
- // @require https://unpkg.com/jsmind@0.8.5/es6/jsmind.screenshot.js
- // @require https://cdn.jsdelivr.net/npm/@kanety/jquery-simple-tree-table@0.5.1/dist/jquery-simple-tree-table.min.js
- // @resource swalStyle https://unpkg.com/jsmind@0.8.5/style/jsmind.css
- // ==/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 += `<span class="json-brackets ${type == 'array' ? 'json-square-brackets' : 'json-curly-brackets'}">`;
- html += type === 'array' ? '[</span><ol class="json-array">' : '{</span><ul class="json-object">';
- for (var key in json) {
- if (json.hasOwnProperty(key)) {
- let comma = --len > 0 ? ',' : '',
- jsonPath = parentPath + '.' + key,
- collapse = isCollapsable(json[key]) ? '<a href class="json-toggle"></a>' : '',
- res = json2html(json[key], jsonPath)
- let toHtml = type === 'array' ? res : `<span class="json-key">"${key}"</span>: ${res}`
- html += [`<li json-path="${jsonPath}">`, collapse, toHtml, comma, '</li>'].join('')
- }
- }
- if(type === 'array'){
- html += `</ol><span class="json-brackets ${type == 'array' ? 'json-square-brackets' : 'json-curly-brackets'}">]</span>`
- }else{
- html += `</ul><span class="json-brackets ${type == 'array' ? 'json-square-brackets' : 'json-curly-brackets'}">}</span>`
- }
- }else{
- html += `<span class="json-brackets ${type == 'array' ? 'json-square-brackets' : 'json-curly-brackets'}">`
- html += (type === 'array') ? '[]' : '{}'
- html += '</span>'
- }
- break
- default:
- /* Escape tags */
- json = type === 'string' ? json.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>') : json
- if (Utils.isUrl(json)){
- html += `<a target="_blank" href="${json}" class="json-string">"${json}"</a>`;
- }else{
- json = type === 'string' ? `"${json}"` : json
- html += `<span class="json-${type}">${json}</span>`;
- }
- 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 = `<div>${jsonpFun}(</div>${html}<div>)</div>`
- }
- /* 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('<a href class="json-placeholder">' + placeholder + '</a>');
- }
- 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').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'))
- $("head").append(`<link rel="stylesheet" type="text/css" href="https://unpkg.com/layer-src@3.5.1/dist/theme/default/layer.css"/>`)
- .append('<script src="https://unpkg.com/layui@2.9.17/dist/layui.js" type="text/javascript" ></script>')
- 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;
- display: none;
- 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{
- z-index: 10;
- position: fixed;
- width: 100vw;
- 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;
- }
- .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{
- border-top: 2px solid #f3f3f3;
- }
- .tabs-item:hover{
- background: #e9e9e9;
- border-top: 2px solid #c3c3c6;
- }
- .tabs-item, .toolbar-item{
- cursor: pointer;
- padding: 0 10px;
- font-size: 12px;
- }
- .tabs-item.active{
- color: #0060df;
- border-top: 2px solid #0060df !important;
- background: #e9e9e9;
- }
- .tabs-item:hover, .toolbar-item:hover{
- background: #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-curly-brackets {
- color: #6D9331;
- }
- .json-square-brackets{
- color: #8E9331;
- }
- /** 暗黑主题 START **/
- body.dark{
- background: #333333;
- }
- .dark li, .dark pre{
- color: #CCC;
- }
- .dark .json-toggle {
- opacity: 0.35;
- }
- .dark .json-toggle:hover {
- opacity: 0.5;
- }
- .dark .json-curly-brackets {
- color: #CE70D6;
- }
- .dark .json-square-brackets{
- color: #F1D700;
- }
- .dark .json-key {
- color: #7CDCFE;
- }
- .dark .json-string, .dark .json-string a{
- color: #CE9178;
- }
- .dark .json-number{
- color: #B5CEA8;
- }
- .dark .json-boolean{
- color: #569CD6;
- }
- .dark .json-null {
- color: #2D7AD6;
- }
- .dark jmnode {
- color: #7CDCFE !important;
- }
- /** 暗黑主题 END **/
- /** 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;
- background: #dfdfdf;
- }
- .mind-array{
- opacity: 0.5;
- font-size: 12px;
- padding-left: 5px;
- }
- /** 脑图样式 END **/
- /** 容器样式 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 #formatContainer{
- padding: 10px;
- }
- .tabs-container #rawTextContainer{
- padding: 0 10px;
- }
- .tabs-container #rawTextContainer pre{
- display: block !important;
- overflow-wrap: break-word;
- white-space: pre-wrap;
- }
- /** 容器样式 END **/
- .layui-layer-tips{
- width: auto !important;
- }
- .tabs .selectbox{
- position: absolute;
- right: 200px;
- display: flex;
- }
- /** 表格 START **/
- table {
- margin-left: 20px;
- border-collapse: collapse;
- }
- table tr:hover{
- background: #f0f9fe;
- }
- .dark table tr:hover{
- background: #353B48
- }
- table tr.selected td, table tr.selected td a{
- color: #fff !important;
- background-color: #3875d7;
- }
- table tbody tr td:first-child{
- width: 120px;
- }
- .simple-tree-table-icon{
- color: #000;
- opacity: 0.2;
- width: 0 !important;
- margin: 0 !important;
- line-height: 0 !important;
- }
- .simple-tree-table-icon:hover {
- opacity: 0.35;
- }
- .simple-tree-table-icon:active {
- opacity: 0.5;
- }
- .simple-tree-table-icon:after{
- content: "" !important;
- }
- .simple-tree-table-icon:before {
- top: 0.5px;
- left: -15px;
- position: relative;
- content: "";
- width: 0;
- height: 0;
- display: none;
- border-style: solid;
- border-width: 5px 0 5px 8px;
- border-color: transparent transparent transparent currentColor;
- transform: rotate(90deg);
- }
- .simple-tree-table-opened .simple-tree-table-icon:before {
- display: block;
- }
- .simple-tree-table-closed .simple-tree-table-icon:before {
- display: block;
- transform: rotate(0deg);
- }
- .dark .simple-tree-table-icon{
- color: #FFF;
- opacity: 0.5;
- }
- /** 表格 END **/
- `)
- source.hide()
- // 将内容用eval函数处理下
- const jsonObject = eval(`(${rawText})`);
- $("body").addClass('dark').append(`
- <div class="scroll-top"></div>
- <div class="flex-container">
- <div class="panel">
- <div class="tabs">
- <div class="tabs-item btn active" id="format">JSON格式化</div>
- <div class="tabs-item btn" id="viewJsonMind">JSON脑图</div>
- <div class="tabs-item btn" id="viewRawText">原始数据</div>
- <div class="selectbox">
- <div class="formatStyle">
- <label>风格:</label>
- <select>
- <option value="default">默认</option>
- <option value="treaTable">表格</option>
- </select>
- </div>
- <div class="theme" style="margin-left: 10px">
- <label>主题: </label>
- <select>
- <option value="default">默认</option>
- <option value="dark">暗黑</option>
- </select>
- </div>
- </div>
- </div>
- <div class="toolbar">
- <div class="toolbar-item btn" id="saveJson">保存</div>
- <div class="toolbar-item btn" id="copyJson">复制</div>
- <div class="toolbar-item btn" id="collapseAll">全部折叠</div>
- <div class="toolbar-item btn" id="expandAll">全部展开</div>
- <div class="toolbar-item btn" id="beautify" style="display: none">美化输出</div>
- <div class="searchbox">
- <input type="text" placeholder="过滤 JSON "/>
- <button class="clear" hidden></button>
- </div>
- </div>
- </div>
- <div class="tabs-container">
- <div class="active" id="formatContainer"></div>
- <div id="jmContainer"></div>
- <div id="rawTextContainer"><pre></pre></div>
- </div>
- </div>`)
- let btnEvent = {
- isFormater: false,
- $rawText: $('#rawTextContainer'),
- /**
- * 保存为文件
- */
- 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($('#formatContainer').is(':visible')){
- try{
- $('.json-toggle').not('.collapsed').click()
- }catch(e){}
- }else{
- jm.collapse_all()
- }
- },
- // 全部展开
- expandAll: function(){
- if($('#formatContainer').is(':visible')){
- try{
- $('a.json-placeholder').click().remove()
- }catch(e){}
- }else{
- jm.expand_all()
- jm.scroll_node_to_center(jm.get_root())
- }
- },
- format: function(){},
- // 显示JSON脑图
- viewJsonMind: function(){},
- // 查看原始JSON内容
- viewRawText: function(){
- this.$rawText.html(source.clone())
- },
- // 美化
- beautify: function(){
- this.isFormater = !this.isFormater
- if(this.isFormater){
- this.$rawText.find('pre').text(JSON.stringify(jsonObject, null, 2))
- }else{
- this.viewRawText()
- }
- },
- init: function(){
- this.viewRawText()
- // 按钮点击事件
- $('.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 beautifyEl = $('#beautify'),
- searchEl= $('.searchbox'),
- copyJsonEl= $('#copyJson'),
- aEl = $('#collapseAll, #expandAll')
- id === 'format' ? searchEl.show(): searchEl.hide()
- id === 'viewJsonMind' ? copyJsonEl.hide(): copyJsonEl.show()
- id === 'viewRawText' ? (beautifyEl.show() && aEl.hide()) : (beautifyEl.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}<span class="mind-array">[${val.length}]</span>` : `${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 = `<b>节点路径(双击复制)</b><br/>${jsonMind.mindChain(node)}`
- layer.tips(s, that, {
- time: 0,
- tips: [2, '#2e59a7']
- });
- break;
- default:
- layer.closeAll()
- break;
- }
- })
- return this
- },
- collapseOrExpand: function(){
- $("jmnode").on('click', function(){
- let node = jm.get_node($(this).attr('nodeid'))
- jm.toggle_node(node)
- })
- 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().collapseOrExpand()
- }
- },
- otherOperate = {
- // 过滤 JSON
- filterJSON: function(filter) {
- let style = GM_getValue('formatStyle') || 'default'
- if(!filter){
- style == 'default' ? $('#formatContainer li').removeClass('hidden') : $('.json-key').parent().removeClass('hidden')
- return
- }
- let chainSet= new Set()
- /**
- * 模糊匹配 JSON key
- * 假如`filter`值为`id`, querySelectorAll得到DOM节点
- * 得到:['.feedList.0.images.0.user_id', '.feedList.0.images.0', '.feedList.0.images', '.feedList.0', '.feedList']
- */
- document.querySelectorAll('#formatContainer *[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("#formatContainer *[class*='json-']:not([class*='json-key']):not([class*='json-brackets'])")
- .forEach(el =>{
- let target = $(el),
- chain = style == 'default' ? target.parent().attr('json-path') : target.siblings('.json-key').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)
- }
- })
- console.log(chainSet)
- style == 'default' ? $('#formatContainer li').addClass('hidden') : $('.json-key').parent().addClass('hidden')
- chainSet.forEach(chain => {
- style == 'default' ? $(`#formatContainer *[json-path="${chain}"]`).removeClass('hidden')
- : $(`#formatContainer *[json-path="${chain}"]`).parent().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);
- })
- $('.tabs-container').scroll(function(e) {
- let scrollTop = $(this).scrollTop()
- scrollTop > 500 ? $('.scroll-top').fadeIn() : $('.scroll-top').fadeOut()
- });
- return this
- },
- // 所有a标签,看是否是图片,是图片生成预览图
- urlHover:function(){
- $("#formatContainer").on({
- mouseenter: function(){
- var that = $(this),
- href = that.attr('href')
- if(Utils.isImg(href)){
- layer.tips(`<img src="${href}" />`, that, {
- time: 0,
- anim: 5,
- maxWidth: 500,
- tips: [3, '#d9d9d9']
- });
- }
- },
- mouseleave: () => layer.closeAll()
- }, 'a[href]')
- return this
- },
- // 提示key的JSONPath
- tipsJsonPath: function(){
- var that = this
- $("#formatContainer").on({
- mouseenter: function(){
- let jsonPath = that.getJsonPath(this)
- layer.tips(jsonPath, this, {
- time: 0,
- anim: 5,
- maxWidth: 500,
- tips: [1, '#2e59a7']
- })
- },
- mouseleave: () => layer.closeAll()
- }, '.json-key')
- return this
- },
- // 单击key复制JSONPath
- copyJsonPath: function(){
- var that = this
- $("#formatContainer").on('click', '.json-key', function(event){
- if(event.ctrlKey){
- let jsonPath = that.getJsonPath(this)
- GM_setClipboard(jsonPath)
- layer.msg('复制成功', {time: 1500})
- }
- })
- return this
- },
- getJsonPath: function(element){
- let style = GM_getValue('formatStyle') || 'default'
- let jsonPath = style == 'default' ? $(element).parent().attr('json-path') : $(element).attr('json-path')
- return jsonPath.split('.').reduce((prev, next) => /^\d+$/.test(next) ? prev + `[${next}]` : prev + '.' + next)
- },
- init:function(){
- this.input().clear().scrollTop().urlHover().tipsJsonPath().copyJsonPath()
- }
- },
- theme = {
- // 切换主题
- changeTheme: function(){
- let that = this
- $('.theme select').change(function(e){
- let val = $(e.target).val()
- GM_setValue('theme', val)
- that.setTheme()
- })
- return this
- },
- // 设置主题
- setTheme: function(){
- let theme = GM_getValue('theme') || 'default'
- $('body').removeClass().addClass(theme)
- $('.theme select').val(theme)
- return this
- },
- init:function(){
- this.setTheme().changeTheme()
- }
- },
- formatStyle = {
- // 切换风格
- changeStyle: function(json){
- let that = this
- $('.formatStyle select').change(function(e){
- let val = $(e.target).val()
- GM_setValue('formatStyle', val)
- that.setStyle(json)
- })
- return this
- },
- // 设置风格
- setStyle: function(json){
- let style = GM_getValue('formatStyle') || 'default'
- $('.formatStyle select').val(style)
- $('input').val('')
- $('#formatContainer').html('')
- if(style === 'default'){
- $('#formatContainer').jsonViewer(json, jsonpFun)
- }else{
- let trHtml= treeTableHtml(json)
- $('#formatContainer').append(`<table id="treeTable">${trHtml}</table>`)
- $('#treeTable').simpleTreeTable({
- expander: '#expandAll',
- collapser: '#collapseAll',
- })
- // Highlight selected row
- $('#treeTable').on("mousedown", "tr", function() {
- $(".selected").not(this).removeClass("selected");
- $(this).toggleClass("selected")
- })
- }
- return this
- },
- init:function(json){
- this.setStyle(json).changeStyle(json)
- theme.init()
- btnEvent.init()
- otherOperate.init()
- jsonMind.init(json)
- }
- }
- formatStyle.init(jsonObject)
- /**
- * 表格
- */
- function treeTableHtml(json, level = 0, pId = '', pChain = ''){
- let tr = ''
- for(let key in json){
- let val = json[key],
- type = Utils.getType(val),
- tId = key + '_' + Math.random(),
- chain = pChain + "." + key
- if(['array', 'object'].includes(type)){
- let brackets = '',
- len = val.length,
- res = treeTableHtml(val, level + 1, tId, chain)
- if(!res){
- if(type ==='array'){
- brackets = `<span class="json-brackets ${type == 'array' ? 'json-square-brackets' : 'json-curly-brackets'}">[]</span>`
- }else{
- brackets = `<span class="json-brackets ${type == 'array' ? 'json-square-brackets' : 'json-curly-brackets'}">{}</span>`
- }
- }
- tr += `
- <tr data-node-id="${tId}" data-node-pid="${pId}" type="${type}">
- <td colspan="${len > 0 ? 2 : 0}" class="json-key" json-path="${chain}" style="padding-left: ${ level * 19 }px">${key}:</td>
- <td>${brackets}</td>
- </tr>`
- tr += res
- }else{
- val = (type === 'string') ? val.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>') : val
- tr += `<tr data-node-id="${tId}" data-node-pid="${pId}" type="${type}">
- <td class="json-key" json-path="${chain}" style="padding-left: ${ level * 19 }px">${key}:</td>`
- if (Utils.isUrl(val)){
- tr += `<td class="json-${type}"><a target="_blank" href="${val}">"${val}"</a></td>`
- }else{
- val = (type === 'string') ? `"${val}"`: val
- tr += `<td class="json-${type}">${val}</td>`
- }
- tr += '</tr>'
- }
- }
- return tr;
- }
- })(_jQuery)
- })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址