|
|
|
<template>
|
|
|
|
<div class="quantity">
|
|
|
|
<div class="val">
|
|
|
|
{{val}}
|
|
|
|
</div>
|
|
|
|
<div class="border-end-0 btns">
|
|
|
|
<i class="ri-arrow-up-s-line"
|
|
|
|
@mousedown="startIncrement"
|
|
|
|
@mouseup="stopChange"
|
|
|
|
@mouseleave="stopChange"></i>
|
|
|
|
<i class="ri-arrow-down-s-line"
|
|
|
|
@mousedown="startDecrement"
|
|
|
|
@mouseup="stopChange"
|
|
|
|
@mouseleave="stopChange"></i>
|
|
|
|
</div>
|
|
|
|
<input type="hidden" :name="xname" v-if="xname != null" :value="val">
|
|
|
|
</div>
|
|
|
|
</template>
|
|
|
|
|
|
|
|
<script>
|
|
|
|
export default {
|
|
|
|
name: "quantity",
|
|
|
|
data: () => ({
|
|
|
|
val: 1,
|
|
|
|
interval: null,
|
|
|
|
timeout: null,
|
|
|
|
changeSpeed: 100, // milliseconds between each change
|
|
|
|
startDelay: 1000, // 1 second delay before rapid change starts
|
|
|
|
}),
|
|
|
|
emits: ['update:modelValue'],
|
|
|
|
props: {
|
|
|
|
min: {
|
|
|
|
default: 1,
|
|
|
|
type: Number,
|
|
|
|
},
|
|
|
|
max: {
|
|
|
|
default: 99,
|
|
|
|
type: Number,
|
|
|
|
},
|
|
|
|
xname: {
|
|
|
|
default: null,
|
|
|
|
type: [null, String],
|
|
|
|
},
|
|
|
|
modelValue: {
|
|
|
|
type: Number,
|
|
|
|
default: 1,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
methods: {
|
|
|
|
inc() {
|
|
|
|
if (this.val < this.max) {
|
|
|
|
this.val++;
|
|
|
|
this.$emit('update:modelValue', this.val);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
dec() {
|
|
|
|
if (this.val > this.min) {
|
|
|
|
this.val--;
|
|
|
|
this.$emit('update:modelValue', this.val);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
startIncrement() {
|
|
|
|
this.inc(); // Immediate first increment
|
|
|
|
this.timeout = setTimeout(() => {
|
|
|
|
this.interval = setInterval(this.inc, this.changeSpeed);
|
|
|
|
}, this.startDelay);
|
|
|
|
},
|
|
|
|
startDecrement() {
|
|
|
|
this.dec(); // Immediate first decrement
|
|
|
|
this.timeout = setTimeout(() => {
|
|
|
|
this.interval = setInterval(this.dec, this.changeSpeed);
|
|
|
|
}, this.startDelay);
|
|
|
|
},
|
|
|
|
stopChange() {
|
|
|
|
clearTimeout(this.timeout);
|
|
|
|
clearInterval(this.interval);
|
|
|
|
},
|
|
|
|
},
|
|
|
|
beforeUnmount() {
|
|
|
|
this.stopChange();
|
|
|
|
},
|
|
|
|
}
|
|
|
|
</script>
|
|
|
|
|
|
|
|
<style scoped>
|
|
|
|
.quantity {
|
|
|
|
direction: ltr;
|
|
|
|
border: 1px solid rgba(128, 128, 128, 0.56);
|
|
|
|
display: grid;
|
|
|
|
grid-template-columns: 2fr 1fr;
|
|
|
|
width: 90px;
|
|
|
|
height: 50px;
|
|
|
|
border-radius: var(--xshop-border-radius);
|
|
|
|
|
|
|
|
.val{
|
|
|
|
display: flex;
|
|
|
|
align-items: center;
|
|
|
|
justify-content: center;
|
|
|
|
font-size: 17px;
|
|
|
|
}
|
|
|
|
|
|
|
|
i{
|
|
|
|
display: block;
|
|
|
|
transition: 377ms;
|
|
|
|
|
|
|
|
&:first-child{
|
|
|
|
border-bottom: 1px solid rgba(128, 128, 128, 0.56);
|
|
|
|
}
|
|
|
|
|
|
|
|
&:hover{
|
|
|
|
background: var(--xshop-primary);
|
|
|
|
color: var(--xshop-diff);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
.btns{
|
|
|
|
border: 1px solid rgba(128, 128, 128, 0.56);
|
|
|
|
border-bottom: 0;
|
|
|
|
border-top: 0;
|
|
|
|
text-align: center;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
</style>
|