Vuetify provides a configurable theme which defines a set of color that may be overridden when constructing the Vuetify object, e.g.
const vuetify = new Vuetify({
theme: {
themes: {
light: {
primary: '#3f51b5',
secondary: '#b0bec5',
error: '#b71c1c',
}
}
}
})
In the example above, I've overridden 3 of the theme colors. How can I use these theme colors in my own components, e.g. if I want to set the background color of a div to match the primary color
<template>
<div id="container"></div>
</template>
<script>
// detail omitted
</script>
<style lang="scss" scoped>
#container {
background-color: '#3f51b5';
}
</style>
In the example above I've hard-coded the primary color, but I assume Vuetify provides a way of avoiding this repetition, e.g. a SASS/SCSS variable?
If you don't need to support IE11 you can tell the theme system to use CSS custom properties instead:
new Vuetify({
theme: {
options: { customProperties: true },
},
})
Then you can access the colors directly in your stylesheet:
#container {
background-color: var(--v-primary-base);
}
https://vuetifyjs.com/en/features/theme/#custom-properties
Vuetify 3 doesn't support IE so this is always enabled, and the custom properties are r,g,b lists so you need to use rgb() or rgba() to access them:
#container {
background-color: rgb(var(--v-theme-primary));
color: rgba(var(--v-theme-on-primary), 0.8);
}
You can simply achieve that by applying the CSS as per your custom theme. Please follow the below steps.
Add a wrapper element <v-app> around your component content and then by using computed property get the theme colors.
<v-app :style="getColors">
computed: {
getColors () {
let themeColors = {}
Object.keys(this.$vuetify.theme.themes.light).forEach((color) => {
themeColors[`--v-${color}`] = this.$vuetify.theme.themes.light[color]
})
return themeColors;
}
}
And then in CSS, You can achieve like this :
#container {
color: var(--v-primary);
}
Live demo :
new Vue({
el: "#app",
opts: {
theme: {
themes: {
light: {
primary: '#3f51b5',
secondary: '#b0bec5',
error: '#b71c1c',
}
}
}
},
vuetify: new Vuetify(this.opts),
computed: {
getColors () {
let themeColors = {}
Object.keys(this.$vuetify.theme.themes.light).forEach((color) => {
themeColors[`--v-${color}`] = this.$vuetify.theme.themes.light[color]
})
return themeColors
}
}
});
.container {
color: var(--v-primary);
}
<script src="https://cdn.jsdelivr.net/npm/vue#2.x/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vuetify#2.x/dist/vuetify.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/vuetify#2.x/dist/vuetify.min.css"/>
<div id="app">
<v-app :style="getColors">
<h4 class="container">Hello</h4>
</v-app>
</div>
Related
I added a new route, and added an animation in transition to the new route.
I added the following code which pushes the new route (/first) when a button is clicked:
/* From the Template */
<router-view #clickedNext1="onClickTransition" v-slot="{ Component }">
<transition name="route1" mode="out-in">
<component :is="Component"></component>
</transition>
</router-view>
/* From the Script */
methods: {
onClickTransition() {
this.$router.push("/first");
},
Now the problem is that when I click the button and invoke the "onClickTransition" method, the router seems to be pushed just fine, but the page is empty. The components are rendered only when I manually refresh the page by pressing ctrl+R.
I believe the problem perhaps comes from insertion of the animation, but if I refresh the page manually, the animation works just fine. So I have no idea what the problem is. I will be very grateful for help.
Here is the rest of the code for app.vue:
<template>
<router-view #clickedNext1="onClickTransition" v-slot="{ Component }">
<transition :key="$route.fullPath" name="route1" mode="out-in">
<component :is="Component" />
</transition>
</router-view>
</template>
<script>
export default {
name: "App",
components: {},
data() {
return {};
},
methods: {
onClickTransition() {
this.$router.push("/first");
},
leave(event) {
event.preventDefault();
event.returnValue = "";
},
},
mounted() {
window.addEventListener("beforeunload", this.leave);
},
beforeUnmount() {
window.removeEventListener("beforeunload", this.leave);
},
};
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #fff;
background-color: #151515;
position: relative;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
margin: 0px;
}
/* route transition */
.route1-enter-from {
opacity: 0;
}
.route1-enter-active {
transition: all 3s ease-in;
}
.route1-leave-to {
opacity: 0;
}
.route1-leave-active {
transition: all 3s ease-in;
}
</style>
code section from index.js:
import { createRouter, createWebHistory } from "vue-router";
import MainPage from "../views/MainPage.vue";
import FirstScene from "../views/FirstScene.vue";
const routes = [
{
path: "/",
name: "main",
component: MainPage,
},
{
path: "/first",
name: "first",
component: FirstScene,
},
];
const router = createRouter({
history: createWebHistory(process.env.BASE_URL),
routes,
});
export default router;
The "onClickTransition" method comes from the "PreStartPage.vue" component, which is the child component of "MainPage.vue" which is the main route.
Once the "Next" button is clicked in the "PreStartPage.vue", it sends an event to the "MainPage.vue" with this.$emit."MainPage.vue" then receives the event with a method named "onClickNext1", which sends out a signal to "App.vue" with another this.$emit. That is where the "#clickedNext1" that is shown in the App.vue comes from.
Here is the code from "PreStartPage.vue":
<script>
export default {
name: "PreStartPage",
methods: {
onClickNext() {
this.$emit("clickedNext");
},
},
};
</script>
Here is the code from "MainPage.vue":
<script>
import PreStartPage from "../components/PreStartPage.vue";
export default {
name: "MainPage",
components: { PreStartPage },
data() {
return { showMain: true, showPre: false };
},
methods: {
toggleMain() {
this.showMain = !this.showMain;
this.showPre = !this.showPre;
},
onClickNext1() {
this.$emit("clickedNext1");
},
},
};
</script>
Try modifying your code like this:
/* From the Template */
<router-view #clickedNext1="onClickTransition" v-slot="{ Component }">
<transition :key="$route.fullPath" name="route1" mode="out-in">
<component :is="Component"></component>
</transition>
</router-view>
The "key" property set to $route.fullPath should ensure that the transition is done correctly whenever the route is changed.
EDIT
To solve this, you can add a ":enter-active-class" and ":leave-active-class" property to the transition component, which allows you to specify the class that should be applied to the element during the transition.
In your App.vue component, you can update the transition component like this:
<transition :key="$route.fullPath" name="route1" mode="out-in" :enter-active-class="'route1-enter-active'" :leave-active-class="'route1-leave-active'">
<component :is="Component" />
</transition>
This will ensure that the correct classes are applied to the element during the transition, and that the components are fully rendered before the animation starts.
For more info i should you to visit the official wiki: https://vuejs.org/guide/built-ins/transition.html#css-based-transitions
You can try using
created() {
this.$watch(() => this.$route.params, () => {
// WATCH FOR ROUTE CHANGES
},
}
I am trying to use Swiper with "vue": "^2.6.11", but it throws runtime errors. I followed the guide from https://swiperjs.com/vue, and changed the imports to:
// Import Swiper Vue.js components
import { Swiper, SwiperSlide } from 'swiper/vue/swiper-vue.js';
// Import Swiper styles
import 'swiper/swiper-bundle.css';
Error message:
Property or method "onSwiper" is not defined on the instance but referenced during render, Invalid handler for event "swiper": got undefined , Failed to mount component: template or render function not defined
The Swiper components only work with Vue 3. Those components cannot be used in Vue 2, but the Swiper API can be used directly instead:
Apply a template ref on the target Swiper container element in the template.
In the component's mounted() hook, initialize an instance of Swiper, passing the template ref and Swiper options that include selectors for the pagination/navigation elements in the template.
<script>
import Swiper, { Navigation, Pagination } from 'swiper'
import 'swiper/css'
import 'swiper/css/navigation'
import 'swiper/css/pagination'
export default {
mounted() {
2️⃣
new Swiper(this.$refs.swiper, {
// configure Swiper to use modules
modules: [Navigation, Pagination],
// Optional parameters
loop: true,
// If we need pagination
pagination: {
el: '.swiper-pagination',
},
// Navigation arrows
navigation: {
nextEl: '.swiper-button-next',
prevEl: '.swiper-button-prev',
},
// And if we need scrollbar
scrollbar: {
el: '.swiper-scrollbar',
},
})
},
}
</script>
<template>
<!-- Slider main container -->
<div 1️⃣ ref="swiper" class="swiper">
<!-- Additional required wrapper -->
<div class="swiper-wrapper">
<!-- Slides -->
<div class="swiper-slide">Slide 1</div>
<div class="swiper-slide">Slide 2</div>
<div class="swiper-slide">Slide 3</div>
</div>
<!-- If we need pagination -->
<div class="swiper-pagination"></div>
<!-- If we need navigation buttons -->
<div class="swiper-button-prev"></div>
<div class="swiper-button-next"></div>
<!-- If we need scrollbar -->
<div class="swiper-scrollbar"></div>
</div>
</template>
<style scoped>
.swiper-slide {
display: flex;
justify-content: center;
align-items: center;
}
</style>
demo
Make some additions for #tony19's good answer.
Here is a demo example project: Live Demo
<script>
import Swiper, { Navigation, Pagination, Autoplay } from 'swiper'
import 'swiper/swiper-bundle.min.css'
export default {
data() {
return {
activeIndex: 0,
}
},
mounted() {
const SECOND = 1000 // milliseconds
new Swiper(this.$refs.swiper, {
modules: [Navigation, Pagination, Autoplay],
loop: true,
autoplay: {
delay: 3 * SECOND,
disableOnInteraction: false,
},
speed: 2 * SECOND,
pagination: {
el: '.swiper-pagination',
clickable: true,
},
navigation: {
nextEl: '.swiper-button-next',
prevEl: '.swiper-button-prev',
},
on: {
slideChange: (swiper) => {
this.activeIndex = swiper.realIndex
},
},
})
},
}
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<template>
<MglMap :accessToken="accessToken" :mapStyle="mapStyle" />
</template>
<script>
import Mapbox from "mapbox-gl";
import { MglMap } from "vue-mapbox";
export default {
components: {
MglMap
},
data() {
return {
accessToken: "pk.eyJ1IjoiYWlzaHdlcnlhIiwiYSI6ImNrYzVyYXBlNzBrZGgzMG8wc3FtZjU5NDAifQ.u4azaXjkh41xSMC1NJLhTw", // your access token. Needed if you using Mapbox maps
mapStyle: "mapbox://styles/aishwerya/ckc5ufmlw0nu11ip289o79bkl" // your map style
};
},
created() {
// We need to set mapbox-gl library here in order to use it in template
this.mapbox = Mapbox;
}
};
</script>
I created the mapbox-gl map but it showing blank screen
I have tried with this link but it didnt worked
I dont what Im missing it clearly shows me blank screen
Here is a simple way to integrate the mapbox application using Vue 2. This example doesn't require NPM or import statements. I would be careful about including your api key on public forums. I have included your api key in order for this example to work.
<script src="https://api.mapbox.com/mapbox-gl-js/v1.11.0/mapbox-gl.js"></script>
<link href="https://api.mapbox.com/mapbox-gl-js/v1.11.0/mapbox-gl.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.11/vue.min.js"></script>
<style>
#project { position: absolute; top: 0; bottom: 0; width: 100%; }
</style>
<div id="project"></div>
<script>
var mapping = new Vue({
el: '#project',
data: {
map: ''
},
mounted(){
mapboxgl.accessToken = 'pk.eyJ1IjoiYWlzaHdlcnlhIiwiYSI6ImNrYzVyYXBlNzBrZGgzMG8wc3FtZjU5NDAifQ.u4azaXjkh41xSMC1NJLhTw';
//create a new mapbox instance
this.map = new mapboxgl.Map({
container: 'project',
'style' : 'mapbox://styles/mapbox/light-v10'
});
//fit the united states to the screen
this.map.fitBounds([[-135, 47], [-60, 25]]);
}
});
</script>
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 added v-cloak directive on the top div in my component and added css as in docs, set a timeout but it does not work I can see else content and the form styles.
Component code:
<div class="form-in-wrap" v-cloak>
<ul id="example-1" v-if="reports.length>0">
<report-component v-for="report in reports" :report="report" :key="report.id" :options="options">
</report-component>
</ul>
</div>
Component script:
<script>
import ReportComponent from "./ReportComponent";
export default {
components: {ReportComponent},
data: function () {
return {
reports: {
type: Array,
},
report: {
...
},
}
},
created: function () {
var self = this
setTimeout(function () {
self.loadData('/reports')
}, 2000);
},
methods: {
loadData: function() {
get method
}
}
</script>
<style scoped>
[v-cloak] {
display: none !important;
}
</style>
All example creates a Vue instance, but I am using export default in my component. Also it is not a main component, it is included with router can this be the case why it does not work?