mirror of
https://github.com/Ssl1S/json-schema-editor-vue.git
synced 2025-12-30 01:37:55 +08:00
核心功能开发
This commit is contained in:
@@ -1,22 +1,28 @@
|
|||||||
<template>
|
<template>
|
||||||
<div id="app">
|
<div id="app">
|
||||||
<json-schema-editor/>
|
<json-schema-editor :disabled="true" :value="tree" :root="true" style="width:600px"/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
name: 'App'
|
name: 'App',
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
tree:{
|
||||||
|
root: {
|
||||||
|
type: "object",
|
||||||
|
title: "title",
|
||||||
|
properties: {
|
||||||
|
field_1: {
|
||||||
|
type: "string"
|
||||||
|
},
|
||||||
|
},
|
||||||
|
required: ["field_1"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
|
||||||
#app {
|
|
||||||
font-family: Avenir, Helvetica, Arial, sans-serif;
|
|
||||||
-webkit-font-smoothing: antialiased;
|
|
||||||
-moz-osx-font-smoothing: grayscale;
|
|
||||||
text-align: center;
|
|
||||||
color: #2c3e50;
|
|
||||||
margin-top: 60px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|||||||
@@ -1,10 +1,17 @@
|
|||||||
import Vue from 'vue'
|
import Vue from 'vue'
|
||||||
import App from './App.vue'
|
import App from './App.vue'
|
||||||
import JsonSchemaEditor from '../packages/json-schema-editor/index'
|
import JsonSchemaEditor from '../packages/json-schema-editor/index'
|
||||||
|
// import { Row, Col, Input, Icon,Checkbox,Button,Select } from 'ant-design-vue'
|
||||||
Vue.config.productionTip = false
|
Vue.config.productionTip = false
|
||||||
|
|
||||||
Vue.use(JsonSchemaEditor)
|
Vue.use(JsonSchemaEditor)
|
||||||
|
// Vue.use(Row)
|
||||||
|
// Vue.use(Col)
|
||||||
|
// Vue.use(Input)
|
||||||
|
// Vue.use(Icon)
|
||||||
|
// Vue.use(Checkbox)
|
||||||
|
// Vue.use(Button)
|
||||||
|
// Vue.use(Select)
|
||||||
new Vue({
|
new Vue({
|
||||||
render: h => h(App),
|
render: h => h(App),
|
||||||
}).$mount('#app')
|
}).$mount('#app')
|
||||||
|
|||||||
@@ -1,19 +1,219 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="json-schema-editor">
|
<div class="form-recursion">
|
||||||
json-schema-editor
|
<a-row class="row" :gutter="10">
|
||||||
<a-input/>
|
<a-col :span="8" class="ant-col-name">
|
||||||
<a-button type="primary">测试按钮</a-button>
|
<div :style="{marginLeft:`${20*deep}px`}" class="ant-col-name-c">
|
||||||
<a-icon type="step-backward" />
|
<a-button v-if="pickValue.type==='object'" type="link" :icon="hidden?'caret-right':'caret-down'" style="color:rgba(0,0,0,.65)" @click="hidden = !hidden"/>
|
||||||
|
<span v-else style="width:32px;display:inline-block"></span>
|
||||||
|
<a-input :disabled="disabled" :value="pickKey" class="ant-col-name-input" @input="onInputName"/>
|
||||||
|
</div>
|
||||||
|
<a-checkbox v-if="root" :disabled="!isObject && !isArray" class="ant-col-name-required" @change="onRootCheck"/>
|
||||||
|
<a-checkbox v-else :disabled="isItem" :checked="checked" class="ant-col-name-required" @change="onCheck"/>
|
||||||
|
</a-col>
|
||||||
|
<a-col :span="4">
|
||||||
|
<a-select v-model="pickValue.type" class="ant-col-type" @change="onChangeType">
|
||||||
|
<a-select-option :key="t" v-for="t in TYPE">
|
||||||
|
{{t}}
|
||||||
|
</a-select-option>
|
||||||
|
</a-select>
|
||||||
|
</a-col>
|
||||||
|
<a-col>
|
||||||
|
<a-input v-model="pickValue.title" class="ant-col-title" placeholder="标题"/>
|
||||||
|
</a-col>
|
||||||
|
<a-col :span="6" class="ant-col-setting">
|
||||||
|
<a-tooltip>
|
||||||
|
<span slot="title">设置属性</span>
|
||||||
|
<a-button type="link" icon="setting" class="setting-icon"/>
|
||||||
|
</a-tooltip>
|
||||||
|
<a-tooltip v-if="isObject">
|
||||||
|
<span slot="title">添加子节点</span>
|
||||||
|
<a-button type="link" icon="plus" class="plus-icon" @click="addChild"/>
|
||||||
|
</a-tooltip>
|
||||||
|
<a-tooltip v-if="!root && !isItem">
|
||||||
|
<span slot="title">删除节点</span>
|
||||||
|
<a-button type="link" class="close-icon ant-btn-icon-only" @click="removeNode">
|
||||||
|
<i aria-label="icon: plus" class="anticon anticon-plus">
|
||||||
|
<svg viewBox="64 64 896 896" data-icon="plus" width="1em" height="1em" fill="currentColor" aria-hidden="true" focusable="false" class=""><path d="M810.666667 273.493333L750.506667 213.333333 512 451.84 273.493333 213.333333 213.333333 273.493333 451.84 512 213.333333 750.506667 273.493333 810.666667 512 572.16 750.506667 810.666667 810.666667 750.506667 572.16 512z" p-id="1142"></path></svg>
|
||||||
|
</i>
|
||||||
|
</a-button>
|
||||||
|
</a-tooltip>
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
|
<template v-if="!hidden&&pickValue.properties && !isArray">
|
||||||
|
<json-schema-editor v-for="(item,key,index) in pickValue.properties" :value="{[key]:item}" :parent="pickValue" :key="index" :deep="deep+1" class="children"/>
|
||||||
|
</template>
|
||||||
|
<template v-if="isArray">
|
||||||
|
<json-schema-editor :value="{items:pickValue.items}" :deep="deep+1" disabled isItem class="children"/>
|
||||||
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
import { Button, Input, Icon } from 'ant-design-vue'
|
import TYPE from './type/type'
|
||||||
|
import { Row,Col,Button,Input, Icon,Checkbox,Select,Tooltip } from 'ant-design-vue'
|
||||||
|
import { clearAttr } from './util'
|
||||||
export default {
|
export default {
|
||||||
name: 'JsonSchemaEditor',
|
name:'JsonSchemaEditor',
|
||||||
components: {
|
components: {
|
||||||
|
ARow:Row,ACol:Col,
|
||||||
AButton: Button,
|
AButton: Button,
|
||||||
|
// eslint-disable-next-line vue/no-unused-components
|
||||||
|
AIcon: Icon,
|
||||||
AInput: Input,
|
AInput: Input,
|
||||||
AIcon:Icon
|
ACheckbox: Checkbox,
|
||||||
|
ASelect: Select,
|
||||||
|
ASelectOption:Select.Option,
|
||||||
|
ATooltip: Tooltip,
|
||||||
|
},
|
||||||
|
props:{
|
||||||
|
value: Object,
|
||||||
|
disabled: { //name不可编辑,根节点name不可编辑,数组元素name不可编辑
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
isItem: { //是否数组元素
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
deep:{ // 节点深度,根节点deep=0
|
||||||
|
type:Number,
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
root:{ //是否root节点
|
||||||
|
type:Boolean,
|
||||||
|
default:false
|
||||||
|
},
|
||||||
|
parent: { //父节点
|
||||||
|
type: Object,
|
||||||
|
default: null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
pickValue(){
|
||||||
|
return Object.values(this.value)[0]
|
||||||
|
},
|
||||||
|
pickKey(){
|
||||||
|
return Object.keys(this.value)[0]
|
||||||
|
},
|
||||||
|
isObject(){
|
||||||
|
return this.pickValue.type === 'object'
|
||||||
|
},
|
||||||
|
isArray(){
|
||||||
|
return this.pickValue.type === 'array'
|
||||||
|
},
|
||||||
|
checked(){
|
||||||
|
return this.parent && this.parent.required && this.parent.required.indexOf(this.pickKey) >= 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data(){
|
||||||
|
return {
|
||||||
|
TYPE,
|
||||||
|
hidden:false,
|
||||||
|
countAdd: 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted(){
|
||||||
|
console.info(this.value)
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
onInputName(event){
|
||||||
|
clearAttr(this.value)
|
||||||
|
console.info(event)
|
||||||
|
},
|
||||||
|
onInputTitle(event){
|
||||||
|
this.title = event.target.value
|
||||||
|
},
|
||||||
|
onChangeType() {
|
||||||
|
this.$delete(this.pickValue,'properties')
|
||||||
|
this.$delete(this.pickValue,'required')
|
||||||
|
if(this.isArray){
|
||||||
|
this.$set(this.pickValue,'items',{type:'string'})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onCheck(e){
|
||||||
|
this._checked(e.target.checked,this.parent)
|
||||||
|
},
|
||||||
|
onRootCheck(e){
|
||||||
|
const checked = e.target.checked
|
||||||
|
this._deepCheck(checked,this.pickValue)
|
||||||
|
},
|
||||||
|
_deepCheck(checked,node){
|
||||||
|
if(node.type === 'object'){
|
||||||
|
checked ? this.$set(node,'required',Object.keys(node.properties)) : this.$delete(node,'required')
|
||||||
|
Object.keys(node.properties).forEach(key => this._deepCheck(checked,node.properties[key]))
|
||||||
|
} else if(node.type === 'array'){
|
||||||
|
checked ? this.$set(node.items,'required',Object.keys(node.items.properties)) : this.$delete(node.items,'required')
|
||||||
|
Object.keys(node.items.properties).forEach(key => this._deepCheck(checked,node.items.properties[key]))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_checked(checked,parent){
|
||||||
|
let required = parent.required
|
||||||
|
if(checked){
|
||||||
|
required || this.$set(this.parent,'required',[])
|
||||||
|
|
||||||
|
required = this.parent.required
|
||||||
|
required.indexOf(this.pickKey) === -1 && required.push(this.pickKey)
|
||||||
|
}else{
|
||||||
|
const pos = required.indexOf(this.pickKey)
|
||||||
|
pos >=0 && required.splice(pos,1)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
addChild(){
|
||||||
|
const name = this._joinName()
|
||||||
|
const type = 'string'
|
||||||
|
const node = this.pickValue
|
||||||
|
node.properties || this.$set(node,'properties',{})
|
||||||
|
const props = node.properties
|
||||||
|
this.$set(props,name,{type: type})
|
||||||
|
console.info(this.value)
|
||||||
|
},
|
||||||
|
removeNode(){
|
||||||
|
const { properties,required } = this.parent
|
||||||
|
console.info(properties,required)
|
||||||
|
this.$delete(properties,this.pickKey)
|
||||||
|
if(required){
|
||||||
|
const pos = required.indexOf(this.pickKey)
|
||||||
|
pos >=0 && required.splice(pos,1)
|
||||||
|
required.length === 0 && this.$delete(this.parent,'required')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_joinName(){
|
||||||
|
return `feild_${this.deep}_${this.countAdd++}`
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.form-recursion{
|
||||||
|
width:100%;
|
||||||
|
.row{
|
||||||
|
display: flex;
|
||||||
|
margin:12px;
|
||||||
|
.ant-col-name{
|
||||||
|
display:flex;
|
||||||
|
align-items:center;
|
||||||
|
.ant-col-name-c{
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.ant-col-name-required{
|
||||||
|
margin-left:6px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.ant-col-type{
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.ant-col-setting{
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
.setting-icon{
|
||||||
|
color:rgba(0,0,0,.45);
|
||||||
|
}
|
||||||
|
.plus-icon{
|
||||||
|
color:#5B8FF9;
|
||||||
|
}
|
||||||
|
.close-icon{
|
||||||
|
color:#E8684A
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
7
packages/json-schema-editor/type/object.js
Normal file
7
packages/json-schema-editor/type/object.js
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
const obj = {
|
||||||
|
type: 'object',
|
||||||
|
properties: [ 'properties', 'required' ],
|
||||||
|
enableChildren: true,
|
||||||
|
requireChildren: false
|
||||||
|
}
|
||||||
|
export { obj }
|
||||||
2
packages/json-schema-editor/type/type.js
Normal file
2
packages/json-schema-editor/type/type.js
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
const TYPE = ['string', 'number', 'integer','object', 'array', 'boolean']
|
||||||
|
export default TYPE
|
||||||
5
packages/json-schema-editor/util.js
Normal file
5
packages/json-schema-editor/util.js
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
export function clearAttr(obj) {
|
||||||
|
for(let key in obj){
|
||||||
|
delete obj[key]
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user