vue3 compile模板字符串解析
最近有需要动态展示form表单的情况,为了偷懒用编辑器动态修改,但是储存的内容确是静态的字符串,比对了2的写法,发现vue3中解析略有不同,自己记录下
compile
compile 返回一个 compileToFunctions
compileToFunctions 只返回Javascript代码,经过编译返回的render函数如下
(function anonymous(Vue
) {
const _Vue = Vue
const { } = _Vue
const _hoisted_1 = ["onUpdate:modelValue"]
return function render(_ctx, _cache) {
with (_ctx) {
const { vModelText: _vModelText, withDirectives: _withDirectives, openBlock: _openBlock, createElementBlock: _createElementBlock } = _Vue
return _withDirectives((_openBlock(), _createElementBlock("input", {
"onUpdate:modelValue": $event => ((this.formData.a1) = $event)
}, null, 8 /* PROPS */, _hoisted_1)), [
[_vModelText, this.formData.a1]
])
}
}
})
注意点:
- 在 template SFC模式下 v-model:value="formData.xxx",在解析的函数体内,默认没有对应的对象 formData,会有大量警告
通过调用 rdx.call(this, this) ,字符模板加上this.formData.xxx
- 字符模板动态修改在setup中固定,不要到render中修改,否则双向绑定的数据会不断触发render
<template>
<tableInput ref="questionRef" v-model:value="dataInfo" :template="temple" v-if="temple"></tableInput>
</template>
<script>
import { toRefs, reactive } from 'vue'
import tableInput from './tableInput.jsx'
export default {
name: 'Login',
components: { tableInput },
setup (props, context) {
let _data = reactive({
questionRef: null,
dataInfo: {},
temple: `<table border="0" width="100%" cellpadding="0" cellspacing="0"><tbody><tr><th>项目</th><th>分数</th><th>项目</th><th>分数</th></tr><tr><td>是否</td><td>a1</td><td>是否8</td><td>a8</td></tr><tr><td>是否2</td><td>a2</td><td>是否9</td><td>a9</td></tr><tr><td>是否3</td><td>a3</td><td>是否10</td><td>a10</td></tr><tr><td>是否4</td><td>a4</td><td>是否11</td><td>a11</td></tr><tr><td>是否5</td><td>a5</td><td>是否12</td><td>a12</td></tr><tr><td>是否6</td><td>a6</td><td></td><td></td></tr><tr><td>是否7</td><td>a7</td><td></td><td></td></tr></tbody></table>`
})
for (let i = 1; i <= 12; i++) {
_data.dataInfo['a' + i] = ''
}
return {
...toRefs(_data),
}
},
}
</script>
- tableInput.jsx
import { watch, reactive, defineComponent, ref, compile, toRefs, getCurrentInstance } from "vue";
const App = defineComponent({
props: {
value: {
type: Object,
default () {
return {}
}
},
template: {
type: String
}
},
setup (props,context) {
let _data = reactive({
formData: JSON.parse(JSON.stringify(props.value)),
tempInfo: ''
})
let info = props.template
for (const key in _data.formData) {
info = info.replace(key, `<a-input v-model:value="this.formData.${key}" />`)
}
_data.tempInfo = info
// info = `<div><input type="text" v-model="formData.test" />{{formData}}</div> `
let _methods = {
getInfo () {
return _data.formData
}
}
watch(()=>_data.formData,(value)=>{
context.emit('update:value',_data.formData)
},{deep:true})
return {
...toRefs(_data),
..._methods
}
},
render () {
let rdx = compile(this.tempInfo)
return rdx.call(this, this)
}
});
export default App