Skip to content

Commit

Permalink
feat:json表单中支持——__methods__方法
Browse files Browse the repository at this point in the history
  • Loading branch information
JakHuang committed Jul 12, 2020
1 parent c9c6ea2 commit 81b4c7a
Show file tree
Hide file tree
Showing 4 changed files with 169 additions and 75 deletions.
83 changes: 51 additions & 32 deletions src/components/parser/Parser.vue
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,39 @@ const ruleTrigger = {
'el-rate': 'change'
}
const layouts = {
colFormItem(h, scheme) {
const config = scheme.__config__
const listeners = buildListeners.call(this, scheme)
let labelWidth = config.labelWidth ? `${config.labelWidth}px` : null
if (config.showLabel === false) labelWidth = '0'
return (
<el-col span={config.span}>
<el-form-item label-width={labelWidth} prop={scheme.__vModel__}
label={config.showLabel ? config.label : ''}>
<render conf={scheme} {...{ on: listeners }} />
</el-form-item>
</el-col>
)
},
rowFormItem(h, scheme) {
let child = renderChildren.apply(this, arguments)
if (scheme.type === 'flex') {
child = <el-row type={scheme.type} justify={scheme.justify} align={scheme.align}>
{child}
</el-row>
}
return (
<el-col span={scheme.span}>
<el-row gutter={scheme.gutter}>
{child}
</el-row>
</el-col>
)
}
}
function renderFrom(h) {
const { formConfCopy } = this
Expand Down Expand Up @@ -63,38 +96,24 @@ function renderChildren(h, scheme) {
return renderFormItem.call(this, h, config.children)
}
const layouts = {
colFormItem(h, scheme) {
const config = scheme.__config__
let labelWidth = config.labelWidth ? `${config.labelWidth}px` : null
if (config.showLabel === false) labelWidth = '0'
return (
<el-col span={config.span}>
<el-form-item label-width={labelWidth} prop={scheme.__vModel__}
label={config.showLabel ? config.label : ''}>
<render conf={scheme} onInput={ event => {
this.$set(config, 'defaultValue', event)
this.$set(this[this.formConf.formModel], scheme.__vModel__, event)
}} />
</el-form-item>
</el-col>
)
},
rowFormItem(h, scheme) {
let child = renderChildren.apply(this, arguments)
if (scheme.type === 'flex') {
child = <el-row type={scheme.type} justify={scheme.justify} align={scheme.align}>
{child}
</el-row>
}
return (
<el-col span={scheme.span}>
<el-row gutter={scheme.gutter}>
{child}
</el-row>
</el-col>
)
}
function setValue(event, config, scheme) {
this.$set(config, 'defaultValue', event)
this.$set(this[this.formConf.formModel], scheme.__vModel__, event)
}
function buildListeners(scheme) {
const config = scheme.__config__
const methods = this.formConf.__methods__ || {}
const listeners = {}
// 给__methods__中的方法绑定this和event
Object.keys(methods).forEach(key => {
listeners[key] = event => methods[key].call(this, event)
})
// 响应 render.js 中的 vModel $emit('input', val)
listeners.input = event => setValue.call(this, event, config, scheme)
return listeners
}
export default {
Expand Down
40 changes: 40 additions & 0 deletions src/components/parser/example/Index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -135,8 +135,48 @@ export default {
type: 'default',
justify: 'start',
align: 'top'
},
{
__config__: {
label: '按钮',
showLabel: true,
changeTag: true,
labelWidth: null,
tag: 'el-button',
tagIcon: 'button',
span: 24,
layout: 'colFormItem',
document: 'https://element.eleme.cn/#/zh-CN/component/button',
renderKey: 1594288459289
},
__slot__: {
default: '测试按钮1'
},
type: 'primary',
icon: 'el-icon-search',
round: false,
size: 'medium',
plain: false,
circle: false,
disabled: false,
on: {
click: 'clickTestButton1'
}
}
],
__methods__: {
clickTestButton1() {
console.log(
`%c【测试按钮1】点击事件里可以访问当前表单:
1) formModel='formData', 所以this.formData可以拿到当前表单的model
2) formRef='elForm', 所以this.$refs.elForm可以拿到当前表单的ref(vue组件)
`,
'color:#409EFF;font-size: 15px'
)
console.log('表单的Model:', this.formData)
console.log('表单的ref:', this.$refs.elForm)
}
},
formRef: 'elForm',
formModel: 'formData',
size: 'small',
Expand Down
117 changes: 77 additions & 40 deletions src/components/render/render.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,5 @@
import { deepClone } from '@/utils/index'

function vModel(self, dataObject, defaultValue) {
dataObject.props.value = defaultValue

dataObject.on.input = val => {
self.$emit('input', val)
}
}

const componentChild = {}
/**
* 将./slots中的文件挂载到对象componentChild上
Expand All @@ -22,46 +14,91 @@ keys.forEach(key => {
componentChild[tag] = value
})

function vModel(dataObject, defaultValue) {
dataObject.props.value = defaultValue

dataObject.on.input = val => {
this.$emit('input', val)
}
}

function mountSlotFlies(h, confClone, children) {
const childObjs = componentChild[confClone.__config__.tag]
if (childObjs) {
Object.keys(childObjs).forEach(key => {
const childFunc = childObjs[key]
if (confClone.__slot__ && confClone.__slot__[key]) {
children.push(childFunc(h, confClone, key))
}
})
}
}

function emitEvents(confClone) {
['on', 'nativeOn'].forEach(attr => {
const eventKeyList = Object.keys(confClone[attr] || {})
eventKeyList.forEach(key => {
const val = confClone[attr][key]
if (typeof val === 'string') {
confClone[attr][key] = event => this.$emit(val, event)
}
})
})
}

function buildDataObject(confClone, dataObject) {
Object.keys(confClone).forEach(key => {
const val = confClone[key]
if (key === '__vModel__') {
vModel.call(this, dataObject, confClone.__config__.defaultValue)
} else if (dataObject[key]) {
dataObject[key] = { ...dataObject[key], ...val }
} else {
dataObject.attrs[key] = val
}
})

// 清理属性
clearAttrs(dataObject)
}

function clearAttrs(dataObject) {
delete dataObject.attrs.__config__
delete dataObject.attrs.__slot__
delete dataObject.attrs.__methods__
}

function makeDataObject() {
return {
attrs: {},
props: {},
nativeOn: {},
on: {},
style: {}
}
}

export default {
render(h) {
const dataObject = {
attrs: {},
props: {},
nativeOn: {},
on: {},
style: {}
props: {
conf: {
type: Object,
required: true
}
},
render(h) {
const dataObject = makeDataObject()
const confClone = deepClone(this.conf)
const children = []

// 如果slots文件夹存在与当前tag同名的文件,则执行文件中的代码
const childObjs = componentChild[confClone.__config__.tag]
if (childObjs) {
Object.keys(childObjs).forEach(key => {
const childFunc = childObjs[key]
if (confClone.__slot__ && confClone.__slot__[key]) {
children.push(childFunc(h, confClone, key))
}
})
}
mountSlotFlies.call(this, h, confClone, children)

// 将json表单配置转化为vue render可以识别的 “数据对象(dataObject)”
Object.keys(confClone).forEach(key => {
const val = confClone[key]
if (key === '__vModel__') {
vModel(this, dataObject, confClone.__config__.defaultValue)
} else if (dataObject[key]) {
dataObject[key] = { ...dataObject[key], ...val }
} else {
dataObject.attrs[key] = val
}
})
// 将字符串类型的事件,发送为消息
emitEvents.call(this, confClone)

// 清理属性
delete dataObject.attrs.__config__
delete dataObject.attrs.__slot__
// 将json表单配置转化为vue render可以识别的 “数据对象(dataObject)”
buildDataObject.call(this, confClone, dataObject)

return h(this.conf.__config__.tag, dataObject, children)
},
props: ['conf']
}
}
4 changes: 1 addition & 3 deletions src/views/index/JsonDrawer.vue
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,7 @@ export default {
props: {
jsonStr: {
type: String,
required: true,
beautifier: null,
jsonEditor: null
required: true
}
},
data() {
Expand Down

0 comments on commit 81b4c7a

Please sign in to comment.