Skip to content

Commit 1cd4814

Browse files
committed
新增复选框功能,props 新增 pathChecked,pathSelectable,selectableType,版本提升至1.3.0
1 parent d3bbeed commit 1cd4814

File tree

6 files changed

+221
-22
lines changed

6 files changed

+221
-22
lines changed

README.md

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
11
# vue-json-pretty
22

3-
A Vue.js project for json-pretty. [leezng/vue-json-pretty](https://github.com/leezng/vue-json-pretty)
3+
A Vue.js 2.0 Toolkit for json.
44

5-
## Installation
5+
## Links
6+
7+
- [Demo](https://leezng.github.io/vue-json-pretty)
8+
- [Github](https://github.com/leezng/vue-json-pretty)
9+
10+
## Install
611

712
```js
813
npm install vue-json-pretty
@@ -39,6 +44,9 @@ export default {
3944
|-------- |-------- |-------- | -------- |
4045
| data | json data | JSON object | - |
4146
| path | root data path | string | root |
47+
| pathChecked | defines the selected data path | array | [] |
48+
| pathSelectable | defines whether a data path supports selection | Function(itemPath, itemData) | - |
49+
| selectableType | defines the selected type, by default all types are supported | enum: both, checkbox, tree | both |
4250

4351
## Events
4452

example/App.vue

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,13 @@
22
<div id="app" class="example-app">
33
<div>
44
<h2>JSON Tree:</h2>
5-
<vue-json-pretty :data="data" :path="'res'" @click="handleClick"></vue-json-pretty>
5+
<vue-json-pretty
6+
:data="data"
7+
:path="'res'"
8+
:path-checked="['res', 'res.c']"
9+
:path-selectable="pathSelectableFn"
10+
@click="handleClick">
11+
</vue-json-pretty>
612
</div>
713
<div class="result">
814
<h2>Click Result:</h2>
@@ -22,15 +28,16 @@ export default {
2228
},
2329
data () {
2430
return {
31+
val: '',
2532
data: {
26-
a: 1,
27-
b: [{
33+
a: 12,
34+
b: [[[{
2835
a: 1,
2936
b: 2
3037
}, {
3138
a: 'abcde',
3239
b: true
33-
}],
40+
}]]],
3441
c: {
3542
a: null,
3643
b: 2
@@ -42,9 +49,13 @@ export default {
4249
}
4350
},
4451
methods: {
45-
handleClick (path, data) {
52+
handleClick (path, data, checked) {
53+
console.log('click', path, data, checked)
4654
this.itemPath = path
4755
this.itemData = !data ? data + '' : data // 处理 data = null 的情况
56+
},
57+
pathSelectableFn (path, data) {
58+
return !(Array.isArray(data) && data.some(item => Array.isArray(item)))
4859
}
4960
}
5061
}

package.json

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "vue-json-pretty",
3-
"version": "1.2.0",
4-
"description": "A Vue.js project",
3+
"version": "1.3.0",
4+
"description": "A Vue.js 2.0 Toolkit for json",
55
"author": "leezng <[email protected]>",
66
"main": "vue-json-pretty.js",
77
"scripts": {
@@ -12,6 +12,22 @@
1212
"test": "npm run e2e",
1313
"lint": "eslint --ext .js,.vue src test/e2e/specs"
1414
},
15+
"repository": {
16+
"type": "git",
17+
"url": "[email protected]:leezng/vue-json-pretty.git"
18+
},
19+
"homepage": "https://leezng.github.io/vue-json-pretty",
20+
"keywords": [
21+
"vue",
22+
"json",
23+
"format",
24+
"pretty",
25+
"vue-component"
26+
],
27+
"license": "MIT",
28+
"bugs": {
29+
"url": "https://github.com/leezng/vue-json-pretty/issues"
30+
},
1531
"dependencies": {
1632
"vue": "^2.3.0"
1733
},

src/components/checkbox.vue

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
<template>
2+
<!-- click.stop 避免向上冒泡触发 tree.vue 的 click 事件-->
3+
<label :class="[ 'vjs-checkbox', value ? 'is-checked': '' ]" @click.stop>
4+
<span :class="[ 'vjs-checkbox__input', value ? 'is-checked': '' ]">
5+
<span class="vjs-checkbox__inner"></span>
6+
<input
7+
class="vjs-checkbox__original"
8+
type="checkbox"
9+
:name="name"
10+
v-model="model"
11+
@change="$emit('change', model)"
12+
@focus="focus = true"
13+
@blur="focus = false">
14+
</span>
15+
</label>
16+
</template>
17+
18+
<script>
19+
export default {
20+
props: {
21+
name: String,
22+
value: {
23+
type: Boolean,
24+
default: false
25+
}
26+
},
27+
data () {
28+
return {
29+
focus: false,
30+
checked: false
31+
}
32+
},
33+
computed: {
34+
model: {
35+
get () {
36+
return this.value !== undefined ? this.value : this.checked
37+
},
38+
set (val) {
39+
this.checked = val
40+
this.$emit('input', val)
41+
}
42+
}
43+
}
44+
}
45+
</script>
46+
47+
<style lang="less">
48+
.vjs-checkbox {
49+
color: #1f2d3d;
50+
user-select: none;
51+
.vjs-checkbox__input {
52+
outline: 0;
53+
line-height: 1;
54+
vertical-align: middle;
55+
cursor: pointer;
56+
display: inline-block;
57+
position: relative;
58+
white-space: nowrap;
59+
&.is-checked .vjs-checkbox__inner {
60+
background-color: #20a0ff;
61+
border-color: #0190fe;
62+
&:after {
63+
transform: rotate(45deg) scaleY(1);
64+
}
65+
}
66+
}
67+
.vjs-checkbox__inner {
68+
display: inline-block;
69+
position: relative;
70+
border: 1px solid #bfcbd9;
71+
border-radius: 4px;
72+
box-sizing: border-box;
73+
width: 18px;
74+
height: 18px;
75+
background-color: #fff;
76+
z-index: 1;
77+
transition: border-color .25s cubic-bezier(.71,-.46,.29,1.46),background-color .25s cubic-bezier(.71,-.46,.29,1.46);
78+
&:after {
79+
box-sizing: content-box;
80+
content: "";
81+
border: 2px solid #fff;
82+
border-left: 0;
83+
border-top: 0;
84+
height: 8px;
85+
left: 5px;
86+
position: absolute;
87+
top: 1px;
88+
transform: rotate(45deg) scaleY(0);
89+
width: 4px;
90+
transition: transform .15s cubic-bezier(.71,-.46,.88,.6) .05s;
91+
transform-origin: center;
92+
}
93+
}
94+
.vjs-checkbox__original {
95+
opacity: 0;
96+
outline: 0;
97+
position: absolute;
98+
margin: 0;
99+
width: 0;
100+
height: 0;
101+
left: -999px;
102+
}
103+
}
104+
</style>

src/components/tree.vue

Lines changed: 72 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,19 @@
11
<template>
22
<div
33
class="vjs__tree"
4-
:style="{ 'background-color': treeContentBackground }"
5-
@click.stop="handleClick"
6-
@mouseover.stop="treeContentBackground = '#eee'"
7-
@mouseout.stop="treeContentBackground = 'transparent'">
4+
:style="{
5+
'background-color': treeContentBackground,
6+
'position': child ? '' : 'relative',
7+
'margin-left': !child && existCheckbox ? '30px' : ''
8+
}"
9+
@click.stop="handleClick($event)"
10+
@mouseover.stop="handleMouseover"
11+
@mouseout.stop="handleMouseout">
12+
13+
<template v-if="selectable && existCheckbox" class="vjs-checkbox">
14+
<checkbox v-model="checkboxVal" @change="handleClick($event, true)"></checkbox>
15+
</template>
16+
817
<template v-if="Array.isArray(data) || isObject(data)">
918
<!-- 左闭合 -->
1019
<brackets-left
@@ -25,6 +34,9 @@
2534
:parent-data="data"
2635
:data="item"
2736
:path="path + (Array.isArray(data) ? `[${index}]` : `.${index}`)"
37+
:path-checked="pathChecked"
38+
:path-selectable="pathSelectable"
39+
:selectable-type="selectableType"
2840
:index="index"
2941
:child="true"
3042
@click="handleItemClick">
@@ -51,12 +63,14 @@
5163
</template>
5264

5365
<script>
66+
import Checkbox from './checkbox'
5467
import BracketsLeft from './brackets-left'
5568
import BracketsRight from './brackets-right'
5669
5770
export default {
5871
name: 'tree',
5972
components: {
73+
Checkbox,
6074
BracketsLeft,
6175
BracketsRight
6276
},
@@ -68,15 +82,31 @@
6882
type: String,
6983
default: 'root'
7084
},
85+
// 定义已选中的数据层级
86+
pathChecked: {
87+
type: Array,
88+
default: () => []
89+
},
90+
// 定义某个数据层级是否支持选中操作
91+
pathSelectable: {
92+
type: Function,
93+
default: () => true
94+
},
95+
// 定义数据层级支持的选中方式, 默认所有方式均支持
96+
selectableType: {
97+
type: String,
98+
default: 'both' // both, checkbox, tree
99+
},
71100
/* 外部可用 END */
72101
parentData: {}, // 当前树的父级数据
73-
child: Boolean, // 是否子树
102+
child: Boolean, // 是否子树(优化: 通过 $parent?)
74103
index: {}
75104
},
76105
data () {
77106
return {
78107
visiable: true,
79-
treeContentBackground: 'transparent'
108+
treeContentBackground: 'transparent',
109+
checkboxVal: this.pathChecked.includes(this.path) // 复选框的值
80110
}
81111
},
82112
computed: {
@@ -88,16 +118,40 @@
88118
let arr = Object.keys(this.parentData)
89119
return arr[arr.length - 1]
90120
}
121+
},
122+
// 当前的树是否支持选中功能
123+
selectable () {
124+
return this.pathSelectable(this.path, this.data)
125+
},
126+
// 存在复选框
127+
existCheckbox () {
128+
return this.selectableType === 'both' || this.selectableType === 'checkbox'
129+
},
130+
// 存在mouseover
131+
existMouseover () {
132+
return this.selectableType === 'both' || this.selectableType === 'tree'
91133
}
92134
},
93135
methods: {
94-
// 触发组件的 click 事件
95-
handleClick () {
96-
this.$emit('click', this.path, this.data)
136+
/**
137+
* 触发组件的 click 事件
138+
* @param {Boolean} changed 复选框值是否已改变(如果来自复选框 change 事件则已改变)
139+
*/
140+
handleClick (e, changed = false) {
141+
// 由于 checkbox 也依赖该函数, 因此通过 changed 进行排除
142+
if (!changed && !this.existMouseover || !this.selectable) return
143+
changed || (this.checkboxVal = !this.checkboxVal)
144+
this.$emit('click', this.path, this.data, this.checkboxVal)
97145
},
98146
// 处理子树触发的 click 事件, 并传递到顶层
99-
handleItemClick (path, data) {
100-
this.$emit('click', path, data)
147+
handleItemClick (path, data, checked) {
148+
this.$emit('click', path, data, checked)
149+
},
150+
handleMouseover () {
151+
this.existMouseover && this.selectable && (this.treeContentBackground = '#eee')
152+
},
153+
handleMouseout () {
154+
this.existMouseover && this.selectable && (this.treeContentBackground = 'transparent')
101155
},
102156
// 工具函数: 判断是否对象
103157
isObject (value) {
@@ -117,10 +171,12 @@
117171
</script>
118172

119173
<style lang="less">
174+
@content-padding: 15px; /* 树的内容区域左留空*/
175+
120176
.vjs__tree {
121177
font-family: "Monaco", "Menlo", "Consolas", "Bitstream Vera Sans Mono";
122178
.vjs__tree__content {
123-
padding-left: 15px;
179+
padding-left: @content-padding;
124180
border-left: 1px dotted #ccc;
125181
}
126182
.vjs__tree__node {
@@ -147,5 +203,9 @@
147203
content: "\""
148204
}
149205
}
206+
.vjs-checkbox {
207+
position: absolute;
208+
left: -30px;
209+
}
150210
}
151211
</style>

src/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import VueJsonPretty from './components/tree.vue'
22

33
export default Object.assign({}, VueJsonPretty, {
4-
version: '1.2.0'
4+
version: '1.3.0'
55
})

0 commit comments

Comments
 (0)