如何在自定义render函数中使用Vue.compile?动态模板警告消除
问题描述
我编写了一个简单组件,代码如下:
const { compile } = Vue; let f1 = compile('<p>{{abc}}</p>'); let f2 = function (_ctx, _cache) { let c = compile('<p>{{ abc }}</p>'); return c(_ctx, _cache); } const component = { data() { return { abc: 'Hello ABC' } }, render: f2 } Vue.createApp(component).mount('#app');
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script> <div id="app"></div>
当将组件的render选项设为f1时一切正常,但设为f2时会出现警告:"Property undefined was accessed during render but is not defined on instance.",不过abc仍能正常渲染。我希望使用f2实现动态模板渲染,请问如何消除该警告?或者有更优的动态模板渲染方式?
解决方案
警告原因
f2中每次调用render都会重新编译模板生成新的渲染函数,新渲染函数未与当前组件的缓存系统正确绑定,导致Vue依赖追踪逻辑误判,触发未定义属性警告。
方法1:缓存编译后的渲染函数
避免在render内重复编译模板,用缓存存储已编译的渲染函数,仅在模板变化时重新编译:
const { compile } = Vue; // 缓存编译结果 const renderCache = {}; let f2 = function (_ctx, _cache) { const template = '<p>{{ abc }}</p>'; if (!renderCache[template]) { renderCache[template] = compile(template); } return renderCache[template](_ctx, _cache); } const component = { data() { return { abc: 'Hello ABC' } }, render: f2 } Vue.createApp(component).mount('#app');
方法2:封装动态模板组件(更优方案)
将动态模板逻辑封装为独立组件,符合Vue组件化思想,同时支持模板动态切换:
const { compile, createApp, defineComponent, h, markRaw } = Vue; const DynamicTemplate = defineComponent({ props: { template: { type: String, required: true }, // 传递需要在模板中使用的上下文属性 context: { type: Object, default: () => ({}) } }, setup(props) { const renderCache = {}; return () => { const { template, context } = props; if (!renderCache[template]) { // 标记为原始值避免被响应式包装 renderCache[template] = markRaw(compile(template)); } return renderCache[template](context, null); }; } }); const component = { data() { return { abc: 'Hello ABC', currentTemplate: '<p>{{ abc }}</p>' } }, render() { return h(DynamicTemplate, { template: this.currentTemplate, context: { abc: this.abc } }); } } createApp(component).mount('#app');
方法3:显式绑定上下文(不推荐)
通过with语句强制将渲染函数的上下文绑定到组件实例,但with会影响性能和可读性,且严格模式下禁用:
let f2 = function (_ctx, _cache) { let c = compile('<p>{{ abc }}</p>'); with(_ctx) { return c(_ctx, _cache); } }
内容的提问来源于stack exchange,提问作者Wenjian Li
相关产品推荐
相关产品推荐

