How can you set a boolean to true when the mouse click is held down, and false when you release the click? On Vue I am using v-on:mousedown="hold = !hold" But this toggles the boolean instead of having the user hold the click down.
You need to use the events mousedown and mouseup. Try something like this:
<template>
<div>
<div :style="{ 'background-color': color }">
Lorem ipsum dolor sit amet consectetur adipisicing elit.
</div>
<button #mousedown="color = 'orange'" #mouseup="color = 'green'" >Click here</button>
</div>
</template>
<script>
export default {
name: 'App',
data: () => ({
color: 'yellow',
}),
};
</script>
Use both mousedown and mouseup events.
<div
v-on:mousedown="hold = true"
v-on:mouseup="hold = false"
>{{hold}}</div>
Related
I am using Quasar, and I would like the drawer changes into mini mode automatically whenever the browser gets smaller by users. For now, it's always opened even I narrows the browser.
It's what I tried below:
<q-drawer
v-model="drawer"
show-if-above
:mini="!drawer || miniState"
#click.capture="drawerClick"
:width="220"
:breakpoint="500"
bordered
:content-style="{ backgroundColor: '#f5f7f9' }"
>
<q-scroll-area class="fit">
<q-list padding>
<q-btn
v-if="!miniState"
flat
left
#click="miniState = !miniState"
class="logo-btn"
>
<img
src="~assets/os_logo.png"
width="144px"
height="24px"
contain
/>
</q-btn>
<q-btn v-else flat left #click="miniState = !miniState">
<img src="~assets/os_logo_no_text.png" width="24px" contain />
</q-btn>
<!-- MENU -->
<q-expansion-item
default-opened
v-for="(menu, index) in menus"
:style="index === 0 && 'margin-top: 27px'"
:icon="menu.icon"
:label="menu.title"
:key="menu.id"
:expand-icon="menu.subMenus.length === 0 ? 'none' : ''"
header-class="header-bg text-black"
expand-icon-class="text-gray"
>
<q-expansion-item
v-for="(sub, index) in menu.subMenus"
:key="index"
:label="sub.title"
expand-icon="none"
class="sub-content"
:to="{ name: sub.link }"
/>
</q-expansion-item>
</q-list>
</q-scroll-area>
</q-drawer>
And the script code below :
<script lang="ts">
import Vue from 'vue';
export default Vue.extend({
// name: 'ComponentName'
data() {
return {
drawer: false,
miniState: false,
},
computed: { // <-- I tried this one..
miniState() {
if (window.innerWidth < 600) {
return (this.miniState = true);
}
}
},
});
</script>
I have also checked this answers here : How to default navigation drawer to closed on mobile and open on desktop?
But this is not really what I am aiming for since the mode of drawer gets stuck and not changes responsively. Any suggestions?
In your code you have made several mistakes;
You are repeating your data property miniState as a computed property. The miniState property inside the data function will override the computed property; thus it will always be false
You are not returning a value from your computed property; instead you are only assigning.
Still; window properties such as innerWidth is not reactive and watchable in Vue. Please correct me if I am wrong. Thus, watching window.innerWidth will not trigger every time the window is resized.
Since you are using Quasar, you can make use of the the screen plugin which comes with Quasar. You dont have to install anything, the screen plugin is installed by default. Here is the link to the docs.
I have put below a very minimal example of the code with the functionality you required. This is not the code you have put in your post above. I extracted the drawer and the content from the Quasar documentation here
Now the drawer will automatically go into mini mode when the screen size is below 500 px; this is of course configurable.
Also; on a side note, if you are only starting with Vue and Quasar, Vue is now upgraded to Vue3 which comes with the composition api. Quasar is also being upgraded to version 2 which supports Vue3.
Follow the comments below and you will understand the code!
new Vue({
el: '#q-app',
data: function() {
return {
drawer: true,
// using a property to track when to show the mini drawer: this way is easy to maintain.
switchToMini: 500
}
},
computed: {
// use ministate as a computed property
miniState: function() {
// use the screen plugin of Quasar -> this is very handy
return this.$q.screen.width < this.switchToMini
// you can do better and compare agains Quasars default breakpoints; following code checks whether the current screen size is 'sm'. You can comapare against 'xs', 'sm', 'md', 'lg' and 'xl'
// return this.$q.screen.name === "sm"
}
}
})
<!-- quasar and vue includes -->
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/#quasar/extras/material-icons/material-icons.css">
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/quasar/dist/quasar.min.css">
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script src="https://cdn.jsdelivr.net/npm/quasar/dist/quasar.umd.min.js"></script>
<!-- end of includes -->
<!-- app -->
<div id="q-app">
<template>
<div class="q-pa-md">
<q-layout view="hHh Lpr lff" container style="height: 300px" class="shadow-2 rounded-borders">
<q-header elevated class="bg-black">
<q-toolbar>
<q-toolbar-title>Header</q-toolbar-title>
</q-toolbar>
</q-header>
<q-drawer
v-model="drawer"
show-if-above
:mini="miniState"
:breakpoint="200"
:width="200"
bordered
class="bg-grey-3"
>
<q-scroll-area class="fit">
<q-list padding>
<q-item clickable v-ripple>
<q-item-section avatar>
<q-icon name="send" />
</q-item-section>
<q-item-section>
Send
</q-item-section>
</q-item>
</q-list>
</q-scroll-area>
</q-drawer>
<q-page-container>
<q-page padding>
<p>
Lorem ipsum dolor sit amet consectetur adipisicing elit. Fugit nihil praesentium molestias a adipisci, dolore vitae odit, quidem consequatur optio voluptates asperiores pariatur eos numquam rerum delectus commodi perferendis voluptate?
</p>
</q-page>
</q-page-container>
</q-layout>
</div>
</template>
</div>
I have a q-list with several q-expansion-items as children. The q-expansion-items are assigned to a list, so there is only one open at any given time.
<q-list padding>
<q-expansion-item
id="explore"
group="somegroup"
icon="explore"
label="Explore"
default-opened
#show="switchMode">
<q-card id="explore-card">
<q-card-section id="explore-card-section">
Item one text
</q-card-section>
</q-card>
</q-expansion-item>
<q-expansion-item
id="identity"
group="somegroup"
icon="perm_identity"
label="Identity"
#show="switchMode">
<q-card>
<q-card-section>
Item two text.
</q-card-section>
</q-card>
</q-expansion-item>
</q-list>
I would like to run a Vue method when any q-expansion-item is opened and determine which specific item was opened.
I've tried assigning an id to each q-expansion-item, but need some clunky code to access the ID within the #show event: `
new Vue({
el: '#q-app',
data: function () {
return {}
},
methods: {
switchMode: function (event) {
console.log(event.target.parentElement.parentElement.parentElement.parentElement.id)
}
},
// ...etc
})
I've also tried using the to property to change the URL fragment, but that doesn't update the URL when the item is expanded (it only updates the URL fragment when clicking on the item title).
How can I determine which q-expansion-item in a group is open at any given time?
You can achieve this without using id's and events. You can use v-model instead.
Example -
<q-expansion-item
group="somegroup"
icon="explore" v-model="selected_model['First']"
label="First"
header-class="text-primary"
>
<q-card>
<q-card-section>
Lorem ipsum dolor sit amet, consectetur adipisicing elit.
</q-card-section>
</q-card>
</q-expansion-item>
<q-separator />
<q-expansion-item
group="somegroup"
v-model="selected_model['Second']"
icon="perm_identity"
label="Second"
header-class="text-teal"
>
<q-card>
<q-card-section>
Lorem ipsum dolor sit amet, consectetur adipisicing elit.
</q-card-section>
</q-card>
</q-expansion-item>
data -
data(){
return{
selected_model:{}
}
}
Result-
{ "First": true, "Second": false, "Third": false, "Fourth": false }
Codepen - https://codepen.io/Pratik__007/pen/poymOqm
and if you want First to open default then you can set "First":true in selected_model.
I use Vue.js for validation but it throws an error:
vue.esm.js?a026:628 [Vue warn]: Property or method "$v" is not defined
on the instance but referenced during render. Make sure that this
property is reactive, either in the data option, or for class-based
components, by initializing the property. See:
https://v2.vuejs.org/v2/guide/reactivity.html#Declaring-Reactive-Properties.
But I don't know how to handle it.
Login.Vue:
<template>
<div id="login">
<CContainer class="d-flex content-center min-vh-100">
<CRow>
<CCol>
<CCardGroup>
<CCard class="p-4">
<CCardBody>
<CForm>
<h1>Login</h1>
<p class="text-muted">Sign In to your account</p>
<CInput
type="text"
placeholder="Username"
required
update:value="username"
input:error-messages="usernameErrors"
#input="$v.username.$touch()"
#blur="$v.username.$touch()"
required
autocomplete="username email"
>
<template #prepend-content><CIcon name="cil-user"/></template>
</CInput>
<CInput
placeholder="Password"
input:rules="passwordRules"
type="password"
required
iuodate:value="password"
input="$v.password.$touch()"
#blur="$v.password.$touch()"
#input="$v.password.$touch()"
autocomplete="current-password"
>
<template #prepend-content><CIcon name="cil-lock-locked"/></template>
</CInput>
<CRow>
<CCol col="6" class="text-left">
<CButton color="primary" class="px-4" #click="direDisplay">Login</CButton>
</CCol>
<CCol col="6" class="text-right">
<CButton color="link" class="px-0">Forgot password?</CButton>
<CButton color="link" class="d-md-none">Register now!</CButton>
</CCol>
</CRow>
</CForm>
</CCardBody>
</CCard>
<CCard
color="primary"
text-color="white"
class="text-center py-5 d-sm-down-none"
body-wrapper
>
<h2>Sign up</h2>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
<CButton
color="primary"
class="active mt-3"
>
Register Now!
</CButton>
</CCard>
</CCardGroup>
</CCol>
</CRow>
</CContainer>
</div>
</template>
<script>
import Dashboard from '../Dashboard.vue';
import { required,minlength,username,password } from 'vuelidate/lib/validators'
import { mapState, mapActions } from 'vuex'
export default {
name: 'Login',
methods:{
direDisplay(){
// console.log(this.id=this.$refs.groupid.value);
// console.log('pasword is ' +password);
//this.$router.push('/Dashboard')
if (this.data.username==='Abc' && this.data.password==='Abc123#') {
this.$router.push('/Dashboard')
} else {
alert('password username cannot match');
}
}
}
}
</script>
Sorry I don't have enough reputation to comment the post, but, as per this, you need to add validations property in your component.
Maybe we can try that one first as I don't see it in your code
Make sure you use the vuelidate plugin.
Also make sure you defined the plugin with .use before you created the instance of vue:
import Vuelidate from 'vuelidate'
Vue.use(Vuelidate)
new Vue({
render: function (h) { return h(App) }
}).$mount('#app')
validations: {
form1: {
phone: { required },
name: { required },
},
form2: {
parol1: { required, minLength: minLength(6) },
},
form3: {
password: { required, minLength: minLength(8) },
password2: { required, sameAsPassword: sameAs("password") },
},
}
try adding validations object to your code before adding it you should call it in your page or component.
The docs say
<a #click="doSomething"> ... </a>
is short-hand for
<a v-on:click="doSomething"> ... </a>
Why does this short-hand not work in all cases? For example,
<v-dialog v-model="dialog" width="500">
<template v-slot:activator="{ on }">
<v-btn dark v-on="on">Working button</v-btn>
<v-spacer />
<v-btn dark #on="on">Non-working button</v-btn>
</template>
<v-card>
<v-card-title>Some Dialog</v-card-title>
<v-card-text>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
</v-card-text>
</v-card>
</v-dialog>
The "Working button" works, but the "Non-working button" doesn't. It seems like the v-on shorthand only works for events. But if that's true, I haven't seen it documented.
I'm using Vuetify in this example, but my question is about Vue.js in general.
Here's a CodePen of above: https://codepen.io/keeganwitt/pen/bGGVeZY
v-on:click short hand is #click not #on
so you can use #click instead of v-on="on". But here slotProp on is an Object with click (function) property. so you can use it like below
<v-btn dark #click="on.click">Now working button</v-btn>
but it is recommended to use v-on="on" since there could be multiple properties under on Object
Ex: if on is { click: fn(), mouseup: fn() }
<v-btn dark #click="on.click" #mouseup="on.mouseup" >Now working button</v-btn>
<!-- same as -->
<v-btn dark v-on="on">Now working button</v-btn>
So, #on in your example is shorthand for v-on:on, meaning that the event handler is listening for the child component to emit an on event. The v-btn component does not ever emit an on event, so nothing ever happens.
This isn't the thrust of your question, but you technically can use the v-on shorthand to bind to an on event:
Vue.config.devtools = false;
Vue.config.productionTip = false;
Vue.component('toggle', {
template: `
<button #click="onClick">
{{ isOn ? 'On' : 'Off' }}
</button>
`,
data() {
return {
isOn: false
};
},
methods: {
onClick() {
this.isOn = !this.isOn;
if (this.isOn) {
this.$emit('on');
} else {
this.$emit('off');
}
}
}
});
new Vue({
el: '#app',
methods: {
alert(val) {
alert(val);
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<toggle #on="alert('on')" #off="alert('off')"/>
</div>
I think what is confusing you is the v-on="on" syntax. It's not obvious from the code, but the on variable being set as the value for v-on in this case is not a function, but an object.
From the vue docs on v-on:
Starting in 2.4.0+, v-on also supports binding to an object of event/listener pairs without an argument. Note when using the object syntax, it does not support any modifiers.
So the on variable in this case probably looks something like this:
{ click: onClick, mouseover: onMouseover }
Passing all of the event listeners this way allows for less boilerplate code. The way you would need to do this before v2.4 was like this:
<template v-slot:activator="{ onClick, onMouseover }">
<v-btn
dark
#click="onClick"
#mouseover="onMouseover"
>
Working button
</v-btn>
</template>
I think boostrap-vue carousel not so detailed. For this reason i can't reach to nice solution.
I wanna just show 3 items (like in image) in my app and i didnt find the solution and i searched other package and there was no solution for me.
All i want to do like this;
data() {
return {
slide: 0,
sliding: null
};
},
methods: {
onSlideStart(slide) {
this.sliding = true;
},
onSlideEnd(slide) {
this.sliding = false;
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div>
<b-carousel id="carousel-1" v-model="slide" :interval="0" controls indicators background="white" img-width="650" img-height="480" #sliding-start="onSlideStart" #sliding-end="onSlideEnd">
<b-carousel-slide caption="First slide" text="Nulla vitae elit libero, a pharetra augue mollis interdum." img-src="https://picsum.photos/1024/480/?image=52"></b-carousel-slide>
<b-carousel-slide img-src="https://picsum.photos/1024/480/?image=54">
<h1>Hello world!</h1>
</b-carousel-slide>
<b-carousel-slide img-src="https://picsum.photos/1024/480/?image=58"></b-carousel-slide>
<b-carousel-slide>
<img slot="img" class="d-block img-fluid w-100" width="1024" height="480" src="https://picsum.photos/1024/480/?image=55" alt="image slot">
</b-carousel-slide>
</b-carousel>
<p class="mt-4">
Slide #: {{ slide }}<br> Sliding: {{ sliding }}
</p>
</div>
If you have any other library suggestion i would appreciate.
Thanks for help.
BootstrapVue <b-carousel> is designed to only show a single slide at a time (as is the standard bootstrap V4.x carousel component). There are never more than 2 slides visible at once (during the slide or fade transition, all other slides are hidden. CSS transforms are used to make the appearance of the slides moving)
You would need to either find a 3rd party component that supports multiple slides showing, or generate your own custom component.
I'm not familiar with this specific component, but this is from its documentation:
<!-- Slide with blank fluid image to maintain slide aspect ratio -->
<b-carousel-slide caption="Blank Image" img-blank img-alt="Blank image">
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse eros felis, tincidunt
a tincidunt eget, convallis vel est. Ut pellentesque ut lacus vel interdum.
</p>
</b-carousel-slide>
I would try using a blank image as the default and inserting whatever other images/content you want as children of the slide:
<!-- Slide with blank fluid image to maintain slide aspect ratio -->
<b-carousel-slide caption="Blank Image" img-blank img-alt="Blank image">
<img class="my-img" src="img1.jpg"/>
<img class="my-img" src="img2.jpg"/>
<img class="my-img" src="img3.jpg"/>
</b-carousel-slide>
And use absolute positioning or flexbox to display them the way you want.
I did the same thing using b-card-group. Because b-carousel does not support showing multiple items.
In template area
<div>
<!-- carousel area -->
<b-card-group deck class="mb-0">
<b-card v-for="(item,index) in currentPageCards" :key="index" class="mr-0">
<!-- card content -->
</b-card>
</b-card-group>
<!-- pagination area -->
<div class="pagination" v-if="cards.length>cardsPerPage">
<div class="index" v-for="i in pageCount" :key="i" #click="next(i)" :class={active:currentPage(i)}></div>
</div>
</div>
In script area
data() {
return {
cards: [{
//Data in the card as objects
},{},{},{},{}],
paginatedCards:[],
pageCount:0,
cardsPerPage:4,
currentPageIndex:0
}
},
computed: {
currentPageCards(){
this.createPages();
return this.paginatedCards[this.currentPageIndex];
}
},
methods:{
currentPage(i){
return i-1===this.currentPageIndex;
},
createPages() {
let cardsLength = this.cards.length;
let fullPagesCount = Math.floor(cardsLength/this.cardsPerPage);
if(cardsLength>this.cardsPerPage) {
this.pageCount = 0;
for (let i = 0; i < fullPagesCount * this.cardsPerPage; i += this.cardsPerPage) {
this.paginatedCards[this.pageCount] = this.cards.slice(i,i + this.cardsPerPage);
this.pageCount++;
}
this.paginatedCards[this.pageCount] = this.cards.slice(cardsLength-this.cardsPerPage,cardsLength);
this.pageCount = this.pageCount+1;
} else {
this.paginatedCards[0] = this.cards;
}
},
next(i){
this.currentPageIndex=i-1;
}
}
In style area
.pagination{
display:flex;
align-items: center;
justify-content: center;
padding:10px;
}
.index{
margin-left:10px;
width:10px;
height:10px;
background:#000000
}
.active{
width:15px;
height:15px;
}
It shows like as below
Try this one. Thank you!