Styles are not being applied to elements created in the setup function in vue - vue.js

So I am working on this mini website and I'm trying to not hard code repetitive elements in the template, so I thought I would a function to display them all.
<template>
<div class="wrapper">
<div class="skills" ref="canvas">
</div>
</div>
import { ref, onMounted } from 'vue';
import MySkills from '../constants/skills';
export default {
setup() {
const skills = MySkills
const canvas = ref(null);
const displaySkills = () => {
skills.forEach(skill => {
const el = document.createElement('div');
el.className = 'skill';
el.innerText = skill.name;
const level = document.createElement('span');
level.className = 'level';
level.innerText = skill.level;
el.appendChild(level);
canvas.value.appendChild(el);
})
}
onMounted(() => {
displaySkills();
})
return {
canvas,
displaySkills
}
}
}
the styles are in a separate file
.skill {
padding: 10px;
border-radius: 100px;
text-align: center;
position: relative;
background-color: aqua;
}
.level {
position: absolute;
top: -5%;
left: 0%;
padding: 5px;
border-radius: 100px;
text-align: center;
}
Now the ssue is that those styles are not being applied the el and level elements
please help!!!

You should not access the DOM (createElement, appendChild) while working with Vue.
If you are new to Vue, v-for does exactly that, more info in the official docs.
So your code would be:
<template>
<div class="wrapper">
<!-- you should put a unique identifier in the key tag, if you don't have an id the name should be fine too -->
<div class="skills" v-for="skill in MySkills" :key="skill.id">
<your-skill-html>
{{ skill.name }} etc
</your-skill-html>
</div>
</div>
</template>
<script setup>
import MySkills from '../constants/skills';
</script>
<style>
.skill {
padding: 10px;
border-radius: 100px;
text-align: center;
position: relative;
background-color: aqua;
}
.level {
position: absolute;
top: -5%;
left: 0%;
padding: 5px;
border-radius: 100px;
text-align: center;
}
/* or import "path/to/my-css-file.css" */
</style>
Please note that I'm using the script setup syntax but it's not required, it's just quicker to write since you can omit the defineComponent part and the return values.

Related

How to get route name in vueJS

I am trying to create a script in vueJS, to enable the navbar only when the pages are not login/register.
For this I am trying to use this.$route.name but I only get undefined in the console when I am console logging it. I have created a method to check for the route name and i am calling it when the components are mounted i.e using mounted fucntion.
app.vue code:
<template>
<div id="app">
<NavBar v-if="flag" />
<main>
<router-view/>
</main>
</div>
</template>
<script>
import NavBar from './components/NavBar.vue';
export default {
components: { NavBar },
data(){
return{
flag1 : false,
flag2 : false,
flag: false
}
},
mounted() {
let id = localStorage.id;
this.getrouteflags();
return {
id
}
},
methods : {
getrouteflags: function(){
console.log(this.$route.query.name)
if(this.$route.name == 'register'){
this.flag1 = true;
}
if(this.$route.name == 'login'){
this.flag2 = true;
}
this.flag = this.flag1 || this.flag2;
console.log(this.flag1,this.flag2)
}
}
}
</script>
<style>
nav{
}
#app{
width: 100%;
height: 100%;
}
html,
body {
height: 100%;
min-height: 75rem;
}
body {
justify-content: center;
display: -ms-flexbox;
display: flex;
-ms-flex-align: center;
align-items: center;
padding-top: 40px;
padding-bottom: 40px;
background-color: #f5f5f5;
background-image: '../../backend/static/plot.png';
}
.form-signin {
width: 100%;
max-width: 330px;
padding: 15px;
margin: auto;
}
.form-signin .checkbox {
font-weight: 400;
}
.form-signin .form-control {
position: relative;
box-sizing: border-box;
height: auto;
padding: 10px;
font-size: 16px;
}
.form-signin .form-control:focus {
z-index: 2;
}
.form-signin input[type="email"] {
margin-bottom: -1px;
border-bottom-right-radius: 0;
border-bottom-left-radius: 0;
}
.form-signin input[type="password"] {
margin-bottom: 10px;
border-top-left-radius: 0;
border-top-right-radius: 0;
}
body,html{
padding: 0;
margin: 0;
min-height: 100vh;
width: 100%;
}
html{
background-color: white;
}
</style>
This is what I am getting in the console.
Can someone help me in resolving this issue?
I'm guessing you're using Vue2.
Have you tried adding a computed property:
computed: {
currentRouteName() {
return this.$route.name;
}
}
In case you're using Vue3 with a script setup you could use VueRouter's composable.
<script setup>
import { useRouter, useRoute } from 'vue-router';
const router = useRouter();
const route = useRoute();
// Do stuff.
</script>
If you need more help, read VueRouter's guide.
v3 reference
v4 reference

How can i change style of the body when my modal it will be open?

How can i change the body{overflow:hidden} when my modal it will be open?
for example it will be my modal, when its open, i would like to apply this style body{overflow:hidden}
<div v-if="dialogFoundation">
i am using vuejs3, i am using setup(){...}
The best performance would be to use javascript plain. You can add Eventlistener top the modal trigger Element. In my example i use a button. If it triggered then you can use classList and assign the body a class. In my example .dark.
Vue version
<!-- Use preprocessors via the lang attribute! e.g. <template lang="pug"> -->
<template>
<div id="app">
<h1>{{message}}</h1>
<p></p>
<button #click="doSomething">Modal</button>
</div>
</template>
<script>
export default {
data() {
return {
message: 'Welcome to Vue!'
};
},
methods: {
doSomething() {
const b = document.querySelector('body');
b.classList.toggle('dark');
}
}
};
</script>
<!-- Use preprocessors via the lang attribute! e.g. <style lang="scss"> -->
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
a,
button {
color: #4fc08d;
}
button {
background: none;
border: solid 1px;
border-radius: 2em;
font: inherit;
padding: 0.75em 2em;
}
.dark {
background: black;
opacity: 0.4;
}
</style>
Vanilla JS
const btn = document.querySelector('button');
btn.addEventListener('click', () => {
const b = document.querySelector('body');
b.classList.toggle('dark');
})
.dark {
background: black;
opacity: 0.4;
}
<body>
<div></div>
<button>click</button>
</body>
You can use watchers in Vue.js for solving this problem.
When variables changes you can check whether it is true or not, and if true change overflow of body to hidden.
{
watch: {
dialogFoundation(dialogFoundation) {
document.body.style.overflow = dialogFoundation ? "hidden" : "auto"
}
}
}
But I think this is not good solution. You can set this styles to your app element
#app {
width: 100%;
height: 100%;
overflow: auto;
}
and you can change style of app element using Vue directives.
<template>
<div id="app" :class="{ hidden: dialogFoundation }">
Long text....
</div>
</template>
<script>
import { ref } from "vue";
export default {
setup() {
const dialogFoundation = ref(true);
return { dialogFoundation };
},
};
</script>
<style>
html,
body,
#app {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
box-sizing: border-box;
}
#app {
overflow: auto;
}
#app.hidden {
overflow: hidden;
}
</style>
Code in codesandbox - https://codesandbox.io/s/immutable-glitter-rwc2iy?file=/src/App.vue

Is it possible to put a CSS template inside a Vue component?

I've created the following Vue component:
var loading = new Vue({
el: "#loading_id",
components:{
'loading' : {
template : `
<div>
<div id="screenLoading" class="background">
<div class="loading">
<div class="obj"></div>
<div class="obj"></div>
<div class="obj"></div>
<div class="obj"></div>
<div class="obj"></div>
<div class="obj"></div>
<div class="obj"></div>
<div class="obj"></div>
</div>
</div>
</div>
`,
methods: {
startLoading: function() {
const load = document.getElementById("screenLoading");
load.classList.add('show')
},
stopLoading: function(){
const load = document.getElementById("screenLoading");
load.classList.remove('show')
}
}
}
}
});
loading.$children[0].startLoading()
setTimeout(() => {
loading.$children[0].stopLoading()
}, 3500);
.background {
width: 100vw;
height: 100vh;
background: rgba(0, 0, 0,.5);
position: fixed;
top: 0px;
left: 0px;
z-index: 2000;
display: none;
justify-content: center;
align-items: center;
}
.background.show {
display: flex;
}
.loading{
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
height: 40px;
display: flex;
align-items: center;
}
.obj{
width: 12px;
height: 70px;
background: white;
margin: 0 3px;
border-radius: 10px;
animation: loading 0.8s infinite;
}
.obj:nth-child(2){
animation-delay: 0.1s;
}
.obj:nth-child(3){
animation-delay: 0.2s;
}
.obj:nth-child(4){
animation-delay: 0.3s;
}
.obj:nth-child(5){
animation-delay: 0.4s;
}
.obj:nth-child(6){
animation-delay: 0.5s;
}
.obj:nth-child(7){
animation-delay: 0.6s;
}
.obj:nth-child(8){
animation-delay: 0.7s;
}
#keyframes loading{
0%{
height: 0;
}
50%{
height: 70px;
}
100%{
height: 0;
}
}
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<loading id="loading_id"></loading>
It works perfectly fine, its purpose is to be a loading screen for me to use when I have to make something wait on my webpage. However, instead of loading the CSS from an external CSS file with the <style> tag on the main HTML, I'd like to load my CSS directly from inside Vue, just like I did with the HTML on the template variable. Basically, it'd be something like the following:
var loading = new Vue({
el: "#loading_id",
components:{
'loading' : {
template : `myHTML template`,
cssTemplate: `myCSS template`,
methods: {
// my methods
}
}
}
});
Is it possible to do on Vue? Can I write CSS templates inside a Vue component?
I know I also can load small pieces of CSS styles with Vue as described here, but in my case, I'd like to keep the classes and ids declaration as they are in a normal CSS file...
You can include css in your vue component in the style tag section as below:
<style scoped src="#/assets/styles/myCSSTemplate.css">
</style>
Also try to use proper structure when creating a vue component by having template, script and style sections.
For exmaple you can create Vue instane in App.vue and then have a component as YourComponent.vue
Refer to Vue documentation here.

Vuejs v-movable with #click is not working

Im trying to implement a moveable text that can also be click and call the method. However when i try to put #click its not calling the function. Can anyone help me? Thank you..
App.vue
<template>
<div id="app">
<div>
<a #click="next()">
<movable class="testmove" posTop="222" posLeft="222" shiftKey="true"
><span>Shift Key Behavior</span></movable
>
</a>
</div>
</div>
</template>
<script>
import movable from "v-movable";
export default {
name: "app",
movable,
methmethods: {
next() {
alert("Hello");
},
},
};
</script>
<style>
body {
padding: 0;
margin: 0;
font-family: Helvetica, Arial;
}
.movable {
cursor: pointer;
}
.testmove {
/* display:block;
position: absolute; */
top: 0;
height: 150px;
width: 150px;
background: #333;
color: white;
}
.modaltitle {
background: blue;
display: block;
width: 100%;
color: white;
}
</style>
Here is the code:
https://codesandbox.io/s/cold-darkness-0zm03?file=/src/App.vue
There is a typo in your code methmethods which should be corrected to methods
You can use start event for the v-movable.
#start: fires immediately after the pointerdown event on the element

vue js use npm module as inline script

I am not using webpack, I include vue as external script Something like this:
<script src ="unpckg.com/vue.js-latest"></script>
And I want to use npm module
https://github.com/stephan281094/vue-drag-select
So I include it like this:
<script src= "https://unpkg.com/vue-drag-select#0.1.5/dist/vue-drag-select.js
"></script>
How do I use it?
UPD: I corrected the path to external script.
My question is how to include vue-drag-select component in my app because
When I write
import DragSelect from 'vue-drag-select/src/DragSelect.vue'
It gives me an error because I don't use webpack, so there is no import function
This is just a url https://github.com/stephan281094/vue-drag-select to dispaly package details not any file path
Here is the raw data of .js file might be you want to include, go this url and save contents of this file in your local and then import/include
https://github.com/stephan281094/vue-drag-select/blob/master/dist/vue-drag-select.js
If you include cdn script, then DragSelect is global variable, you can access it directly
Vue.component('vue-drag-select', DragSelect.default)
Vue.component('vue-drag-select', DragSelect.default)
new Vue({
el: "#app1",
methods: {
getClasses (item, selectedItems) {
const isActive = !!(selectedItems.find((selectedItem) => {
return parseInt(selectedItem.dataset.item, 10) === item
}))
return {
item: true,
active: isActive
}
}
}
})
*,
*:before,
*:after {
box-sizing: inherit;
}
html {
box-sizing: border-box;
user-select: none;
}
html,
body {
margin: 0;
padding: 0;
min-height: 100vh;
}
body {
font: 16px / 1.5 'Helvetica Neue', sans-serif;
padding: 5%;
}
/* Custom styling */
.item {
display: inline-flex;
min-width: 80px;
height: 100px;
margin-right: 10px;
margin-bottom: 10px;
background-color: #ddd;
justify-content: center;
align-items: center;
text-transform: uppercase;
letter-spacing: 3px;
font-size: 10px;
}
.item.active {
background-color: rgb(0, 162, 255);
color: #fff;
}
<script src="https://unpkg.com/vue-drag-select#0.1.5/dist/vue-drag-select.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vue#2.5.16/dist/vue.js"></script>
<div id="app1">
<h1>Vue Drag Select Example</h1>
<vue-drag-select selector-class="item">
<template slot-scope="{ selectedItems }">
<div
v-for="item in 50"
:class="getClasses(item, selectedItems)"
:data-item="item"
>
Item {{ item }}
</div>
</template>
</vue-drag-select>
</div>