Vue components / elements in v-html

Viewed 3286

I have a post.text data that contains the text of a blog post submitted by the user Much like in Twitter, users can mention other users with the sintax I am tagging @user1 in this post. When rendering the post, I want to replace all the @username instances with links to the page of the mentioned user.

With a regex match / replace I can easily transform the mentioned @username into something like (I'm using vue-router):

I am tagging <router-link :to="{name: 'user', params: {userId: post.userId}}">{{ dPost.user_name }}</router-link> in this post

But when I use it like this:

<p v-html="preparedText"></p>

vue doesn't reprocess the html to bind its own tags.

How to solve this problem? Thanks

2 Answers

What you want to do sortof breaks the normal Vue paradigm, but it can be done using Vue.compile. You'll need to use Vue.compile to generate the render functions and then manually create a new Vue instance once your component has been mounted.

Here's an example:

Vue.component('post', {
  template: `<div></div>`,
  props: { text: String },
  mounted() {
    let regex = /\B\@([\w\-]+)/gim;
    let username = this.text.match(regex)[0];
    let linkText = this.text.replace(regex, `<a href="#">${username}</a>`);
    let res = Vue.compile(`<p>${linkText}</p>`);
    
    let { render, staticRenderFns } = res;
    new Vue({ el: this.$el, render, staticRenderFns })
  }
})

new Vue({
  el: '#app',
  data() {
    return { text: `Hi @user1, how are you?` }
  }
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.4.4/vue.min.js"></script>
<div id="app">
  <post :text="text"></post>
</div>

You don't need to use v-html.

To dynamically render your components, simply use :is="your component name".

Related