我可以动态加载组件模板吗

问题描述 投票:0回答:2

是否可以从服务器动态加载模板(包括组件)?或者我可以在渲染之前更改模板吗?

我想让用户将自己的表单模板存储到数据库中,并根据模板id生成表单。

我尝试更改

this.$options.template
,但似乎只适用于vue2。

<!-- static/myproj/js/my-field.vue -->
<template>
<label :for="name+'Fld'" v-html="title"></label>
<input :name="name" :type="text" :value="value" :id="name+'Fld'"/>
</template>

<script>
export default{
  props: {
    name: {type:String, required:true},
    value: {type:String, required:false, default:''},
    type:  {type:String, required:true},
    title: {type:String, required:false, default:'Field: '},
  },
  data: function(){ return {}; },
}
</script>
// index.vue
const loadVueModuleOpts= {
   moduleCache: {vue: Vue},  
   async getFile(url) {
     const res = await fetch(url);
     if ( !res.ok )
       throw Object.assign(new Error(res.statusText + ' ' + url), { res }); 
     return {
       getContentData: asBinary => asBinary ? res.arrayBuffer() : res.text(),
     }   
   },
};

export default{
   props: {
      id:            {required:true, type:String, default:'abcdefg'},
   }, 

   data: function(){
      this.loadSource();
      return {
         source:     null,
         target:     null,
      };
   },

   template: '<div>I\'m here to be replaced.</div>',

   created: async function(){
      this.$options.template=await axios.get(`/api/template/${id}`).then(resp=>resp.data);
   },

   components: {
      'my-field': Vue.defineAsyncComponent( ()=>loadModule('/static/myproj/js/my-field.vue', loadVueModuleOpts)),
}
<!-- server response for /api/template/abcdefg -->
<form action="POST">
   <my-field name="name" title="Your Name: " type="text"/>
   <my-field name="email" title="Email: " type="email"/>
   <input type="submit"/><input type="reset"/>
</form>

谢谢。

vue-component vuejs3
2个回答
3
投票

终于,我找到了解决方案。根据Vue3:如何在Vue3中使用Vue.compile,我们可以像这样直接通过Vue3渲染模板:

// index.vue
import { h, compile } from 'vue';

const loadVueModuleOpts= {
   moduleCache: {vue: Vue},  
   async getFile(url) {
     const res = await fetch(url);
     if ( !res.ok )
       throw Object.assign(new Error(res.statusText + ' ' + url), { res }); 
     return {
       getContentData: asBinary => asBinary ? res.arrayBuffer() : res.text(),
     }   
   },
};

export default{
   props: {
      id:            {required:true, type:String, default:'abcdefg'},
   }, 

   data: function(){
      this.loadSource();
      return {
         source:     null,
         target:     null,
      };
   },

   // Magic here
   render: function(){
      if(this.target)
         return h(compile(this.target).bind(this));
      return h('div', 'Loading...');
   },

   created: async function(){
      this.$options.template=await axios.get(`/api/template/${id}`).then(resp=>resp.data);
   },

   components: {
      'my-field': Vue.defineAsyncComponent( ()=>loadModule('/static/myproj/js/my-field.vue', loadVueModuleOpts)),
   },
}

0
投票

您可以使用ESM动态导入

<script type="module">
    import { createApp } from 'https://unpkg.com/vue@3/dist/vue.esm-browser.prod.js'
    
    const { default: dynamic_module } = await import('path-to-component.js');

    createApp(dynamic_module).mount('#app')
</script>
<div id="app"></div>

在“path-to-component.js”中

export default {
  data() {
    return { count: 1 }
  },
  template: `<div>Count is: {{ count }}</div>`
}

最新问题
© www.soinside.com 2019 - 2025. All rights reserved.