Reputation: 612
I'm making a blog using Vue and am using vue-highlightjs to add syntax highlighting to the code I will write in the blog posts. I'm just using a textarea
in my admin panel to write the blog posts, so I have to manually type in the HTML I want displayed.
<textarea v-model="editorData" cols="60" rows="10"></textarea>
editorData
is just a String. On the page where the blog posts are displayed, I grab the blog post from the server and display it in a BlogPost.vue component. Here is the code for that component:
<template>
<div>
<pre v-highlightjs><code class="javascript">const s = new Date().toString()</code></pre>
<h1 class="page-title">{{postTitle}}</h1>
<div v-html="postBody"></div>
</div>
</template>
<script>
import axios from "axios";
import { baseUrl } from "@/strings";
export default {
name: "BlogPost",
data: function() {
return {
postTitle: "",
postBody: ""
};
},
beforeRouteEnter(to, from, next) {
axios.get(baseUrl + "/blogPosts/" + to.params.id).then(response => {
next(vm => vm.setData(response.data));
});
},
methods: {
setData(data) {
this.postTitle = data.title;
this.postBody = data.content;
}
}
};
</script>
The v-highlightjs
directive in the pre
tag at the beginning of the template just tells the vue-highlightjs plugin to add syntax highlighting to the code inside.
The problem is that the hardcoded code in the pre
tag at the beginning of the div
is highlighted, but the dynamically loaded code in postBody
is not highlighted. For example, if I type <pre v-highlightjs><code class="javascript">const s = new Date().toString()</code></pre>
into my admin panel textarea then display the post in my BlogPost.vue page, it looks like this:
I don't know if vue-highlightjs doesn't highlight the code because it's dynamic or what. Any ideas? Thank you in advance.
P.S. There's got to be a better way to create an admin panel where I can make blog posts that will show up with syntax highlighting when I type code. I tried CKEditor for a bit but found it really confusing. Any suggestions?
Upvotes: 1
Views: 2101
Reputation: 18187
The directive will not highlight updated code after the initial highlighting. To do so, you need to pass a variable to the v-highlightjs
directive:
<pre v-highlightjs="postBody"><code class="javascript"></code></pre>
From Vue.js Syntax Highlighting with Highlight.js:
Reacting to code updates
highlight.js
replaces the content of the code block. If using the directive as shown above, updating the source-code after the initial highlighting does not work anymore. To be able to update the code and highlight it again after an update, pass the variable directly into the v-highlightjs directive
Here's a working jsFiddle modified from this example.
If you need more control over the content that is highlighted, I would suggest using the highlightjs
library itself rather than the directive and manually call hljs.highlightBlock
.
new Vue({
el: '#app',
data: () => ({
post: null,
posts: [
`Phasellus luctus magna non sem fermentum, sed pulvinar ex blandit. Vestibulum id auctor neque. Etiam aliquam commodo sollicitudin. <pre><code class="javascript">var foo = bar</code></pre>Etiam cursus commodo neque, at semper dui vestibulum auctor.`,
`Etiam non elit velit. <pre><code class="javascript">while (true) { console.log('test') }</code></pre>Vestibulum nec posuere lorem. Ut dolor ante, eleifend ut porttitor eu, faucibus non sapien.`,
`Morbi eleifend ornare felis, vel vulputate nibh suscipit id. <pre><code class="javascript">const func = () = ({ foo: 'bar' })</code></pre>Phasellus luctus magna non sem fermentum, sed pulvinar ex blandit. Vestibulum id auctor neque. Etiam aliquam commodo sollicitudin.`
]
}),
beforeMount() {
this.post = this.posts[0]
},
mounted() {
this.highlightPost()
},
methods: {
highlightPost() {
document.querySelectorAll('code').forEach((block) => {
hljs.highlightBlock(block)
})
},
cycle() {
const index = this.posts.indexOf(this.post)
this.post = index === this.posts.length - 1 ? this.posts[0] : this.posts[index + 1]
this.$nextTick(() => {
this.highlightPost()
})
}
}
})
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.9.0/styles/default.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.9.0/highlight.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<button @click="cycle">Next Post</button>
<p id="post-content" v-html="post"></p>
</div>
Upvotes: 2