UNPKG

pagerender

Version:

113 lines (107 loc) 2.97 kB
import { computed, getCurrentInstance,defineComponent,Suspense,createVNode } from "vue"; import loading from './loading.vue' let flag = false export default function(props,ctx){ const components = getCurrentInstance().appContext.components const {emit} = ctx const bindModel = computed({ get:()=>props.modelValue, set:newValue=>emit('update:modelValue',newValue) }) const resolveModelField = (value)=>{ if(typeof(value) === 'string'){ return value.split('.')[1] } return value } const resolveModelValue = (value)=>{ if(typeof(value) === 'string'){ const key = value.split('.') if(key[0] === 'model'){ return props.modelValue[key[1]] } if(key[0] === 'source'){ if(props.source){ if(!flag){ bindModel.value[key[1]] = props.source[key[1]] flag = true } return bindModel.value[key[1]] }else{ console.warn('source is undefined') } } } return value } const emitModel = (value,field)=>{ bindModel.value[resolveModelField(field.value)] = value emit('change',props.modelValue) } //解析Props const resolveProps = (field)=>{ const sysComponent = components[field.component] // if(sysComponent){ // console.log(sysComponent) // } let prop = field.props if(field.value){ prop = { modelValue:resolveModelValue(field.value), 'onUpdate:modelValue':(value)=>emitModel(value,field), value:resolveModelValue(field.value), ...prop, } } if(field.component === 'input' || field.component === 'textarea'){ prop = { onInput:($event)=>emitModel($event.target.value,field), ...prop, } } if(field.component === 'select'){ prop = { onChange:($event)=>emitModel($event.target.value,field), ...prop, } } return prop } //解析slot子集 const resolveSlot = (field)=>{ let slot = {} let defaultSlot = [] if(field.slots){ Object.keys(field.slots).map(key=>{ slot[key] = ()=>createDom(field.slots[key]) }) } if(field.text){ defaultSlot.push(resolveModelValue(field.text)) } if(field.children && field.children.length){ defaultSlot = [...defaultSlot,...createDom(field.children)] } slot.default = ()=>defaultSlot return slot } const createDom = (data)=>{ return data.map(item=>{ return composeVNode(item) }) } const composeVNode = (field)=>{ const sysComponent = components[field.component] const component = sysComponent || field.component const fieldProps = resolveProps(field) const fieldSlot = resolveSlot(field) return createVNode(component,fieldProps,fieldSlot) } const createPage = (pageProps)=>{ return createVNode(Suspense,null,{ default:()=>createVNode('div',{class:pageProps.class},createDom(pageProps.elements)), fallback:()=>createVNode(loading) }) } return createPage(props) }