Reputation: 7564
Short version:
I'm generating a string with HTML in a component's method, and I can't figure out how to style that HTML with scoped CSS, because it's missing the data attribute for scoping.
Slightly longer version:
I have a function called highlight which takes a string and returns an HTML string with all occurrences of a search term highlighted, meaning surrounded by a <span class="match">
. However, since I'm doing this manually in a string, that span doesn't get the special data attribute that the scoped CSS in my Vue component needs to work, so the only way for me to style those matches is to make my CSS not scoped, which I'd like to not have to do. Is there a more Vue-specific way for me to do this?
The function looks like this:
// Source: http://stackoverflow.com/a/280805/2874789
function highlight(data, search) {
return data.replace(
new RegExp("(" + preg_quote(search) + ")", 'gi'),
"<span class=match>$1</span>"
);
}
(preg_quote is just a function that escapes things that need to be escaped)
Thanks!
Upvotes: 15
Views: 4459
Reputation: 820
DOM content created with v-html are not affected by scoped styles, but you can still style them using deep selectors.
https://vue-loader.vuejs.org/guide/scoped-css.html#deep-selectors
Refer this below link, it explains how to use deep selected for different vue versions and with/without scss
https://github.com/vuejs/vue-loader/issues/749
Upvotes: 0
Reputation: 846
Good question! I had the same problem and solved it in an elegant way. Can't wait to share!
Suppose your template looks like this
<template>
<div class="match">
<div v-html="<span>hello world</span>"></div>
</div>
</template>
Just change
<style scoped>
.match span {
color: yellow;
}
</style>
compiled output: `.match span[data-v-f3f3eg9] { color: yellow; }`
to
<style scoped>
.match >>> span {
color: yellow;
}
</style>
compiled output: `.match[data-v-f3f3eg9] span { color: yellow; }`
Look at the difference between the two outputs. You should know what I mean. See more on the Vue Loader Document.
Upvotes: 2
Reputation: 465
Just ran into something similar. The easiest way around it, don't scope it. Just namespace your markup and CSS classes so they don't get inherited from some other module and you're done. Messing around with JavaScript to pull this off is overkill.
Upvotes: 4
Reputation: 210
Dynamically Generated Content DOM content created with v-html are not affected by scoped styles, but you can still style them using deep selectors.
There doesn't appear to be a VueJS specific way of doing it. It sounds like your best option is to either style in-line in your highlight function's output, or use a global class.
function highlight(data, search) {
return data.replace(
new RegExp("(" + preg_quote(search) + ")", 'gi'),
"<span class=match>$1</span>"
);
}
<style>
.match {
color: yellow;
}
</style>
or
function highlight(data, search) {
return data.replace(
new RegExp("(" + preg_quote(search) + ")", 'gi'),
"<span style="{ color: yellow }">$1</span>"
);
}
You can also try deep selectors, but I am not very familiar with them myself.
https://vue-loader.vuejs.org/en/features/scoped-css.html
Upvotes: 7
Reputation: 32921
This is an interesting one.
Not sure how to approach this with scoped
styles alone but I think we can hack around it with an additional <style>
element using css modules (which are also scoped).
I was thinking like:
<style scoped>
...
</style>
<style module>
.match {
color: red;
}
</style>
Then, in your replace function you can do:
`<span class="${this.$style.match}">...</span>`
You can read more about vue-loader's CSS module support here:
http://vue-loader.vuejs.org/en/features/css-modules.html
Upvotes: 3