I want to be able to pass data from a object to the <styles> in a single file component. However, it doesn't seem like this is possible.
What I'm trying to achieve:
<template></template>
<script>
export default {
data: function() {
return { color: "#f00" }
}
}
</script>
<style>
body {
background-color: this.color
}
</style>
As far as I'm aware, you are not able to pass data from the component to its stylesheets.
The best practice as far as dynamic styling is to use v-bind:class or v-bind:style if needed. The <style> section should be used for the CSS templating language only.
<template>
<p :style="{ backgroundColor: bgColor }">Lorem ipsum</p>
</template>
<script>
export default {
data() {
return {
bgColor: '#000'
}
}
}
</script>
Let me know if you have any other questions!
Update
Since the goal is to use it for Sass functions like darken, I would recommend managing the various colors needed through utility classes instead.
Related
I need to present some random/dynamic html data in my project that might contain style tags, by default vue.js doesn't allow style tags in the template to avoid messing styles that is a very good option.
To make my project work I tried some runtime-component projects on github but they doesn't accept css styles in the way I need, so I came up with the solution of creating my own runtime component with accepting css styles data.
What I want in code is sth like:
<template>
<div v-html="template"></div>
</template>
<script>
export default {
name: "DynamicTemplate",
props: {template: String, style: String}
}
</script>
<style scoped>
// style data goes here
</style>
Any alternative working solution is welcome too :)
I tried v-html and v-text attributes on the component style tag (without any results) and also using css #import statement with base64 encoded css codes (got some errors like Cannot read properties of undefined), but none of them worked :(
You can encapsulate the data inside the style tags inside the component tag provided by vue in this manner ->
<component :is="'style'"> .test-class { color: red; }....Your style data </component>
An example of the same can be found in this project I created
https://codesandbox.io/s/interesting-dewdney-id9erd?file=/src/components/HelloWorld.vue
Edit 1 =>
After reading the comment as I think the CSS scope compilation is done during the build process not during runtime thus having css at runtime won't scope it an alternate solution for this can be embedding your HTML code inside an iframe and passing your code to the iframe using the srcdoc attribute.An example of the same is given below
https://codesandbox.io/s/currying-cherry-zzv3wk?file=/src/components/HelloWorld.vue
<template>
<iframe style="width: 100vw; height: 80vh" :srcdoc="htmlCssCode"></iframe>
</template>
<script>
export default {
data() {
return {
htmlCssCode: `Your Html code here`
<html>
Here is an example of passing that can pass dynamic HTML data in your project with an example using style tags
<template>
<div>
<div v-html="template" :style="style"></div>
</div>
</template>
<script>
export default {
name: 'DynamicTemplate',
props: {
template: {
type: String,
required: true
},
style: {
type: Object,
required: false,
default: () => {}
}
}
}
</script>
Here is the component being used.
<DynamicTemplate
:template="<p>This is some dynamic HTML content</p>"
:style="{ color: 'red', font-size: '14px' }">
</DynamicTemplate>
Here is an example of passing that can pass dynamic HTML data in your project with an example of passing classes dynamically
<template>
<div>
<div v-html="template" :class="classes"></div>
</div>
</template>
<script>
export default {
name: 'DynamicTemplate',
props: {
template: {
type: String,
required: true
},
classes: {
type: Object,
required: false,
default: () => {}
}
}
}
</script>
Here is the component being used.
<DynamicTemplate
:template="template"
:classes="classes"
/>
Some of my single-file components need to take hover color from props.
My solution is that i set css variables in the following way (the main part is in the mounted(){...})
<template>
<div class="btnWrapper" ref="btnWrapper">...</div>
</template>
...
...
props() {
color1: {type: String, default: 'blue'},
},
mounted () {
this.$refs.btnWrapper.style.setProperty('--wrapHoverColor', this.color1)
}
...
...
<style scoped>
.btnWrapper {
--wrapHoverColor: pink;
}
.btnWrapper:hover {
background-color: var(--wrapHoverColor) !important;
}
</style>
This solution seems kind of woowoo.
But maybe there is no better way with pseudo elements, which are hard to control from js.
Do you guys ever take pseudo element's properties from props in vue components?
You have two different ways to do this.
1 - CSS Variables
As you already know, you can create CSS variables from what you want to port from JS to CSS and put them to your root element :style attr on your components created hooks, and then use them inside your CSS codes with var(--x).
<template>
<button :style="style"> Button </button>
</template>
<script>
export default {
props: ['color', 'hovercolor'],
data() {
return {
style: {
'--color': this.color,
'--hovercolor': this.hovercolor,
},
};
}
}
</script>
<style scoped>
button {
background: var(--color);
}
button:hover {
background: var(--hovercolor);
}
</style>
2 - Vue Component Style
vue-component-style is a tiny (~1kb gzipped) mixin to do this internally. When you active that mixin, you can write your entire style section inside of your component object with full access to the component context.
<template>
<button class="$style.button"> Button </button>
</template>
<script>
export default {
props: ['color', 'hovercolor'],
style({ className }) {
return [
className('button', {
background: this.color,
'&:hover': {
background: this.hovercolor,
},
});
];
}
}
</script>
I am coming from React and Vue frankly seems to be way different to me even from Javascript prospective.
From the boiler plate code (HelloWorld.vue), Say we have the following code snippet
<template>
<div class="hello">
<h1>{{ msg }}</h1>
<p>
For a guide and recipes on how to configure / customize this project,<br />
check out the
<a href="https://cli.vuejs.org" target="_blank" rel="noopener"
>vue-cli documentation</a
>.
</p>
</template>
<script>
export default {
name: "HelloWorld",
props: {
msg: String
}
};
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
h3 {
margin: 40px 0 0;
}
ul {
list-style-type: none;
padding: 0;
}
li {
display: inline-block;
</style>
Here, I am unable to comprehend how does our export default knows What we need to export
Since the question was marked closed due to duplicate, Sharing the difference between the both
Consider, In case of react (or take it as any function) if we created a function
const someFunc = () => (
<div>
<h1> Test Component </h1>
</div>
)
export default someFunc
Here i am exporting my somefunc which I can import and use it with whatever way I want in other component
import Whatever from "./location"
But in the above Vue snippet, I cannot comprehend the significance of
export default {
name: "HelloWorld",
props: {
msg: String
}
};
What is the significance of exporting this object?
Also, where would If suppose I need to will I write my functions, class?
Everything inside the curly braces on export default {} including methods and data will be exported, and can be imported using import like in your example on React
import Whatever from "./location"
Just to answer your question
Also, where would If suppose I need to will I write my functions, class?
Methods and other data can be included inside the curly braces on export default {}. For example,
<script>
export default {
name: "HelloWorld",
props: {
message: {
type: String
}
},
data() {
return {
// put any data here, e.g.,
isVueDeveloper: true
}
},
methods: {
// put any methods here, e.g.,
firstMethod() {
return;
}
}
}
</script>
I am using vuejs style bindings to render changes dynamically as the styles are computed.
This works great for everything within the scope of my Vue instance but how can I compute styles for body or html tags?
This used to be possible when you could bind the vue instance to but vue no longer lets you do it.
I want to dynamically update the background color of using my computed variables in vue.
edit: added code snippet to demonstrate
var app = new Vue({
el: '#app',
data: {
color: '#666666'
},
computed: {
backgroundColor: function() {
return {
'background-color': this.color
}
}
},
methods: {
toggleBackground: function() {
if(this.color=='#666666'){
this.color = '#BDBDBD'
} else {
this.color = '#666666'
}
}
}
})
<script src="https://vuejs.org/js/vue.min.js"></script>
<html>
<body>
<div id="app" :style="backgroundColor">
<div>
lots of content...
</div>
<button #click="toggleBackground"> Click to toggle </button>
</div>
</body>
</html>
If you really need to style body itself, you'll need to do it with plain JavaScript in a watcher. A simple example is below.
You should (not something I've tried, but I'm hypothesizing) be able to defeat overscrolling effects by making body and your outer container non-scrolling. Put a scrollable container inside that. When it overscrolls, it will show your outer container, right?
The reasons for not binding to body are here (for React, but applies to Vue).
What’s the problem with ? Everybody updates it! Some people have
non-[Vue] code that attaches modals to it. Google Font Loader will
happily put elements into body for a fraction of second, and
your app will break horribly and inexplicably if it tries to update
something on the top level during that time. Do you really know what
all your third party scripts are doing? What about ads or that social
network SDK?
new Vue({
el: '#app',
data: {
isRed: false
},
watch: {
isRed() {
document.querySelector('body').style.backgroundColor = this.isRed ? 'red' : null;
}
}
});
#app {
background-color: white;
margin: 3rem;
}
<script src="//cdnjs.cloudflare.com/ajax/libs/vue/2.4.2/vue.min.js"></script>
<div id="app">
<input type="checkbox" v-model="isRed">
</div>
I think I found better solution than using jQuery/querySelector
You can add tag style right in your Vue template.
And add v-if on this, smth like that:
<style v-if="true">
body {
background: green;
}
</style>
Thus you can use computed/methods in this v-if and DOM always will update when you need.
Hope this will help someone ;)
UPD:
Using tag "style" in templates is not best idea, but you can create v-style component, then everything will be fine:
Use style tags inside vuejs template and update from data model
My snippet:
Vue.component('v-style', {
render: function (createElement) {
return createElement('style', this.$slots.default)
}
});
new Vue({
el: '#app',
data: {
isRed: false,
color: 'yellow',
},
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<input type="checkbox" v-model="isRed">
<v-style v-if="isRed">
body {
background: red; /*one more benefit - you can write "background: {{color}};" (computed)*/
}
</v-style>
</div>
<template>
<div class="demo">
<profile-header :title="profileTitle" :imagePath="profileImagePath"></profile-header>
</div>
</template>
<style scoped>
.demo {
width: 750px;
background-color: #f2f3f4;
}
</style>
<script>
import ProfileHeader from '../components/profile-header.vue'
export default {
components: { ProfileHeader },
data () {
return {
profileTitle: "Lorem Ipsum",
profileImagePath: "http://...."
}
}
}
</script>
In Weex, I created a reusable component "profile-header" with title and imagePath properties. It appears that I can only pass the data to these two attributes using the code presented above, where I need to define two variables.
Is there anyway where I can pass data to my custom component by inlining the data right there? Like:
<profile-header :title="This is the hardcoded title" :imagePath="hard coded path"></profile-header>
<profile-header title="This is the hardcoded title" imagePath="hard coded path"></profile-header>
or
<profile-header :title="'This is the hardcoded title'" :imagePath="'hard coded path'"></profile-header>
In the first case, you are simply not binding and the props are treated as strings. In the second case, you are binding a hard coded string (note the quotes).