admin管理员组

文章数量:1310420

I've read about 100 threads about this and still can't quite get it.

I'm trying to parse a string template from a backend API and render it, using custom ponents.

I have aliased esm build in vite.config.js:

  resolve: {
    alias: {
      '@': fileURLToPath(new URL('./src', import.meta.url)),
      vue: 'vue/dist/vue.esm-bundler.js',
    },
  },

Here is my ponent:

<script>
import { defineAsyncComponent, h } from 'vue';

export default {
  ponents: {
    PageCalculator: defineAsyncComponent(() => import('@/ponents/PageCalculator.vue')), /* eslint-disable-line */
  },
  props: {
    content: {
      type: String,
      default: '',
    },
  },
  render() {
    const render = {
      template: `<div class="content">${this.content}</div>`,
    };
    return h(render);
  },
};
</script>

This gives the error Failed to resolve ponent.

how can I go about dynamically loading the ponent? I have a large number of ponents that the backend can send back, so I wanted to lazily load them.

Here is how it's used from the outer ponent:

<app-page :title="page.title" container-class="w-full">
  <piled-content :content="page.content_html" />
</app-page>

The content of the HTML might look like this (the content prop):

<p>this is a nice sentence</p>
<page-calculator />
<p>this is a <router-link :to="{name: 'home'}">link</router-link></p>

I've read about 100 threads about this and still can't quite get it.

I'm trying to parse a string template from a backend API and render it, using custom ponents.

I have aliased esm build in vite.config.js:

  resolve: {
    alias: {
      '@': fileURLToPath(new URL('./src', import.meta.url)),
      vue: 'vue/dist/vue.esm-bundler.js',
    },
  },

Here is my ponent:

<script>
import { defineAsyncComponent, h } from 'vue';

export default {
  ponents: {
    PageCalculator: defineAsyncComponent(() => import('@/ponents/PageCalculator.vue')), /* eslint-disable-line */
  },
  props: {
    content: {
      type: String,
      default: '',
    },
  },
  render() {
    const render = {
      template: `<div class="content">${this.content}</div>`,
    };
    return h(render);
  },
};
</script>

This gives the error Failed to resolve ponent.

how can I go about dynamically loading the ponent? I have a large number of ponents that the backend can send back, so I wanted to lazily load them.

Here is how it's used from the outer ponent:

<app-page :title="page.title" container-class="w-full">
  <piled-content :content="page.content_html" />
</app-page>

The content of the HTML might look like this (the content prop):

<p>this is a nice sentence</p>
<page-calculator />
<p>this is a <router-link :to="{name: 'home'}">link</router-link></p>
Share Improve this question edited Apr 23, 2023 at 21:40 Tallboy asked Apr 23, 2023 at 21:32 TallboyTallboy 13.5k13 gold badges93 silver badges189 bronze badges 3
  • where are you using PageCalculator? – Boussadjra Brahim Commented Apr 23, 2023 at 21:34
  • @BoussadjraBrahim i edited my question. its HTML ing in as a prop – Tallboy Commented Apr 23, 2023 at 21:41
  • Have you tried defining the src alias with path? alias: { '@': path.resolve(__dirname, './src') }. I haven't seen a configuration like yours before. – Samuel Eiche Commented Apr 24, 2023 at 8:14
Add a ment  | 

2 Answers 2

Reset to default 9

Wow, this was such a painful journey, yet the answer is so simple.

here is how you render vue ponents from the server dynamically, even if they're mixed within html

I'm extremely surprised the answer is not in more places... people had me registering global ponents, using methods that didnt't work. I actually eventually just stumbled across it on my own while trying to piece together tons of different answers.

Here's the final version that:

  1. piles vue code in realtime from the server
  2. does so with ponents and methods IN that ponent, without requiring global ponents
<script>
import { h } from 'vue';
import AppAlert from '@/ponents/AppAlert.vue';

export default {
  props: {
    content: {
      type: String,
      default: '',
    },
  },
  render() {
    const r = {
      ponents: {
        AppAlert,
      },
      template: `<div class="content">${this.content || ''}</div>`,
      methods: {
        hello() {
          // method "hello" is also available here
        },
      },
    };
    return h(r);
  },
};
</script>

If you have tons of ponents in your content you can also make them all async ponents:

ponents: {
  AppAlert: defineAsyncComponent(() => import('@/ponents/AppAlert.vue')), 
  ...

You should better use Vue slots for content instead of props

And you should also not interpolate HTML, since it will not work with ponents.

template: `<div class="content">${this.content}</div>`,

Use Vue Render Functions instead.

const { createApp, h, defineAsyncComponent  } = Vue;

const test = { template: 'Test' }
const PageCalculator = 
  defineAsyncComponent(() => {
    return new Promise((resolve, reject) => {                
       resolve( { template: 'My PageCalculator' } )
    })
  })

const CompiledContent = {
  template: 'Slot: <slot></slot>'  
}

const App = { 
  ponents:  {CompiledContent, PageCalculator }
}

const app = createApp(App)
const vm = app.mount('#app')
#app { line-height: 2; }
[v-cloak] { display: none; }
<div id="app" v-cloak>
 <piled-content><page-calculator></page-calculator></piled-content>
</div>
<script src="https://unpkg./vue@3/dist/vue.global.prod.js"></script>

本文标签: javascriptVue 3 h() with custom componentStack Overflow