zoukankan      html  css  js  c++  java
  • jsonview的实现

    前端页面展示json,组件封装如下:

    先贴一下目录结构:

     

    // index.vue

      1 <template>
      2     <div v-if="visible" :class="['json-view-container',theme,`deep-${currentDeep}`]">
      3         <div
      4             :class="['json-view', length ? 'closeable' : '']"
      5             :style="{fontSize: fontSize + 'px',lineHeight: lineHeight + 'px'}"
      6         >
      7             <!--icon-style-square-->
      8             <span
      9                 v-if="length && iconStyle === 'square'" class="angle"
     10                 @click="toggleClose"
     11             >
     12                 <svg
     13                     v-if="innerclosed" :fill="iconColors[0]"
     14                     width="1em" height="1em"
     15                     viewBox="0 0 1792 1792"
     16                     style=" 1em; height: 1em; color: rgb(42, 161, 152); vertical-align: middle;"
     17                 >
     18                     <path
     19                         d="M1344 800v64q0 14-9 23t-23 9h-352v352q0 14-9 23t-23 9h-64q-14
     20                     0-23-9t-9-23v-352h-352q-14 0-23-9t-9-23v-64q0-14 9-23t23-9h352v-352q0-14
     21                     9-23t23-9h64q14 0 23 9t9 23v352h352q14 0 23 9t9 23zm128
     22                     448v-832q0-66-47-113t-113-47h-832q-66 0-113 47t-47 113v832q0 66 47
     23                     113t113 47h832q66 0 113-47t47-113zm128-832v832q0 119-84.5 203.5t-203.5
     24                     84.5h-832q-119 0-203.5-84.5t-84.5-203.5v-832q0-119 84.5-203.5t203.5-84.5h832q119
     25                     0 203.5 84.5t84.5 203.5z"
     26                     />
     27                 </svg>
     28                 <svg
     29                     v-if="!innerclosed" :fill="iconColors[1]"
     30                     width="1em" height="1em"
     31                     viewBox="0 0 1792 1792"
     32                     style=" 1em; height: 1em; color: rgb(88, 110, 117); vertical-align: middle;"
     33                 >
     34                     <path
     35                         d="M1344 800v64q0 14-9 23t-23 9h-832q-14 0-23-9t-9-23v-64q0-14 9-23t23-9h832q14
     36                     0 23 9t9 23zm128 448v-832q0-66-47-113t-113-47h-832q-66 0-113 47t-47 113v832q0 66 47
     37                      113t113 47h832q66 0 113-47t47-113zm128-832v832q0 119-84.5 203.5t-203.5 84.5h-832q-119
     38                      0-203.5-84.5t-84.5-203.5v-832q0-119 84.5-203.5t203.5-84.5h832q119 0 203.5 84.5t84.5 203.5z"
     39                     />
     40                 </svg>
     41             </span>
     42             <!--icon-style-circle-->
     43             <span
     44                 v-if="length && iconStyle === 'circle'" class="angle"
     45                 @click="toggleClose"
     46             >
     47                 <svg
     48                     v-if="!innerclosed" viewBox="0 0 24 24"
     49                     :fill="iconColors[0]" preserveAspectRatio="xMidYMid meet"
     50                     style="  1em; height: 1em; color: rgb(1, 160, 228); vertical-align: middle;"
     51                 >
     52                     <path
     53                         d="M12,20C7.59,20 4,16.41 4,12C4,7.59 7.59,4 12,4C16.41,4 20,7.59 20,12C20,16.41 16.41,
     54                     20 12,20M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2M7,13H17V11H7"
     55                     />
     56                 </svg>
     57                 <svg
     58                     v-if="innerclosed" viewBox="0 0 24 24"
     59                     :fill="iconColors[1]" preserveAspectRatio="xMidYMid meet"
     60                     style="  1em; height: 1em; color: rgb(161, 106, 148); vertical-align: middle;"
     61                 >
     62                     <path
     63                         d="M12,20C7.59,20 4,16.41 4,12C4,7.59 7.59,4 12,4C16.41,4 20,7.59 20,12C20,
     64                         16.41 16.41,20 12,20M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,
     65                         12A10,10 0 0,0 12,2M13,7H11V11H7V13H11V17H13V13H17V11H13V7Z"
     66                     />
     67                 </svg>
     68             </span>
     69             <!--icon-style-triangle-->
     70             <span
     71                 v-if="length && iconStyle === 'triangle'" class="angle"
     72                 @click="toggleClose"
     73             >
     74                 <svg
     75                     v-if="!innerclosed"
     76                     viewBox="0 0 15 15"
     77                     :fill="iconColors[0]"
     78                     style="  1em; height: 1em; padding-left: 2px; color: #3c4047; vertical-align: top;"
     79                 >
     80                     <path d="M0 5l6 6 6-6z"/>
     81                 </svg>
     82                 <svg
     83                     v-if="innerclosed" viewBox="0 0 15 15"
     84                     :fill="iconColors[1]"
     85                     style=" 1em; height: 1em; padding-left: 2px; color: #3c4047; vertical-align: top;"
     86                 >
     87                     <path d="M0 14l6-6-6-6z"/>
     88                 </svg>
     89             </span>
     90             <div class="content-wrap">
     91                 <p :class="['first-line',length > 0 ? 'pointer' : '']" @click="toggleClose">
     92                     <span v-if="jsonKey" class="json-key">"{{ jsonKey }}": </span>
     93                     <span v-if="length">{{ prefix }}{{ innerclosed ? ('...' + subfix) : '' }}
     94                         <span class="json-note">{{ innerclosed ? (length + ' items') : '' }}</span>
     95                     </span>
     96                     <span v-if="!length">{{ `${isArray ? '[]' : '{}'}${isLast ? '' : ','}` }}</span>
     97                 </p>
     98                 <div v-if="!innerclosed && length" class="json-body">
     99                     <template v-for="(item, index) in items">
    100                         <json-view
    101                             v-if="item.isJSON"
    102                             :key="index"
    103                             :closed="isClose()"
    104                             :data="item.value"
    105                             :json-key="item.key"
    106                             :current-deep="templateDeep + 1"
    107                             :deep="deep"
    108                             :icon-style="iconStyle"
    109                             :theme="theme"
    110                             :font-size="fontSize"
    111                             :line-height="lineHeight"
    112                             :icon-color="iconColors"
    113                             :is-last="index === items.length - 1"
    114                             :has-siblings="item.hasSiblings"
    115                         />
    116                         <p
    117                             v-else :key="index"
    118                             class="json-item"
    119                         >
    120                             <span class="json-key">
    121                                 {{ (isArray ? '' : '"' + item.key + '":') }}
    122                             </span>
    123                             <span :class="['json-value',getDataType(item.value)]">
    124                                 {{
    125                                     `${
    126                                         getDataType(item.value) === 'string' ? '"' : ''
    127                                     }${
    128                                         formatValue(item.value)}${getDataType(item.value) === 'string' ? '"' : ''
    129                                     }
    130                                     ${index === items.length - 1 ? '' : ','}`
    131                                 }}
    132                             </span>
    133                         </p>
    134                     </template>
    135                     <span v-if="!innerclosed" class="base-line"></span>
    136                 </div>
    137                 <p v-if="!innerclosed " class="last-line">
    138                     <span>{{ subfix }}</span>
    139                 </p>
    140             </div>
    141         </div>
    142 
    143     </div>
    144 </template>
    145 <script src="./json-view.js"></script>
    146 <style lang="less" scoped>
    147 @import "./style/index";
    148 </style>
    View Code

    // json-view.js

      1 export default {
      2     name: 'json-view',
      3     props: {
      4         data: { // 传入的json数据
      5             type: [Object, Array],
      6             required: true
      7         },
      8         jsonKey: { // json的key值,用于第二层及二层以上的组件的key值
      9             type: String,
     10             default: ''
     11         },
     12         closed: { // 是否折叠
     13             type: Boolean,
     14             default: false
     15         },
     16         isLast: { // 是否是最后一行
     17             type: Boolean,
     18             default: true
     19         },
     20         fontSize: { // 字体大小
     21             type: Number,
     22             default: 14
     23         },
     24         lineHeight: { // 行高
     25             type: Number,
     26             default: 24
     27         },
     28         deep: { // 展开深度
     29             type: Number,
     30             default: 3
     31         },
     32         currentDeep: { // 当前为递归的第几层
     33             type: Number,
     34             default: 1
     35         },
     36         iconStyle: { // 折叠icon样式
     37             type: String,
     38             default: 'square'
     39         },
     40         iconColor: { // icon颜色
     41             type: Array,
     42             default() {
     43                 return [];
     44             }
     45         },
     46         theme: { // 主题
     47             type: String,
     48             default: ''
     49         },
     50         hasSiblings: { // 是否有兄弟节点
     51             type: Boolean,
     52             default: true
     53         }
     54     },
     55     data() {
     56         return {
     57             innerclosed: this.closed,
     58             templateDeep: this.currentDeep,
     59             visible: false
     60         };
     61     },
     62     computed: {
     63         isArray() {
     64             return this.getDataType(this.data) === 'array';
     65         },
     66         length() {
     67             return this.isArray ? this.data.length : Object.keys(this.data).length;
     68         },
     69         subfix() {
     70             const data = this.data;
     71             if (this.isEmptyArrayOrObject(data)) { // 如果是空数组或空对象
     72                 return '';
     73             } else {
     74                 return (this.isArray ? ']' : '}') + (this.isLast ? '' : ',');
     75             }
     76         },
     77         prefix() {
     78             return this.isArray ? '[' : '{';
     79         },
     80         items() {
     81             const json = this.data;
     82 
     83             if (this.isArray) {
     84                 return json.map(item => {
     85                     const isJSON = this.isObjectOrArray(item);
     86                     return {
     87                         value: item,
     88                         isJSON,
     89                         key: ''
     90                     };
     91                 });
     92             }
     93             return Object.keys(json).map(key => {
     94                 const item = json[key];
     95                 const isJSON = this.isObjectOrArray(item);
     96                 return {
     97                     value: item,
     98                     isJSON,
     99                     key
    100                 };
    101             });
    102         },
    103         iconColors() {
    104             const {theme, iconColor} = this;
    105             if (iconColor.length === 2) {
    106                 return iconColor;
    107             } else if (theme === 'one-dark') {
    108                 return ['#747983', '#747983'];
    109             } else if (theme === 'vs-code') {
    110                 return ['#c6c6c6', '#c6c6c6'];
    111             } else {
    112                 return ['#747983', '#747983'];
    113             }
    114         }
    115     },
    116     mounted() {
    117         setTimeout(() => {
    118             this.visible = true;
    119         }, 0);
    120     },
    121     methods: {
    122         formatValue(data) {
    123             if (data && data.isBigNumber) {
    124                 return data.toString(10);
    125             }
    126             return data;
    127         },
    128         getDataType(data) {
    129             return data && data.isBigNumber
    130                 ? 'number'
    131                 : Object.prototype.toString.call(data).slice(8, -1).toLowerCase();
    132         },
    133         isObjectOrArray(source) {
    134             return ['array', 'object'].includes(this.getDataType(source));
    135         },
    136         toggleClose() {
    137             if (this.length === 0) {
    138                 return;
    139             }
    140             if (this.innerclosed) {
    141                 this.innerclosed = false;
    142             } else {
    143                 this.innerclosed = true;
    144             }
    145         },
    146         isClose() {
    147             return this.templateDeep + 1 > this.deep;
    148         },
    149         isEmptyArrayOrObject(data) { // 空数组或者空对象
    150             return [
    151                 {},
    152                 []
    153             ].map(item => JSON.stringify(item)).includes(JSON.stringify(data));
    154         }
    155     },
    156     watch: {
    157         closed() {
    158             this.innerclosed = this.closed;
    159         }
    160     }
    161 };
    View Code

    style下的文件:

    // index.less

      1 // default
      2 @import "./on-dark";
      3 @import "./vs-code";
      4 
      5 .json-view-container {
      6     background-color: #fff;
      7 
      8     &.deep-1 {
      9         // overflow: auto;
     10         padding-right: 10px;
     11     }
     12 
     13     .json-view {
     14         position: relative;
     15         box-sizing: border-box;
     16         display: block;
     17         width: 100%;
     18         height: 100%;
     19         padding-left: 2rem;
     20         font-family: Consolas !important;
     21         white-space: nowrap;
     22         cursor: default;
     23 
     24         .json-note {
     25             font-size: 12px;
     26             font-style: italic;
     27             color: #909399;
     28         }
     29 
     30         .json-key {
     31             color: #8c6325;
     32         }
     33 
     34         .json-value {
     35             display: inline-block;
     36             color: #57b73b;
     37             word-break: break-all;
     38             white-space: normal;
     39 
     40             &.number {
     41                 color: #2d8cf0;
     42             }
     43 
     44             &.string {
     45                 color: #57b73b;
     46             }
     47 
     48             &.boolean {
     49                 color: #eb3324;
     50             }
     51 
     52             &.null {
     53                 color: #eb3324;
     54             }
     55         }
     56 
     57         .json-item {
     58             display: flex;
     59             padding-left: 2rem;
     60             margin: 0;
     61         }
     62 
     63         .first-line {
     64             padding: 0;
     65             margin: 0;
     66 
     67             &.pointer {
     68                 cursor: pointer !important;
     69             }
     70         }
     71 
     72         .json-body {
     73             position: relative;
     74             padding: 0;
     75             margin: 0;
     76 
     77             .base-line {
     78                 position: absolute;
     79                 top: 0;
     80                 left: 2px;
     81                 height: 100%;
     82                 border-left: 1px dashed #bbb;
     83             }
     84         }
     85 
     86         .last-line {
     87             padding: 0;
     88             margin: 0;
     89         }
     90 
     91         .angle {
     92             position: absolute;
     93 
     94             /* left: ~"calc(2rem - 18px)"; */
     95             left: 12px;
     96             display: block;
     97             // eslint-disable-next-line
     98             //float: left; // eslint-disable-line
     99             width: 20px;
    100             text-align: center;
    101             cursor: pointer;
    102         }
    103     }
    104 }
    View Code

    // on-dark.less

     1 // dark
     2 .json-view-container {
     3     &.one-dark {
     4         background-color: #292c33;
     5 
     6         .json-view {
     7             font-family: Menlo, Consolas, "Courier New", Courier, FreeMono, monospace !important;
     8 
     9             .json-note {
    10                 font-size: 12px;
    11                 font-style: italic;
    12                 color: #909399;
    13             }
    14 
    15             .json-key {
    16                 color: #d27277;
    17             }
    18 
    19             .json-value {
    20                 color: #c6937c;
    21 
    22                 &.number {
    23                     color: #bacdab;
    24                 }
    25 
    26                 &.string {
    27                     color: #c6937c;
    28                 }
    29 
    30                 &.boolean {
    31                     color: #659bd1;
    32                 }
    33 
    34                 &.null {
    35                     color: #659bd1;
    36                 }
    37             }
    38 
    39             .first-line {
    40                 color: #acb2be;
    41             }
    42 
    43             .json-body {
    44                 .base-line {
    45                     border-left: 1px solid #3c4047;
    46                 }
    47             }
    48 
    49             .last-line {
    50                 color: #acb2be;
    51             }
    52 
    53             .json-item {
    54                 color: #acb2be;
    55             }
    56         }
    57     }
    58 }
    View Code

    // vs.code.less

     1 // vs-code
     2 .json-view-container {
     3     &.vs-code {
     4         background-color: #1e1e1e;
     5 
     6         .json-view {
     7             font-family: Menlo, Consolas, "Courier New", Courier, FreeMono, monospace !important;
     8 
     9             .json-note {
    10                 font-size: 12px;
    11                 font-style: italic;
    12                 color: #909399;
    13             }
    14 
    15             .json-key {
    16                 color: #a9dbfb;
    17             }
    18 
    19             .json-value {
    20                 color: #c6937c;
    21             }
    22 
    23             .first-line {
    24                 color: #d4d4d4;
    25             }
    26 
    27             .json-body {
    28                 .base-line {
    29                     border-left: 1px solid #404040;
    30                 }
    31             }
    32 
    33             .last-line {
    34                 color: #d4d4d4;
    35             }
    36 
    37             .json-item {
    38                 color: #d4d4d4;
    39             }
    40         }
    41     }
    42 }
    View Code

    使用示例:

     1 <json-view
     2                 :data="json"
     3                 :theme="theme"
     4                 :deep="deep"
     5                 :icon-style="iconStyle"
     6                 :font-size="fontSize"
     7                 :line-height="lineHeight"
     8                 :closed="closed"
     9                 :icon-color="iconColor"
    10             />

    效果展示:

    参数:

  • 相关阅读:
    Bulk insert的用法
    跨服务器与连接不同数据库 不跨服务器连接库存表
    读书笔记(1)
    CSS渲染HTML时的优先级问题
    如何使用as3获得一组不重复的随机数
    flash cs5导出swc到flash builder 4
    转:AS3.0的Dictionary类简介
    转:As3.0中的反射
    Flex 4里的fx、mx以及s命名空间
    yahoo的flash组件
  • 原文地址:https://www.cnblogs.com/huangxingquan/p/15703177.html
Copyright © 2011-2022 走看看