json格式数据的树形展示,可展开收缩

603 阅读3分钟

使用JSONPretty组件库,

配置

属性说明类型默认值
data待美化的源数据,注意不是 JSON 字符串JSON 对象-
deep数据深度, 大于该深度的数据将不被展开numberInfinity
showLength是否在数据线闭合的时候展示长度booleanfalse
showLine是否显示缩紧标识线booleantrue
showDoubleQuotes是否展示key名的双引号booleantrue
highlightMouseoverNode是否在mouseover的时候高亮booleanfalse
v-model双向绑定选中的数据层级string, array-, []
path定义最顶层数据层级stringroot
pathChecked定义哪些数据层级是已被选中的array[]
pathSelectable定义哪些数据层级是可以被选中的,返回true或falseFunction(itemPath, itemData)-
selectableType定义组件支持的选中方式,默认无选中功能enum: -, multiple, single-
showSelectController是否展示选择控制器booleanfalse
selectOnClickNode是否在点击节点的时候触发v-model双向绑定booleantrue
highlightSelectedNode是否高亮已选项booleantrue
customValueFormatter可以进行值的自定义渲染Function(data, key, parent, defaultFormatted)-

Events

事件名说明回调参数
click点击某一个数据层级时触发的事件(path, data)
changev-model改变的事件(仅在选择模式下可用)(newVal, oldVal)

父子组件

    <div>
        <el-dialog title="配置缓存明细" :visible.sync="dialogShow" :before-close="close" width="700px">
            <div class="log-dialog">
                <div class="container">
                    <div class="item first"><span class="title">缓存键:</span>
                        <div @click="onSync"><span style="font-weight: 600;">{{ params.key }}</span><a href="#" style="color: #4598F0;">
                                [同步]</a></div>
                    </div>
                    <div class="item"><span class="title">缓存值:</span>
                        <jsonView :config="config" :width="503"></jsonView>   
                    </div>
                </div>
                <div class="bottom">
                    <button class="copy" @click="copy">复制</button>
                    <button class="back" @click="close">返回</button>
                </div>
            </div>
        </el-dialog>
        
    </div>
    
</template>

<script>
import jsonView from "./jsonView.vue"
export default {
    props: {
        // 弹窗是否开启
        value: {
            type: Boolean,
            default: () => false
        },
        configParams: {
            type: Object,
            default: () => {}
        },
    },
    data() {
        return {
            config:{},
            configData:{},
            dialogShow:false,
            params:{
                key:'',
                configPath: ''
            },
        }
    },
    created() {   
        
    },
    components: {
        jsonView,
    },
    methods: {
        //获取配置明细
        getConfigDetal() {
            console.log("配置明细:", this.params)
            this.$api.getConfigDetail(this.params).then(({data})=>{
                console.log('配置明细data',data)
                this.configData=data
                this.config=JSON.parse(data.config)
            }).catch(() => {
            })
        },
        //同步事件
        onSync() {
            console.log("同步:", this.params)
            this.$api.getConfigSync(this.params).then((data) => {
                console.log('同步数据data', data)
                if(data.success){
                    this.$message({
                            message: "同步成功!",
                            type: "success"
                        })
                    this.list=[]
                    this.getConfigDetal()
                }
            }).catch(() => {
            })
        },
        
        close() {
            this.dialogShow = false
            this.config={}
            this.$emit("on-cancel")
        },
        //复制
        copy() {
            navigator.clipboard.writeText(JSON.stringify(this.config));
            this.$message({
                message: '复制成功',
                type: 'success'
            });
        }
    },
    watch: {
        value: {
            handler(val) {
                this.dialogShow = val
            }
        },
        configParams: {
            handler(val){
                console.log(val)
                this.params.key = val.key
                this.params.configPath=val.configPath
                this.getConfigDetal()
            }
        }
    }

}
</script>

<style lang="less" scoped>
.log-dialog {
    .container {
        font-size: 14px;
        .item {
            display: flex;
            align-items: flex-start;
            gap: 16px;
            flex: 1 0 0;

            .title {
                width: 100px;
                display: inline-block;
                text-align: right;
            }
        }

        .first {
            margin-bottom: 24px;
        }
        .pre {
            
            display: block;
            position: relative;
            font-size: 12px;
            text-align: left;
            word-break: break-all;
            word-wrap: break-word;
            .json-dict {
                list-style-type: none;
                margin: 0 0 0 1px;
                border-left: 1px dotted #ccc;
                padding-left: 2em;

                li {
                    color: #333;
                    font-feature-settings: 'clig' off, 'liga' off;
                    font-family: Roboto Mono;
                    font-size: 12px;
                    font-style: normal;
                    font-weight: 400;
                    line-height: 16px;

                    .json-string {
                        color: #0B7500;
                    }
                }
            }

            .jiantou {
                position: absolute;
                width: 7px;
                height: 7px;
                left: 9px;
                top: 20px;
                cursor: pointer;
            }

            .pick-up {
                color: #999;
                padding: 0 10px;
            }
        }

    }

    .bottom {
        padding: 16px 0px;
        display: flex;
        justify-content: flex-end;
        align-items: center;
        gap: 10px;
        align-self: stretch;

        .copy {
            padding: 8px 16px;
            font-size: 13px;
            border-radius: 4px;
            border: 1px solid var(---nc8, #D7DEE3);
            background: #fff;
            color: black;
            cursor: pointer;

            &:hover {
                background-color: #f4f6fa;
                color: black;
            }

            &:active {
                background-color: #D7DEE3;
                color: black;
            }
        }

        .back {
            border: none;
            padding: 8px 16px;
            font-size: 13px;
            color: white;
            border-radius: 4px;
            background: var(---blue1-, #4598F0);
            cursor: pointer;

            &:hover {
                opacity: 0.8;
            }

            &:active {
                background: var(---blue1-, #418cdb);
            }
        }
    }
}</style>

子组件

  <div class="main">
        <div v-if="Object.keys(config).length===0">配置未同步</div> 
        <JSONPretty 
           v-else
          :data="config" 
          :deep="deep"
          :show-select-controller="true"
          :show-length="true"
          :showIcon="true"
          :virtual="true"
            ></JSONPretty>
    </div>
</template>

<script>
import JSONPretty from 'vue-json-pretty';
import 'vue-json-pretty/lib/styles.css';
export default {
    props:{
        config:{
            type: Object,
            default: ()=>{}
        },
    },
    data() {
        return {
            deep:2, //展开深度
        }
    },
    components: {
        JSONPretty
    },

}
</script >

<style lang="less" scoped>
.main{
        width: 503px;
        padding: 11px 11px 11px 11px;
        color: #333333;
        background-color: #eaeef0;
        border: 1px solid #cbd6d6;
        border-radius: 4px;
    }
/deep/.vjs-tree-node .vjs-indent-unit.has-line{
    border-left: 1px dotted #ccc;
}
/deep/.vjs-value-string{
    color: #0B7500;
}
/deep/.vjs-value-number,.vjs-value-boolean{
    color: blue;
}
/deep/.vjs-value-boolean{
    color: blue;
}
/deep/.vjs-tree-node.has-carets.has-selector, .vjs-tree-node.has-selector{
    padding-left: 12px;
}

</style>