pagerender
Version:
113 lines (107 loc) • 2.97 kB
JavaScript
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)
}