I have a Vue2 SPA page which is loading content from the server. It is editable by client in a CMS.
When user is adding relative link (lets say /about-us), this should be picked by Vue and treated as the menu link (which already has /about-us link).
However link to /about-us added in the content is reloading the whole page, so it is not picked as vue route.
How is it possible to attach router to such links?
What I did so far is changing the content in the backend response.
So I am essentially changing
<a href="/about-us">Text</a>
into
<router-link :to="{ path: '/about-us'}">Text</router-link>
Using:
function parseVueLinks($value)
{
$pattern = "/<a([^>]*) href=\\\"[^http|https|mailto|tel]([^\\\"]*)\"([^>]*)>(.*?)<(\\/a>)/";
$replace = "<router-link$1 :to=\"{ path: '$2'}\">$4</router-link>";
return preg_replace($pattern, $replace, $value);
}
Still no luck.
How is this possible?
If I understand you correctly your issue is not with the link parsing, this looks fine. You want to compile the resulting HTML so Vue router can kick in. There is a function Vue.compile
which can help you:
Vue.component('my-component', {
template: '<div></div>',
props: {
html: String
},
mounted() {
let { render, staticRenderFns } = Vue.compile(this.html);
new Vue({ el: this.$el, render, staticRenderFns, router })
}
});
With this component you can specify any HTML using the prop html
, which will then get compiled in the mounted
event and will replace the component template. Please note the router
being passed to new Vue()
, this is a reference to your Vue router, which is needed so all the <router-link>
tags in your HTML can be resolved.
Now you can use this component to compile your HTML like this:
<my-component :html="content"></my-component>
where var content = parseVueLinks('<a href="/about-us">Text</a>')
.
You can see a working example over here https://codepen.io/anon/pen/BmmjwV
I think your replacement regex is good but is missing one /
.
Indeed, after testing it, I see the result of parsing :
<a href="/about-us">Text</a>
outputs :
<router-link :to="{ path: 'about-us'}">Text</router-link>
instead of correct:
<router-link :to="{ path: '/about-us'}">Text</router-link>
(see about-us
instead of /about-us
)
Could you try this,please:
function parseVueLinks($value)
{
$pattern = "/<a([^>]*) href=\\\"[^http|https|mailto|tel]([^\\\"]*)\"([^>]*)>(.*?)<(\\/a>)/";
$replace = "<router-link$1 :to=\"{ path: '/$2'}\">$4</router-link>";
return preg_replace($pattern, $replace, $value);
}
The simplest regex pattern to do this is /<a href="([^>]*)">(.+)<\/a>/
.
Test example:
console.clear()
const parseVueLinks = ($value) => {
const re = /<a href="([^>]*)">(.+)<\/a>/g;
const matches = re.exec($value);
return `<router-link :to="{ path: '${matches[1]}'}">${matches[2]}</router-link>`
}
console.log(parseVueLinks('<a href="/about-us">Text</a>'))
console.log(parseVueLinks('<a href="http://google.com">Goooooogle</a>'))
function parseVueLinks($value)
{
$pattern = "/<a href="([^>]*)">(.+)<\/a>/";
$matches = [];
preg_match($pattern, $replace, $matches);
return "<router-link :to=\"{ path: '" + $matches[1] + "'}\">" + $matches[2] + "</router-link>";
}
I'm wondering about the presence of http|https|mailto|tel
in your regex, does this mean you want to do some validation on the link?
If so, using preg_match()
allows a second regex step to be performed on $matches[1]
before output. It would seem simpler to validate as a second step rather than using one big regex.
The issue is not in regex. It is in Vue not parsing content pulled from the server
This may not apply if you're using server side rendering, but this is how I apply links from content.
MyComponent.ts
<template>
<div class="row">
...
<router-link :to="'/' + measure.link" class="measure">
<i class="measure-icon fa fa-lg" :class="measure.icon" aria-hidden="true">
<span class="title">{{measure.title}}</span>
</i>
</router-link>
Here, measure
is an object that is fetched from the server. I you are fetching the full <router-link>
, that may work with a Dynamic Component but it seems like overkill, since you know the element will be a <router-link
.
Note, if there's also a problem with the server responding with 404 to the click, you can use hash-mode routing (default) by adding # before the link, e.g #/about-us
.
Alternatively, set history mode in the Vue router.
const router = new Router({
routes,
mode: 'history'
})
This requires the server to redirect to index.html
for a 404. See HTML History Mode.
Also, you then need to handle 404 in Vue with a catch-all route,
const routes = [
...
{ path: '*', component: NotFoundComponent },
]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With