How to convert a mention tag text to a <router-link> ? (VUEJS)

Viewed 1583

I have a body property in data

data(){
 return{
  body:'Hello im @username1 and @username2'
 }
}

I want to convert each @user into a code below, where a user can click that link to go that url path.

<router-link :to="`/${username1}`">@{{username1}}</router-link>

What i tried

<span v-html='bodyReplaced'>
  computed: {
    bodyReplaced(){
      return this.body.replace(
        /@\w+/g, 
        (user) => '<router-link :to="`/${username1}`">@{{username1}}</router-link>'
      )
    }
  }

What the code did:

  1. Convert the string into router-link in the dom but not in the view
  2. I dont know how to replace the @ after the match, so i can use it in to="`/${username1}
2 Answers

I think you're looking for something like

<template v-for="part of body.split(/(@\w+)/g)">
  <router-link v-if="part[0] == '@'" :to="`/${part.slice(1)}`">{{part}}</router-link>
  <template v-else>{{part}}</template>
</template>

new Vue({
  el: 'main',
  data: {
    body:'Hello im @username1 and @username2'
  },
  router: new VueRouter({
    routes: []
  }),
})
<main>
  <template v-for="part of body.split(/(@\w+)/g)">
    <router-link v-if="part[0] == '@'" :to="`/${part.slice(1)}`">{{part}}</router-link>
    <template v-else>{{part}}</template>
  </template>
</main>
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>

Create a component called mention and pass the user name as prop, i used the same approach of @Bergi, or you could replaced a computed property in which you replace the mention uder by a element which could be parsed not like router-link :

Vue.component('mention', {
  template: `<router-link :to="'/'+user">@{{user}}</router-link>`,
  props: ['user']
})
const Foo = {
  template: '<div>im foo</div>'
}
const Bar = {
  template: '<div>im bar</div>'
}
const routes = [{
    path: '/foo',
    component: Foo
  },
  {
    path: '/bar',
    component: Bar
  }
]

const router = new VueRouter({
  routes, // short for `routes: routes`,

})

// 4. Create and mount the root instance.
// Make sure to inject the router with the router option to make the
// whole app router-aware.
const app = new Vue({
  router,
  data() {
    return {
      body: 'Hello im @foo and @bar'
    }
  },

  computed: {
    tokens() {
      return this.body.split(' ');
    },
    bodyReplaced() {
      return this.body.split(' ').map(w => {
        return w.startsWith('@') ? `<a href="#/${w.slice(1)}">${w}</a>` : w;
      }).join(' ')
    }
  }
}).$mount('#app')
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>

<div id="app">
  <div>********The first solution********</div>

  <template v-for="token in tokens">
    
     <mention v-if="token.startsWith('@')" :user="token.slice(1)"></mention>
     <template v-else>&nbsp;{{token}}&nbsp;</template>
  </template>
  <div>********The second solution********</div>
  <span v-html='bodyReplaced'></span>
  <router-view></router-view>
</div>

Related