mirror of
https://github.com/tenrok/vue-json-viewer.git
synced 2026-06-08 17:22:32 +03:00
Merge pull request #84 from mlanin-forks/feature/expand-all
Add ability to expand full branch
This commit is contained in:
+6
-1
@@ -146,4 +146,9 @@ public/bundle/*
|
||||
nbproject/*
|
||||
.DS_Store
|
||||
.devhost
|
||||
examples/dist/
|
||||
examples/dist/
|
||||
/vue-json-viewer.js
|
||||
/ssr.js
|
||||
/style.css
|
||||
yarn.lock
|
||||
package-lock.json
|
||||
-33
@@ -1,33 +0,0 @@
|
||||
language : node_js
|
||||
node_js:
|
||||
- "10"
|
||||
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
|
||||
install:
|
||||
- npm install
|
||||
|
||||
os:
|
||||
- linux
|
||||
|
||||
stages:
|
||||
- name: deploy
|
||||
|
||||
jobs:
|
||||
include:
|
||||
- stage: deploy
|
||||
script:
|
||||
- echo "NPM Deploying Started ..."
|
||||
- npm version
|
||||
- npm run build
|
||||
- echo "NPM Building Finished."
|
||||
|
||||
deploy:
|
||||
provider: npm
|
||||
email: chenfengjw@hotmail.com
|
||||
api_key: "$NPM_TOKEN"
|
||||
skip_cleanup: true
|
||||
on:
|
||||
all_branches: true
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
## 2.2.20 2021-10-31
|
||||
|
||||
- 给box加getPath方法 [pr](https://github.com/chenfengjw163/vue-json-viewer/pull/79)
|
||||
- chore: move "vue" to "peerDependencies" [pr](https://github.com/chenfengjw163/vue-json-viewer/pull/75)
|
||||
|
||||
|
||||
## 2.2.17 2020-12-29
|
||||
|
||||
- fix: issues [issues](https://github.com/chenfengjw163/vue-json-viewer/issues/64)
|
||||
- fix: issues [issues](https://github.com/chenfengjw163/vue-json-viewer/issues/65)
|
||||
- fix: issues [issues](https://github.com/chenfengjw163/vue-json-viewer/issues/66)
|
||||
|
||||
## 2.2.17 2020-12-29
|
||||
|
||||
- fix: long string expand arrow display error [pr](https://github.com/chenfengjw163/vue-json-viewer/pull/62)
|
||||
|
||||
## 2.2.16 2020-11-13
|
||||
|
||||
- support long string expand [issues](https://github.com/chenfengjw163/vue-json-viewer/issues/60)
|
||||
|
||||
## 2.2.15 2020-10-13
|
||||
|
||||
- Add Preview Mode
|
||||
|
||||
## 2.2.14 2020-07-27
|
||||
|
||||
- Allow add specific style for float and integer numbers [pr](https://github.com/chenfengjw163/vue-json-viewer/pull/51)
|
||||
|
||||
|
||||
## 2.2.13 2020-07-14
|
||||
|
||||
- Add timeformat props to support custom time format [pr](https://github.com/chenfengjw163/vue-json-viewer/pull/48)
|
||||
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2018 陈峰
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -1,24 +1,37 @@
|
||||
# vue-json-viewer
|
||||
|
||||
Simple JSON viewer component, for Vue.js 2
|
||||
[中文版](https://github.com/chenfengjw163/vue-json-viewer/blob/master/README_CN.md)
|
||||
|
||||
[](https://travis-ci.org/<chenfengjw163>/<vue-json-viewer>)
|
||||
Simple JSON viewer component, for Vue.js 2 or 3.
|
||||
|
||||
Support for incremental update components
|
||||
|
||||
[](https://travis-ci.org/chenfengjw163/vue-json-viewer)
|
||||
[](https://www.npmjs.com/package/vue-json-viewer)
|
||||

|
||||
|
||||
- [Installing](#installing)
|
||||
- [Example](#example)
|
||||
- [Options](#options)
|
||||
- [Listeners](#listeners)
|
||||
- [Slots](#slots)
|
||||
- [Theming](#theming)
|
||||
|
||||
## Installing
|
||||
Using npm:
|
||||
```
|
||||
$ npm install vue-json-viewer --save
|
||||
$ npm install vue-json-viewer@2 --save
|
||||
// Vue2
|
||||
$ npm install vue-json-viewer@3 --save
|
||||
// Vue3
|
||||
```
|
||||
|
||||
Using yarn:
|
||||
```
|
||||
$ yarn add vue-json-viewer
|
||||
$ yarn add vue-json-viewer@2
|
||||
// Vue2
|
||||
$ yarn add vue-json-viewer@3
|
||||
// Vue3
|
||||
```
|
||||
|
||||
## Example
|
||||
@@ -38,10 +51,13 @@ $ yarn add vue-json-viewer
|
||||
|
||||
``` js
|
||||
import Vue from 'vue'
|
||||
import JsonViewer from '../lib'
|
||||
import JsonViewer from 'vue-json-viewer'
|
||||
|
||||
// Import JsonViewer as a Vue.js plugin
|
||||
Vue.use(JsonViewer)
|
||||
// or
|
||||
// components: {JsonViewer}
|
||||
|
||||
|
||||
new Vue({
|
||||
el: '#app',
|
||||
@@ -111,6 +127,22 @@ new Vue({
|
||||
}
|
||||
})
|
||||
```
|
||||
### SSR
|
||||
``` js
|
||||
import JsonViewer from 'vue-json-viewer/ssr'
|
||||
|
||||
// Import JsonViewer as a Vue.js plugin
|
||||
Vue.use(JsonViewer)
|
||||
// or
|
||||
// components: {JsonViewer}
|
||||
```
|
||||
and
|
||||
|
||||
``` js
|
||||
import 'vue-json-viewer/style.css'
|
||||
```
|
||||
|
||||
|
||||
### Preview
|
||||

|
||||
|
||||
@@ -121,10 +153,25 @@ new Vue({
|
||||
| ----------- |:------------- | ----------- |
|
||||
| `value` | JSON data (can be used with `v-model`) | **Required** |
|
||||
| `expand-depth` | Collapse blocs under this depth | `1` |
|
||||
| `copyable` | Display the copy button | `false` |
|
||||
| `copyable` | Display the copy button, you can customize copy text just set `{copyText: 'copy', copiedText: 'copied', timeout: 2000}` or set `true` use default copytext | `false` |
|
||||
| `sort` | Sort keys before displaying | `false` |
|
||||
| `boxed` | Add a fancy "boxed" style to component | `false` |
|
||||
| `theme` | Add a custom CSS class for theming purposes | `jv-light` |
|
||||
| `expanded` | Default expand the view | `false` |
|
||||
| `timeformat` | custom time format function | time => time.toLocaleString() |
|
||||
| `preview-mode` | no expand mode | `false` |
|
||||
|
||||
## Listeners
|
||||
|
||||
| Listener | Description | Value |
|
||||
| ----------- |:------------- | ----------- |
|
||||
| `copied` | Emits copyEvent after text copied | Clipboard success event |
|
||||
|
||||
## Slots
|
||||
|
||||
| Name | Description | Scope |
|
||||
| ----------- |:------------- | ----------- |
|
||||
| `copy` | Custom content for copy button | `{copied: boolean}` |
|
||||
|
||||
## Theming
|
||||
|
||||
@@ -160,6 +207,8 @@ To create custom theme, (e.g. `my-awesome-json-theme`), in two easy steps:
|
||||
&.jv-boolean { color: #fc1e70 }
|
||||
&.jv-function { color: #067bca }
|
||||
&.jv-number { color: #fc1e70 }
|
||||
&.jv-number-float { color: #fc1e70 }
|
||||
&.jv-number-integer { color: #fc1e70 }
|
||||
&.jv-object { color: #111111 }
|
||||
&.jv-undefined { color: #e08331 }
|
||||
&.jv-string {
|
||||
|
||||
+216
@@ -0,0 +1,216 @@
|
||||
# vue-json-viewer
|
||||
|
||||
简单易用的json内容展示组件,支持vue@2和3,支持SSR,组件支持增量渲染即使大文件json也可以快速渲染。
|
||||
|
||||
[](https://travis-ci.org/chenfengjw163/vue-json-viewer)
|
||||
[](https://www.npmjs.com/package/vue-json-viewer)
|
||||

|
||||
|
||||
- [安装](#安装)
|
||||
- [示例](#示例)
|
||||
- [选项](#选项)
|
||||
- [主题](#主题)
|
||||
|
||||
## 安装
|
||||
使用 npm:
|
||||
```
|
||||
$ npm install vue-json-viewer@2 --save
|
||||
// Vue2
|
||||
$ npm install vue-json-viewer@3 --save
|
||||
// Vue3
|
||||
```
|
||||
|
||||
使用 yarn:
|
||||
```
|
||||
$ yarn add vue-json-viewer@2
|
||||
// Vue2
|
||||
$ yarn add vue-json-viewer@3
|
||||
// Vue3
|
||||
```
|
||||
|
||||
## 示例
|
||||
|
||||
``` html
|
||||
<json-viewer :value="jsonData"></json-viewer>
|
||||
|
||||
<hr />
|
||||
|
||||
<json-viewer
|
||||
:value="jsonData"
|
||||
:expand-depth=5
|
||||
copyable
|
||||
boxed
|
||||
sort></json-viewer>
|
||||
```
|
||||
|
||||
``` js
|
||||
import Vue from 'vue'
|
||||
import JsonViewer from 'vue-json-viewer'
|
||||
|
||||
// Import JsonViewer as a Vue.js plugin
|
||||
Vue.use(JsonViewer)
|
||||
// or
|
||||
// components: {JsonViewer}
|
||||
|
||||
|
||||
new Vue({
|
||||
el: '#app',
|
||||
data() {
|
||||
return {
|
||||
jsonData: {
|
||||
total: 25,
|
||||
limit: 10,
|
||||
skip: 0,
|
||||
links: {
|
||||
previous: undefined,
|
||||
next: function () {},
|
||||
},
|
||||
data: [
|
||||
{
|
||||
id: '5968fcad629fa84ab65a5247',
|
||||
firstname: 'Ada',
|
||||
lastname: 'Lovelace',
|
||||
awards: null,
|
||||
known: [
|
||||
'mathematics',
|
||||
'computing'
|
||||
],
|
||||
position: {
|
||||
lat: 44.563836,
|
||||
lng: 6.495139
|
||||
},
|
||||
description: `Augusta Ada King, Countess of Lovelace (née Byron; 10 December 1815 – 27 November 1852) was an English mathematician and writer,
|
||||
chiefly known for her work on Charles Babbage's proposed mechanical general-purpose computer,
|
||||
the Analytical Engine. She was the first to recognise that the machine had applications beyond pure calculation,
|
||||
and published the first algorithm intended to be carried out by such a machine.
|
||||
As a result, she is sometimes regarded as the first to recognise the full potential of a "computing machine" and the first computer programmer.`,
|
||||
bornAt: '1815-12-10T00:00:00.000Z',
|
||||
diedAt: '1852-11-27T00:00:00.000Z'
|
||||
}, {
|
||||
id: '5968fcad629fa84ab65a5246',
|
||||
firstname: 'Grace',
|
||||
lastname: 'Hopper',
|
||||
awards: [
|
||||
'Defense Distinguished Service Medal',
|
||||
'Legion of Merit',
|
||||
'Meritorious Service Medal',
|
||||
'American Campaign Medal',
|
||||
'World War II Victory Medal',
|
||||
'National Defense Service Medal',
|
||||
'Armed Forces Reserve Medal',
|
||||
'Naval Reserve Medal',
|
||||
'Presidential Medal of Freedom'
|
||||
],
|
||||
known: null,
|
||||
position: {
|
||||
lat: 43.614624,
|
||||
lng: 3.879995
|
||||
},
|
||||
description: `Grace Brewster Murray Hopper (née Murray; December 9, 1906 – January 1, 1992)
|
||||
was an American computer scientist and United States Navy rear admiral.
|
||||
One of the first programmers of the Harvard Mark I computer,
|
||||
she was a pioneer of computer programming who invented one of the first compiler related tools.
|
||||
She popularized the idea of machine-independent programming languages, which led to the development of COBOL,
|
||||
an early high-level programming language still in use today.`,
|
||||
bornAt: '1815-12-10T00:00:00.000Z',
|
||||
diedAt: '1852-11-27T00:00:00.000Z'
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
```
|
||||
### 支持SSR
|
||||
``` js
|
||||
import JsonViewer from 'vue-json-viewer/ssr'
|
||||
|
||||
// Import JsonViewer as a Vue.js plugin
|
||||
Vue.use(JsonViewer)
|
||||
// or
|
||||
// components: {JsonViewer}
|
||||
```
|
||||
and
|
||||
|
||||
``` js
|
||||
import 'vue-json-viewer/style.css'
|
||||
```
|
||||
|
||||
|
||||
### 图片预览
|
||||

|
||||
|
||||
|
||||
## 选项
|
||||
|
||||
| 属性 | 描述 | 默认值 |
|
||||
| ----------- |:------------- | ----------- |
|
||||
| `value` | json对象的值,可以使用v-model,支持响应式 | **必填** |
|
||||
| `expand-depth` | 默认展开的层级 | `1` |
|
||||
| `copyable` | 展示复制按钮,默认文案为:copy、copied!, 你可以设置一个对象`{copyText: 'copy', copiedText: 'copied'}` 来自定义复制按钮文案 | `false` |
|
||||
| `sort` | 按照key排序展示 | `false` |
|
||||
| `boxed` | 为组件添加一个盒样式 | `false` |
|
||||
| `theme` | 添加一个自定义的样式class用作主题 | `jv-light` |
|
||||
| `expanded` | 默认展开视图 | `false` |
|
||||
| `timeformat` | 自定义时间格式函数 | time => time.toLocaleString() |
|
||||
| `preview-mode` | 不可折叠模式,默认全部展开 | `false` |
|
||||
|
||||
## 主题
|
||||
|
||||
有两个办法创建自定义主题, (e.g. `my-awesome-json-theme`):
|
||||
1. 添加 `theme="my-awesome-json-theme"` JsonViewer的组件属性
|
||||
2. 复制粘贴下面的模板并且根据自定义的theme名称做对应调整:
|
||||
|
||||
``` scss
|
||||
// values are default one from jv-light template
|
||||
.my-awesome-json-theme {
|
||||
background: #fff;
|
||||
white-space: nowrap;
|
||||
color: #525252;
|
||||
font-size: 14px;
|
||||
font-family: Consolas, Menlo, Courier, monospace;
|
||||
|
||||
.jv-ellipsis {
|
||||
color: #999;
|
||||
background-color: #eee;
|
||||
display: inline-block;
|
||||
line-height: 0.9;
|
||||
font-size: 0.9em;
|
||||
padding: 0px 4px 2px 4px;
|
||||
border-radius: 3px;
|
||||
vertical-align: 2px;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
}
|
||||
.jv-button { color: #49b3ff }
|
||||
.jv-key { color: #111111 }
|
||||
.jv-item {
|
||||
&.jv-array { color: #111111 }
|
||||
&.jv-boolean { color: #fc1e70 }
|
||||
&.jv-function { color: #067bca }
|
||||
&.jv-number { color: #fc1e70 }
|
||||
&.jv-number-float { color: #fc1e70 }
|
||||
&.jv-number-integer { color: #fc1e70 }
|
||||
&.jv-object { color: #111111 }
|
||||
&.jv-undefined { color: #e08331 }
|
||||
&.jv-string {
|
||||
color: #42b983;
|
||||
word-break: break-word;
|
||||
white-space: normal;
|
||||
}
|
||||
}
|
||||
.jv-code {
|
||||
.jv-toggle {
|
||||
&:before {
|
||||
padding: 0px 2px;
|
||||
border-radius: 2px;
|
||||
}
|
||||
&:hover {
|
||||
&:before {
|
||||
background: #eee;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
+27
-16
@@ -1,14 +1,29 @@
|
||||
const path = require('path');
|
||||
const webpack = require('webpack')
|
||||
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
|
||||
const VueLoaderPlugin = require('vue-loader/lib/plugin');
|
||||
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
|
||||
|
||||
module.exports = {
|
||||
mode: 'production',
|
||||
entry: './lib/index.js',
|
||||
optimization: {
|
||||
minimizer: [
|
||||
new UglifyJsPlugin({
|
||||
cache: true,
|
||||
parallel: true,
|
||||
sourceMap: true,
|
||||
uglifyOptions: {
|
||||
comments: false
|
||||
}
|
||||
}),
|
||||
],
|
||||
},
|
||||
output: {
|
||||
path: path.join(__dirname, '../dist'),
|
||||
path: path.join(__dirname, '../'),
|
||||
filename: 'vue-json-viewer.js',
|
||||
libraryTarget: 'umd',
|
||||
library: 'JsonView'
|
||||
library: 'JsonView',
|
||||
globalObject: 'this'
|
||||
},
|
||||
resolve: {
|
||||
extensions: ['.js', '.vue'],
|
||||
@@ -17,7 +32,8 @@ module.exports = {
|
||||
]
|
||||
},
|
||||
externals: {
|
||||
vue: 'vue'
|
||||
vue: 'vue',
|
||||
clipboard: 'clipboard'
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
@@ -27,8 +43,8 @@ module.exports = {
|
||||
exclude: /node_modules/
|
||||
},
|
||||
{
|
||||
test: /\.css$/,
|
||||
use: ['vue-style-loader', 'css-loader', 'autoprefixer-loader']
|
||||
test: /\.s?css$/,
|
||||
use: ['style-loader', 'css-loader', 'postcss-loader', 'sass-loader']
|
||||
},
|
||||
{
|
||||
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
|
||||
@@ -55,15 +71,10 @@ module.exports = {
|
||||
]
|
||||
},
|
||||
plugins: [
|
||||
new webpack.optimize.UglifyJsPlugin({
|
||||
parallel: true,
|
||||
uglifyOptions: {
|
||||
compress: {
|
||||
warnings: false
|
||||
},
|
||||
comments: false
|
||||
}
|
||||
}),
|
||||
// new BundleAnalyzerPlugin()
|
||||
new VueLoaderPlugin()
|
||||
]
|
||||
}
|
||||
|
||||
if (process.argv.some(a => a === '--report')) {
|
||||
module.exports.plugins.push(new BundleAnalyzerPlugin());
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
const path = require('path');
|
||||
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
|
||||
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
|
||||
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
|
||||
const VueLoaderPlugin = require('vue-loader/lib/plugin');
|
||||
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
|
||||
|
||||
module.exports = {
|
||||
mode: 'production',
|
||||
entry: './lib/index.js',
|
||||
optimization: {
|
||||
minimizer: [
|
||||
new UglifyJsPlugin({
|
||||
cache: true,
|
||||
parallel: true,
|
||||
sourceMap: false,
|
||||
uglifyOptions: {
|
||||
comments: false
|
||||
}
|
||||
}),
|
||||
new OptimizeCSSAssetsPlugin({
|
||||
cssProcessorOptions: { safe: true, sourceMap: false}
|
||||
})
|
||||
],
|
||||
},
|
||||
output: {
|
||||
path: path.join(__dirname, '../'),
|
||||
filename: 'ssr.js',
|
||||
libraryTarget: 'umd',
|
||||
library: 'JsonView',
|
||||
globalObject: 'this'
|
||||
},
|
||||
resolve: {
|
||||
extensions: ['.js', '.vue'],
|
||||
modules: [
|
||||
'node_modules'
|
||||
]
|
||||
},
|
||||
externals: {
|
||||
vue: 'vue',
|
||||
clipboard: 'clipboard'
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.js$/,
|
||||
loader: 'babel-loader',
|
||||
exclude: /node_modules/
|
||||
},
|
||||
{
|
||||
test: /\.s?css$/,
|
||||
use: [MiniCssExtractPlugin.loader, 'css-loader', 'postcss-loader', 'sass-loader']
|
||||
},
|
||||
{
|
||||
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
|
||||
loader: 'url-loader',
|
||||
options: {
|
||||
limit: 10000,
|
||||
name: 'img/[name].[ext]'
|
||||
}
|
||||
},
|
||||
{
|
||||
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
|
||||
loader: 'url-loader',
|
||||
options: {
|
||||
limit: 10000,
|
||||
name: 'fonts/[name].[ext]'
|
||||
}
|
||||
},
|
||||
{
|
||||
test: /\.vue$/,
|
||||
use: [{
|
||||
loader: 'vue-loader'
|
||||
}]
|
||||
}
|
||||
]
|
||||
},
|
||||
plugins: [
|
||||
new VueLoaderPlugin(),
|
||||
new MiniCssExtractPlugin({
|
||||
filename: 'style.css',
|
||||
allChunks: true,
|
||||
})
|
||||
]
|
||||
}
|
||||
|
||||
if (process.argv.some(a => a === '--report')) {
|
||||
module.exports.plugins.push(new BundleAnalyzerPlugin());
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
.jv-number-float {
|
||||
color: #faa !important;
|
||||
}
|
||||
.jv-key-node {
|
||||
display: flex;
|
||||
}
|
||||
+44
-6
@@ -1,21 +1,57 @@
|
||||
import Vue from 'vue'
|
||||
import JsonViewer from '../dist/vue-json-viewer'
|
||||
import JsonViewer from '../lib'
|
||||
import './app.css'
|
||||
|
||||
Vue.use(JsonViewer)
|
||||
|
||||
new Vue({
|
||||
el: '#app',
|
||||
render() {
|
||||
const scopedSlots = {
|
||||
copy: ({ copied }) => {
|
||||
if (copied) return <button disabled>Copied!</button>
|
||||
return <button>Copy me!</button>
|
||||
},
|
||||
}
|
||||
const onCopied = (copyEvent) => {
|
||||
alert(`Text successfully copied!\n${copyEvent.text}`);
|
||||
}
|
||||
return (
|
||||
<div>
|
||||
<json-viewer
|
||||
preview-mode
|
||||
value={{
|
||||
data: {
|
||||
data: {
|
||||
data: {
|
||||
a: 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}}></json-viewer>
|
||||
<json-viewer value={this.jsonData}></json-viewer>
|
||||
<hr />
|
||||
<json-viewer
|
||||
value={this.jsonData}
|
||||
expand-depth={5}
|
||||
copyable
|
||||
copyable={{
|
||||
copyText: '复制',
|
||||
copiedText: '复制成功',
|
||||
align: 'left'
|
||||
}}
|
||||
boxed
|
||||
timeformat={time => new Date(time)}
|
||||
sort></json-viewer>
|
||||
<hr />
|
||||
<json-viewer
|
||||
value={this.jsonData}
|
||||
expand-depth={1}
|
||||
copyable={{
|
||||
timeout: 4000,
|
||||
align: 'left'
|
||||
}}
|
||||
scopedSlots={scopedSlots}
|
||||
onCopied={onCopied}></json-viewer>
|
||||
</div>
|
||||
)
|
||||
},
|
||||
@@ -25,6 +61,7 @@ new Vue({
|
||||
total: 25,
|
||||
limit: 10,
|
||||
skip: 0,
|
||||
numbers: 10.11,
|
||||
success: true,
|
||||
links: {
|
||||
previous: undefined,
|
||||
@@ -34,6 +71,7 @@ new Vue({
|
||||
{
|
||||
id: '5968fcad629fa84ab65a5247',
|
||||
firstname: 'Ada',
|
||||
link: 'http://google.com',
|
||||
lastname: 'Lovelace',
|
||||
awards: null,
|
||||
known: [
|
||||
@@ -49,8 +87,8 @@ new Vue({
|
||||
the Analytical Engine. She was the first to recognise that the machine had applications beyond pure calculation,
|
||||
and published the first algorithm intended to be carried out by such a machine.
|
||||
As a result, she is sometimes regarded as the first to recognise the full potential of a "computing machine" and the first computer programmer.`,
|
||||
bornAt: '1815-12-10T00:00:00.000Z',
|
||||
diedAt: '1852-11-27T00:00:00.000Z'
|
||||
bornAt: new Date('1815-12-10T00:00:00.000Z'),
|
||||
diedAt: new Date('1852-11-27T00:00:00.000Z')
|
||||
}, {
|
||||
id: '5968fcad629fa84ab65a5246',
|
||||
firstname: 'Grace',
|
||||
@@ -77,8 +115,8 @@ new Vue({
|
||||
she was a pioneer of computer programming who invented one of the first compiler related tools.
|
||||
She popularized the idea of machine-independent programming languages, which led to the development of COBOL,
|
||||
an early high-level programming language still in use today.`,
|
||||
bornAt: '1815-12-10T00:00:00.000Z',
|
||||
diedAt: '1852-11-27T00:00:00.000Z'
|
||||
bornAt: new Date('1815-12-10T00:00:00.000Z'),
|
||||
diedAt: new Date('1852-11-27T00:00:00.000Z')
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
const path = require('path');
|
||||
const VueLoaderPlugin = require('vue-loader/lib/plugin');
|
||||
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||
|
||||
module.exports = {
|
||||
mode: 'development',
|
||||
entry: './example/app.js',
|
||||
output: {
|
||||
path: path.join(__dirname, '../dist'),
|
||||
@@ -9,7 +11,8 @@ module.exports = {
|
||||
},
|
||||
devtool: 'cheap-module-source-map',
|
||||
devServer: {
|
||||
port: 8081
|
||||
port: 8082,
|
||||
disableHostCheck: true
|
||||
},
|
||||
resolve: {
|
||||
extensions: ['.js', '.vue'],
|
||||
@@ -26,8 +29,8 @@ module.exports = {
|
||||
exclude: /node_modules/
|
||||
},
|
||||
{
|
||||
test: /\.css$/,
|
||||
use: ['vue-style-loader', 'css-loader', 'autoprefixer-loader']
|
||||
test: /\.s?css$/,
|
||||
use: ['vue-style-loader', 'css-loader', 'sass-loader']
|
||||
},
|
||||
{
|
||||
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
|
||||
@@ -59,5 +62,6 @@ module.exports = {
|
||||
template: './example/index.html',
|
||||
inject: true
|
||||
}),
|
||||
new VueLoaderPlugin(),
|
||||
]
|
||||
}
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
<svg height="16" width="8" xmlns="http://www.w3.org/2000/svg">
|
||||
|
||||
<polygon points="0,0 8,8 0,16"
|
||||
style="fill:#666;stroke:purple;stroke-width:0" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 152 B |
+56
-11
@@ -6,13 +6,14 @@ import JsonBoolean from './types/json-boolean'
|
||||
import JsonObject from './types/json-object'
|
||||
import JsonArray from './types/json-array'
|
||||
import JsonFunction from './types/json-function'
|
||||
import JsonDate from './types/json-date'
|
||||
|
||||
export default {
|
||||
name: 'JsonBox',
|
||||
inject: ['expandDepth'],
|
||||
props: {
|
||||
value: {
|
||||
type: [Object, Array, String, Number, Boolean, Function],
|
||||
type: [Object, Array, String, Number, Boolean, Function, Date],
|
||||
default: null
|
||||
},
|
||||
keyName: {
|
||||
@@ -23,20 +24,32 @@ export default {
|
||||
depth: {
|
||||
type: Number,
|
||||
default: 0
|
||||
}
|
||||
},
|
||||
previewMode: Boolean,
|
||||
forceExpand: Boolean,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
expand: true
|
||||
expand: true,
|
||||
forceExpandMe: this.forceExpand,
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.expand = this.depth >= this.expandDepth ? false : true
|
||||
this.expand = this.previewMode || (this.depth >= this.expandDepth ? false : true) || this.forceExpandMe
|
||||
},
|
||||
methods: {
|
||||
toggle() {
|
||||
this.expand = !this.expand
|
||||
|
||||
this.dispatchEvent()
|
||||
},
|
||||
toggleAll() {
|
||||
this.expand = !this.expand
|
||||
this.forceExpandMe = this.expand
|
||||
|
||||
this.dispatchEvent()
|
||||
},
|
||||
dispatchEvent() {
|
||||
try {
|
||||
this.$el.dispatchEvent(new Event('resized'))
|
||||
} catch (e) {
|
||||
@@ -45,16 +58,29 @@ export default {
|
||||
evt.initEvent('resized', true, false)
|
||||
this.$el.dispatchEvent(evt)
|
||||
}
|
||||
},
|
||||
getPath() {
|
||||
const path = [this.keyName];
|
||||
let p = this.$parent;
|
||||
while(p.depth) {
|
||||
if (p.$el.classList.contains('jv-node')) {
|
||||
path.push(p.keyName);
|
||||
}
|
||||
p = p.$parent;
|
||||
}
|
||||
return path.reverse()
|
||||
}
|
||||
},
|
||||
render (h) {
|
||||
let elements = []
|
||||
let dataType
|
||||
|
||||
if (this.value === null || this.value === undefined) {
|
||||
if (this.value === null || this.value === undefined) {
|
||||
dataType = JsonUndefined
|
||||
} else if (Array.isArray(this.value)) {
|
||||
dataType = JsonArray
|
||||
} else if (Object.prototype.toString.call(this.value) === '[object Date]') {
|
||||
dataType = JsonDate
|
||||
} else if (typeof this.value === 'object') {
|
||||
dataType = JsonObject
|
||||
} else if (typeof this.value === 'number') {
|
||||
@@ -66,15 +92,22 @@ export default {
|
||||
} else if (typeof this.value === 'function') {
|
||||
dataType = JsonFunction
|
||||
}
|
||||
const complex = this.keyName && (this.value && (Array.isArray(this.value) || (typeof this.value === 'object' && Object.prototype.toString.call(this.value) !== '[object Date]')))
|
||||
|
||||
if (this.keyName && (this.value && (Array.isArray(this.value) || typeof this.value === 'object'))) {
|
||||
if (!this.previewMode && complex) {
|
||||
elements.push(h('span', {
|
||||
class: {
|
||||
'jv-toggle': true,
|
||||
open: !!this.expand
|
||||
},
|
||||
on: {
|
||||
click: this.toggle
|
||||
click: (event) => {
|
||||
if (event.altKey) {
|
||||
this.toggleAll()
|
||||
} else {
|
||||
this.toggle()
|
||||
}
|
||||
}
|
||||
}
|
||||
}))
|
||||
}
|
||||
@@ -85,7 +118,7 @@ export default {
|
||||
'jv-key': true
|
||||
},
|
||||
domProps: {
|
||||
innerHTML: `${this.keyName}:`
|
||||
innerText: `${this.keyName}:`
|
||||
}
|
||||
}))
|
||||
}
|
||||
@@ -99,18 +132,26 @@ export default {
|
||||
keyName: this.keyName,
|
||||
sort: this.sort,
|
||||
depth: this.depth,
|
||||
expand: this.expand
|
||||
expand: this.expand,
|
||||
previewMode: this.previewMode,
|
||||
forceExpand: this.forceExpandMe
|
||||
},
|
||||
on: {
|
||||
'update:expand': value => {
|
||||
this.expand = value
|
||||
},
|
||||
'update:expandAll': value => {
|
||||
this.expand = value
|
||||
this.forceExpandMe = this.expand
|
||||
}
|
||||
}
|
||||
}))
|
||||
|
||||
return h('div', {
|
||||
class: {
|
||||
'jv-node': true
|
||||
class: {
|
||||
'jv-node': true,
|
||||
'jv-key-node': Boolean(this.keyName) && !complex,
|
||||
'toggle': !this.previewMode && complex
|
||||
}
|
||||
}, elements)
|
||||
}
|
||||
@@ -130,6 +171,10 @@ export default {
|
||||
}
|
||||
}
|
||||
|
||||
&.toggle {
|
||||
margin-left: 13px !important;
|
||||
}
|
||||
|
||||
& .jv-node {
|
||||
margin-left: 25px;
|
||||
}
|
||||
|
||||
+109
-52
@@ -1,28 +1,38 @@
|
||||
<template>
|
||||
<div :class="jvClass">
|
||||
<div
|
||||
ref="viewer"
|
||||
:class="jvClass"
|
||||
>
|
||||
<div
|
||||
v-if="copyable"
|
||||
class="jv-tooltip"
|
||||
:class="`jv-tooltip ${copyText.align || 'right'}`"
|
||||
>
|
||||
<span
|
||||
ref="clip"
|
||||
class="jv-button"
|
||||
:class="{copied}"
|
||||
@click="clip"
|
||||
>{{ copied ? 'copied!' : 'copy' }}</span>
|
||||
>
|
||||
<slot
|
||||
name="copy"
|
||||
:copied="copied"
|
||||
>
|
||||
{{ copied ? copyText.copiedText : copyText.copyText }}
|
||||
</slot>
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="jv-code"
|
||||
:class="{'open': expandCode}"
|
||||
:class="{'open': expandCode, boxed}"
|
||||
>
|
||||
<json-box
|
||||
ref="jsonBox"
|
||||
:value="value"
|
||||
:sort="sort"
|
||||
:preview-mode="previewMode"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
v-if="expandableCode"
|
||||
v-if="expandableCode && boxed"
|
||||
class="jv-more"
|
||||
@click="toggleExpandCode"
|
||||
>
|
||||
@@ -38,6 +48,7 @@
|
||||
import Vue from 'vue'
|
||||
import JsonBox from './json-box'
|
||||
import Clipboard from 'clipboard'
|
||||
import {debounce} from './utils';
|
||||
|
||||
export default {
|
||||
name: 'JsonViewer',
|
||||
@@ -49,12 +60,16 @@ export default {
|
||||
type: [Object, Array, String, Number, Boolean, Function],
|
||||
required: true
|
||||
},
|
||||
expanded: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
expandDepth: {
|
||||
type: Number,
|
||||
default: 1
|
||||
},
|
||||
copyable: {
|
||||
type: Boolean,
|
||||
type: [Boolean, Object],
|
||||
default: false
|
||||
},
|
||||
sort: {
|
||||
@@ -69,31 +84,73 @@ export default {
|
||||
type: String,
|
||||
default: 'jv-light'
|
||||
},
|
||||
timeformat: {
|
||||
type: Function,
|
||||
default: value => value.toLocaleString(),
|
||||
},
|
||||
previewMode: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
}
|
||||
},
|
||||
provide () {
|
||||
return {
|
||||
expandDepth: this.expandDepth,
|
||||
timeformat: this.timeformat,
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
copied: false,
|
||||
expandableCode: false,
|
||||
expandCode: false
|
||||
expandCode: this.expanded
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
jvClass () {
|
||||
jvClass() {
|
||||
return 'jv-container ' + this.theme + (this.boxed ? ' boxed' : '')
|
||||
},
|
||||
copyText() {
|
||||
const { copyText, copiedText, timeout, align } = this.copyable
|
||||
|
||||
return {
|
||||
copyText: copyText || 'copy',
|
||||
copiedText: copiedText || 'copied!',
|
||||
timeout: timeout || 2000,
|
||||
align,
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
value() {
|
||||
this.onResized()
|
||||
}
|
||||
},
|
||||
mounted: function () {
|
||||
this.onResized()
|
||||
this.$el.addEventListener("resized", this.onResized, true)
|
||||
this.debounceResized = debounce(this.debResized.bind(this), 200);
|
||||
if (this.boxed && this.$refs.jsonBox) {
|
||||
this.onResized()
|
||||
this.$refs.jsonBox.$el.addEventListener("resized", this.onResized, true)
|
||||
}
|
||||
if (this.copyable) {
|
||||
const clipBoard = new Clipboard(this.$refs.clip, {
|
||||
container: this.$refs.viewer,
|
||||
text: () => {
|
||||
return JSON.stringify(this.value, null, 2)
|
||||
}
|
||||
});
|
||||
clipBoard.on('success', (e) => {
|
||||
this.onCopied(e)
|
||||
})
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onResized () {
|
||||
this.debounceResized();
|
||||
},
|
||||
debResized() {
|
||||
this.$nextTick(() => {
|
||||
if (!this.$refs.jsonBox) return;
|
||||
if (this.$refs.jsonBox.$el.clientHeight >= 250) {
|
||||
this.expandableCode = true
|
||||
} else {
|
||||
@@ -101,25 +158,15 @@ export default {
|
||||
}
|
||||
})
|
||||
},
|
||||
clip () {
|
||||
onCopied(copyEvent) {
|
||||
if (this.copied) {
|
||||
return
|
||||
return;
|
||||
}
|
||||
|
||||
const clipBoard = new Clipboard(this.$refs.clip, {
|
||||
text: () => {
|
||||
return JSON.stringify(this.value, null, 2)
|
||||
}
|
||||
})
|
||||
|
||||
clipBoard.on('success', () => {
|
||||
this.copied = true
|
||||
setTimeout(() => {
|
||||
this.copied = false
|
||||
}, 2000)
|
||||
this.$emit('copied')
|
||||
clipBoard.destroy()
|
||||
})
|
||||
this.copied = true
|
||||
setTimeout(() => {
|
||||
this.copied = false
|
||||
}, this.copyText.timeout)
|
||||
this.$emit('copied', copyEvent)
|
||||
},
|
||||
toggleExpandCode () {
|
||||
this.expandCode = !this.expandCode
|
||||
@@ -194,6 +241,10 @@ export default {
|
||||
color: #42b983;
|
||||
word-break: break-word;
|
||||
white-space: normal;
|
||||
|
||||
.jv-link {
|
||||
color: #0366d6;
|
||||
}
|
||||
}
|
||||
}
|
||||
.jv-code {
|
||||
@@ -212,12 +263,15 @@ export default {
|
||||
}
|
||||
|
||||
.jv-code {
|
||||
max-height: 300px;
|
||||
overflow: hidden;
|
||||
padding: 20px;
|
||||
padding: 30px 20px;
|
||||
|
||||
&.boxed {
|
||||
max-height: 300px;
|
||||
}
|
||||
|
||||
&.open {
|
||||
max-height: initial;
|
||||
max-height: initial !important;
|
||||
overflow: visible;
|
||||
overflow-x: auto;
|
||||
padding-bottom: 45px;
|
||||
@@ -225,25 +279,19 @@ export default {
|
||||
}
|
||||
|
||||
.jv-toggle {
|
||||
background-image: url(./icon.svg);
|
||||
background-repeat: no-repeat;
|
||||
background-size: contain;
|
||||
background-position: center center;
|
||||
cursor: pointer;
|
||||
|
||||
&:before {
|
||||
content: "⏷";
|
||||
padding: 0px 2px;
|
||||
border-radius: 2px;
|
||||
position: absolute;
|
||||
}
|
||||
&:after {
|
||||
content: " ";
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
width: 16px;
|
||||
}
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
margin-right: 2px;
|
||||
display: inline-block;
|
||||
transition: transform 0.1s;
|
||||
|
||||
&.open {
|
||||
&:before {
|
||||
content: "⏶";
|
||||
}
|
||||
transform: rotate(90deg)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -264,7 +312,11 @@ export default {
|
||||
z-index: 2;
|
||||
color: #888;
|
||||
transition: all 0.1s;
|
||||
// background: red;
|
||||
transform: rotate(90deg);
|
||||
|
||||
&.open {
|
||||
transform: rotate(-90deg)
|
||||
}
|
||||
}
|
||||
|
||||
&:after {
|
||||
@@ -278,14 +330,14 @@ export default {
|
||||
background: linear-gradient(
|
||||
to bottom,
|
||||
rgba(0, 0, 0, 0) 20%,
|
||||
rgba(230, 230, 230, 1) 100%
|
||||
rgba(230, 230, 230, 0.3) 100%
|
||||
);
|
||||
transition: all 0.1s;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
.jv-toggle {
|
||||
top: 50%;
|
||||
top: 50%;
|
||||
color: #111;
|
||||
}
|
||||
|
||||
@@ -314,8 +366,13 @@ export default {
|
||||
|
||||
.jv-tooltip {
|
||||
position: absolute;
|
||||
right: 15px;
|
||||
top: 10px;
|
||||
|
||||
&.right {
|
||||
right: 15px;
|
||||
}
|
||||
&.left {
|
||||
left: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
.j-icon {
|
||||
|
||||
+70
-42
@@ -17,23 +17,44 @@ export default {
|
||||
default: 0
|
||||
},
|
||||
sort: Boolean,
|
||||
expand: Boolean
|
||||
expand: Boolean,
|
||||
forceExpand: Boolean,
|
||||
previewMode: Boolean,
|
||||
},
|
||||
computed: {
|
||||
ordered () {
|
||||
let value = this.jsonValue
|
||||
|
||||
if (!this.sort) {
|
||||
return value
|
||||
}
|
||||
|
||||
return value.sort()
|
||||
data() {
|
||||
return {
|
||||
value: []
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
jsonValue(newVal) {
|
||||
this.setValue(newVal);
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.setValue(this.jsonValue);
|
||||
},
|
||||
methods: {
|
||||
setValue(vals, index = 0) {
|
||||
if (index === 0) {
|
||||
this.value = [];
|
||||
}
|
||||
setTimeout(() => {
|
||||
if (vals.length > index) {
|
||||
this.value.push(vals[index]);
|
||||
this.setValue(vals, index + 1);
|
||||
}
|
||||
}, 0);
|
||||
},
|
||||
toggle() {
|
||||
this.$emit('update:expand', !this.expand)
|
||||
|
||||
this.dispatchEvent();
|
||||
},
|
||||
toggleAll() {
|
||||
this.$emit('update:expandAll', !this.expand)
|
||||
this.dispatchEvent();
|
||||
},
|
||||
dispatchEvent() {
|
||||
try {
|
||||
this.$el.dispatchEvent(new Event('resized'))
|
||||
} catch (e) {
|
||||
@@ -47,14 +68,20 @@ export default {
|
||||
render (h) {
|
||||
let elements = []
|
||||
|
||||
if (!this.keyName) {
|
||||
if (!this.previewMode && !this.keyName) {
|
||||
elements.push(h('span', {
|
||||
class: {
|
||||
'jv-toggle': true,
|
||||
'open': !!this.expand,
|
||||
'open': !!this.expand,
|
||||
},
|
||||
on: {
|
||||
click: this.toggle
|
||||
click: (event) => {
|
||||
if (event.altKey) {
|
||||
this.toggleAll()
|
||||
} else {
|
||||
this.toggle()
|
||||
}
|
||||
}
|
||||
}
|
||||
}))
|
||||
}
|
||||
@@ -62,46 +89,47 @@ export default {
|
||||
elements.push(h('span', {
|
||||
class: {
|
||||
'jv-item': true,
|
||||
'jv-array': true,
|
||||
'jv-array': true,
|
||||
},
|
||||
domProps: {
|
||||
innerHTML: '['
|
||||
innerText: '['
|
||||
}
|
||||
}))
|
||||
|
||||
for (let key in this.ordered) {
|
||||
let value = this.ordered[key]
|
||||
|
||||
elements.push(h(JsonBox, {
|
||||
key,
|
||||
style: {
|
||||
display: !this.expand ? 'none' : undefined
|
||||
},
|
||||
props: {
|
||||
sort: this.sort,
|
||||
// keyName: key,
|
||||
depth: this.depth + 1,
|
||||
value,
|
||||
}
|
||||
}))
|
||||
if (this.expand) {
|
||||
this.value.forEach((value, key) => {
|
||||
elements.push(h(JsonBox, {
|
||||
key,
|
||||
props: {
|
||||
sort: this.sort,
|
||||
keyName: `${key}`,
|
||||
depth: this.depth + 1,
|
||||
value,
|
||||
previewMode: this.previewMode,
|
||||
forceExpand: this.forceExpand,
|
||||
}
|
||||
}))
|
||||
})
|
||||
}
|
||||
|
||||
if (!this.expand) {
|
||||
if (!this.expand && this.value.length) {
|
||||
elements.push(h('span', {
|
||||
style: {
|
||||
display: this.expand ? 'none' : undefined
|
||||
},
|
||||
class: {
|
||||
'jv-ellipsis': true,
|
||||
'jv-ellipsis': true,
|
||||
},
|
||||
on: {
|
||||
click: this.toggle
|
||||
click: (event) => {
|
||||
if (event.altKey) {
|
||||
this.toggleAll()
|
||||
} else {
|
||||
this.toggle()
|
||||
}
|
||||
}
|
||||
},
|
||||
attrs: {
|
||||
title: `click to reveal ${this.jsonValue.length} hidden items`
|
||||
title: `click to reveal ${this.value.length} hidden items`
|
||||
},
|
||||
domProps: {
|
||||
innerHTML: '...'
|
||||
innerText: '...'
|
||||
}
|
||||
}))
|
||||
}
|
||||
@@ -109,10 +137,10 @@ export default {
|
||||
elements.push(h('span', {
|
||||
class: {
|
||||
'jv-item': true,
|
||||
'jv-array': true,
|
||||
'jv-array': true,
|
||||
},
|
||||
domProps: {
|
||||
innerHTML: ']'
|
||||
innerText: ']'
|
||||
}
|
||||
}))
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ export default {
|
||||
'jv-boolean': true,
|
||||
},
|
||||
domProps: {
|
||||
innerHTML: props.jsonValue.toString()
|
||||
innerText: props.jsonValue.toString()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
<script>
|
||||
export default {
|
||||
name: 'JsonDate',
|
||||
inject: ['timeformat'],
|
||||
functional: true,
|
||||
props: {
|
||||
jsonValue: {
|
||||
type: Date,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
render (h, { props, injections }) {
|
||||
const value = props.jsonValue;
|
||||
const timeformat = injections.timeformat;
|
||||
|
||||
return h('span', {
|
||||
class: {
|
||||
'jv-item': true,
|
||||
'jv-string': true,
|
||||
},
|
||||
domProps: {
|
||||
innerText: `"${timeformat(value)}"`
|
||||
}
|
||||
})
|
||||
}
|
||||
};
|
||||
</script>
|
||||
@@ -9,13 +9,17 @@ export default {
|
||||
}
|
||||
},
|
||||
render (h, { props }) {
|
||||
const isInteger = Number.isInteger(props.jsonValue)
|
||||
|
||||
return h('span', {
|
||||
class: {
|
||||
'jv-item': true,
|
||||
'jv-number': true,
|
||||
'jv-number-integer': isInteger,
|
||||
'jv-number-float': !isInteger,
|
||||
},
|
||||
domProps: {
|
||||
innerHTML: props.jsonValue.toString()
|
||||
innerText: props.jsonValue.toString()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
+70
-34
@@ -17,25 +17,51 @@ export default {
|
||||
default: 0
|
||||
},
|
||||
expand: Boolean,
|
||||
sort: Boolean
|
||||
forceExpand: Boolean,
|
||||
sort: Boolean,
|
||||
previewMode: Boolean,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
value: {}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
ordered () {
|
||||
if (!this.sort) {
|
||||
return this.jsonValue
|
||||
return this.value
|
||||
}
|
||||
|
||||
const ordered = {}
|
||||
Object.keys(this.jsonValue).sort().forEach(key => {
|
||||
ordered[key] = this.jsonValue[key]
|
||||
Object.keys(this.value).sort().forEach(key => {
|
||||
ordered[key] = this.value[key]
|
||||
})
|
||||
return ordered
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
jsonValue(newVal) {
|
||||
this.setValue(newVal);
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.setValue(this.jsonValue);
|
||||
},
|
||||
methods: {
|
||||
setValue(val) {
|
||||
setTimeout(() => {
|
||||
this.value = val;
|
||||
}, 0);
|
||||
},
|
||||
toggle() {
|
||||
this.$emit('update:expand', !this.expand)
|
||||
|
||||
this.dispatchEvent();
|
||||
},
|
||||
toggleAll() {
|
||||
this.$emit('update:expandAll', !this.expand)
|
||||
this.dispatchEvent();
|
||||
},
|
||||
dispatchEvent() {
|
||||
try {
|
||||
this.$el.dispatchEvent(new Event('resized'))
|
||||
} catch (e) {
|
||||
@@ -49,14 +75,20 @@ export default {
|
||||
render (h) {
|
||||
let elements = []
|
||||
|
||||
if (!this.keyName) {
|
||||
if (!this.previewMode && !this.keyName) {
|
||||
elements.push(h('span', {
|
||||
class: {
|
||||
'jv-toggle': true,
|
||||
'open': !!this.expand,
|
||||
'open': !!this.expand,
|
||||
},
|
||||
on: {
|
||||
click: this.toggle
|
||||
click: (event) => {
|
||||
if (event.altKey) {
|
||||
this.toggleAll()
|
||||
} else {
|
||||
this.toggle()
|
||||
}
|
||||
}
|
||||
}
|
||||
}))
|
||||
}
|
||||
@@ -64,48 +96,52 @@ export default {
|
||||
elements.push(h('span', {
|
||||
class: {
|
||||
'jv-item': true,
|
||||
'jv-object': true,
|
||||
'jv-object': true,
|
||||
},
|
||||
domProps: {
|
||||
innerHTML: '{'
|
||||
innerText: '{'
|
||||
}
|
||||
}))
|
||||
|
||||
for (let key in this.ordered) {
|
||||
if (this.ordered.hasOwnProperty(key)) {
|
||||
let value = this.ordered[key]
|
||||
if (this.expand) {
|
||||
for (let key in this.ordered) {
|
||||
if (this.ordered.hasOwnProperty(key)) {
|
||||
let value = this.ordered[key]
|
||||
|
||||
elements.push(h(JsonBox, {
|
||||
key,
|
||||
style: {
|
||||
display: !this.expand ? 'none' : undefined
|
||||
},
|
||||
props: {
|
||||
sort: this.sort,
|
||||
keyName: key,
|
||||
depth: this.depth + 1,
|
||||
value,
|
||||
}
|
||||
}))
|
||||
elements.push(h(JsonBox, {
|
||||
key,
|
||||
props: {
|
||||
sort: this.sort,
|
||||
keyName: key,
|
||||
depth: this.depth + 1,
|
||||
value,
|
||||
previewMode: this.previewMode,
|
||||
forceExpand: this.forceExpand,
|
||||
}
|
||||
}))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!this.expand) {
|
||||
if (!this.expand && Object.keys(this.value).length) {
|
||||
elements.push(h('span', {
|
||||
style: {
|
||||
display: this.expand ? 'none' : undefined
|
||||
},
|
||||
class: {
|
||||
'jv-ellipsis': true,
|
||||
'jv-ellipsis': true,
|
||||
},
|
||||
on: {
|
||||
click: this.toggle
|
||||
click: (event) => {
|
||||
if (event.altKey) {
|
||||
this.toggleAll()
|
||||
} else {
|
||||
this.toggle()
|
||||
}
|
||||
}
|
||||
},
|
||||
attrs: {
|
||||
title: `click to reveal object content (keys: ${Object.keys(this.ordered).join(', ')})`
|
||||
},
|
||||
domProps: {
|
||||
innerHTML: '...'
|
||||
innerText: '...'
|
||||
}
|
||||
}))
|
||||
}
|
||||
@@ -113,10 +149,10 @@ export default {
|
||||
elements.push(h('span', {
|
||||
class: {
|
||||
'jv-item': true,
|
||||
'jv-object': true,
|
||||
'jv-object': true,
|
||||
},
|
||||
domProps: {
|
||||
innerHTML: '}'
|
||||
innerText: '}'
|
||||
}
|
||||
}))
|
||||
|
||||
|
||||
+73
-10
@@ -1,23 +1,86 @@
|
||||
<script>
|
||||
const REG_LINK = /^\w+:\/\//;
|
||||
|
||||
export default {
|
||||
name: 'JsonString',
|
||||
functional: true,
|
||||
props: {
|
||||
jsonValue: {
|
||||
type: String,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
render (h, { props }) {
|
||||
return h('span', {
|
||||
class: {
|
||||
'jv-item': true,
|
||||
'jv-string': true,
|
||||
},
|
||||
domProps: {
|
||||
innerHTML: `"${props.jsonValue.toString()}"`
|
||||
data() {
|
||||
return {
|
||||
expand: true,
|
||||
canExtend: false,
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
if (this.$refs.itemRef.offsetHeight > this.$refs.holderRef.offsetHeight) {
|
||||
this.canExtend = true;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
toggle() {
|
||||
this.expand = !this.expand;
|
||||
}
|
||||
},
|
||||
render (h) {
|
||||
let value = this.jsonValue;
|
||||
const islink = REG_LINK.test(value)
|
||||
let domItem
|
||||
|
||||
if (!this.expand) {
|
||||
domItem = {
|
||||
class: {
|
||||
'jv-ellipsis': true,
|
||||
},
|
||||
on: {
|
||||
click: this.toggle
|
||||
},
|
||||
domProps: {
|
||||
innerText: '...'
|
||||
}
|
||||
};
|
||||
} else {
|
||||
domItem = {
|
||||
class: {
|
||||
'jv-item': true,
|
||||
'jv-string': true,
|
||||
},
|
||||
ref: 'itemRef',
|
||||
}
|
||||
})
|
||||
if (islink) {
|
||||
value = `<a href="${value}" target="_blank" class="jv-link">${value}</a>`;
|
||||
domItem.domProps = {
|
||||
innerHTML: `"${value.toString()}"`
|
||||
}
|
||||
} else {
|
||||
domItem.domProps = {
|
||||
innerText: `"${value.toString()}"`
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return h('span', {}, [
|
||||
this.canExtend && h('span', {
|
||||
class: {
|
||||
'jv-toggle': true,
|
||||
open: this.expand,
|
||||
},
|
||||
on: {
|
||||
click: this.toggle,
|
||||
}
|
||||
}),
|
||||
h('span', {
|
||||
class: {
|
||||
'jv-holder-node': true,
|
||||
},
|
||||
ref: 'holderRef'
|
||||
}),
|
||||
h('span', domItem)
|
||||
])
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -15,7 +15,7 @@ export default {
|
||||
'jv-undefined': true,
|
||||
},
|
||||
domProps: {
|
||||
innerHTML: props.jsonValue === null ? 'null' : 'undefined'
|
||||
innerText: props.jsonValue === null ? 'null' : 'undefined'
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
export const debounce = function(func, wait) {
|
||||
let startTime = Date.now();
|
||||
let timer;
|
||||
|
||||
return (...args) => {
|
||||
if (Date.now() - startTime < wait && timer) {
|
||||
clearTimeout(timer);
|
||||
}
|
||||
timer = setTimeout(() => {
|
||||
func(...args);
|
||||
}, wait);
|
||||
startTime = Date.now();
|
||||
}
|
||||
}
|
||||
Generated
-11619
File diff suppressed because it is too large
Load Diff
+29
-25
@@ -1,33 +1,30 @@
|
||||
{
|
||||
"name": "vue-json-viewer",
|
||||
"version": "2.0.2",
|
||||
"version": "2.2.20",
|
||||
"description": "vuejs展示json的组件",
|
||||
"main": "dist/vue-json-viewer.js",
|
||||
"files": [
|
||||
"lib/*"
|
||||
],
|
||||
"main": "vue-json-viewer.js",
|
||||
"files": ["vue-json-viewer.js", "ssr.js", "style.css"],
|
||||
"directories": {
|
||||
"lib": "./lib",
|
||||
"example": "./example"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "webpack --config ./build/webpack.config.js",
|
||||
"build": "npm run build:browser && npm run build:ssr",
|
||||
"build:browser": "webpack --config ./build/webpack.config.js",
|
||||
"build:ssr": "webpack --config ./build/webpack.ssr.config.js",
|
||||
"example": "webpack-dev-server --config ./example/build/webpack.dev.conf.js"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/chenfengjw163/vue-json-viewer.git"
|
||||
},
|
||||
"keywords": [
|
||||
"vue",
|
||||
"json"
|
||||
],
|
||||
"keywords": ["vue", "json"],
|
||||
"homepage": "https://github.com/chenfengjw163/vue-json-viewer#readme",
|
||||
"author": {
|
||||
"name": "陈峰",
|
||||
"email": "chenfengjw@hotmail.com"
|
||||
},
|
||||
"license": "ISC",
|
||||
"license": "MIT",
|
||||
"bugs": {
|
||||
"url": "https://github.com/chenfengjw163/vue-json-viewer/issues"
|
||||
},
|
||||
@@ -42,12 +39,10 @@
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"clipboard": "^1.7.1",
|
||||
"vue": "^2.5.2"
|
||||
"clipboard": "^2.0.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"autoprefixer": "^7.1.5",
|
||||
"autoprefixer-loader": "^3.2.0",
|
||||
"babel-core": "^6.26.0",
|
||||
"babel-eslint": "^8.0.1",
|
||||
"babel-loader": "^7.1.2",
|
||||
@@ -57,21 +52,30 @@
|
||||
"babel-plugin-transform-vue-jsx": "^3.7.0",
|
||||
"babel-preset-es2015": "^6.24.1",
|
||||
"babel-runtime": "^6.26.0",
|
||||
"css-loader": "^0.28.7",
|
||||
"eslint": "^5.6.0",
|
||||
"css-loader": "^3.0.0",
|
||||
"eslint": "^6.0.1",
|
||||
"eslint-plugin-vue": "^5.0.0-beta.3",
|
||||
"file-loader": "^1.1.5",
|
||||
"html-webpack-plugin": "^2.30.1",
|
||||
"node-sass": "^4.5.3",
|
||||
"sass-loader": "^6.0.6",
|
||||
"html-webpack-plugin": "^3.2.0",
|
||||
"mini-css-extract-plugin": "^0.5.0",
|
||||
"node-sass": "^4.12.0",
|
||||
"optimize-css-assets-webpack-plugin": "^5.0.3",
|
||||
"postcss-loader": "^3.0.0",
|
||||
"sass-loader": "^7.1.0",
|
||||
"style-loader": "^0.19.0",
|
||||
"uglifyjs-webpack-plugin": "^2.1.2",
|
||||
"url-loader": "^0.6.2",
|
||||
"vue-loader": "^13.3.0",
|
||||
"vue-style-loader": "^3.0.3",
|
||||
"vue-template-compiler": "^2.5.2",
|
||||
"webpack": "^3.8.1",
|
||||
"webpack-bundle-analyzer": "^3.0.2",
|
||||
"webpack-dev-server": "^2.9.2",
|
||||
"vue": "^2.6.9",
|
||||
"vue-loader": "^15.7.0",
|
||||
"vue-style-loader": "^4.1.2",
|
||||
"vue-template-compiler": "^2.6.9",
|
||||
"webpack": "=4.29.6",
|
||||
"webpack-bundle-analyzer": "^3.3.2",
|
||||
"webpack-cli": "^3.3.11",
|
||||
"webpack-dev-server": "^3.10.3",
|
||||
"webpack-merge": "^4.1.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"vue": "^2.6.9"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
module.exports = {
|
||||
sourceMap: false,
|
||||
plugins: [
|
||||
require('autoprefixer')({
|
||||
browsers: ['> 1%', 'android >=4', 'ios >=8']
|
||||
})
|
||||
]
|
||||
};
|
||||
Reference in New Issue
Block a user