I have a button containing a child component which consists of a circle made with a div. I want the circle to change color when the user clicks with a mouse or touches the screen. I tried this and it kinda works but something is wrong because only the touchstart event is not causing the class to change.
I tried logging the value of flag
in both the parent and child and even inspected the element manually to see if the class changed. The weird thing is, the values logged to the console are correct. When I touch-and-hold the button, flag
is true and color.value
is green
but upon inspection (by pressing F12), Child component's class in the DOM is still red
.
I tried using a different child component which is built from SVG and the same thing happens. The problem must be with the events. I learnt somewhere that touchstart/touchend
events will be triggered first, followed by mousedown/mouseup
then click
. So I was thinking of just responding to mousedown/mouseup
, to which the same problem is occuring.
I also tried commenting out the // Suggested solutions
which worked for both mousedown and touchstart but for touchstart there was a delay between the color change and the button reacting(the native button press animation)
Can someone explain to me what is going on? And how I can enable the button to react and change its content's styles upon touch and click?
Would appreciate any comments or help. Thank you very much.
My Button component
<template>
<button class="slot-header slot-header-btn"
ref="btn"
@mousedown="cb"
@mouseup="cbEnd"
>
<Child :flag="pressed"/>
</button>
</template>
<script>
import { ref } from "vue"
import Child from './assets/Child.vue'
const pressed = ref<boolean>(false)
function cb(event: any) {
// Suggested solution
console.log("Mouse down")
if(event.handled === false) return
event.stopPropagation()
event.preventDefault()
event.handled = true
// My own logic
pressed.value = true
}
function cbEnd(event: any) {
// Suggested solution
console.log("Mouse up")
if(event.handled === false) return
event.stopPropagation()
event.preventDefault()
event.handled = true
// My own logic
pressed.value = false
}
</script>
My Child component
<template>
<div :class="`circle ${color}`">
</div>
</template>
<script setup lang="ts">
import { computed, PropType, toRefs, watch } from 'vue';
const props = defineProps({
flag: {
type: Boolean as PropType<boolean>,
required: false,
default: () => false
}
})
const { flag } = toRefs(props)
const color = computed<string>(() => flag.value ? "green" : "red")
watch(() => flag.value, (newValue, oldValue) => {
console.log(`Child color.value: ${color.value}`)
console.log(`Child flag.value: ${newValue}`)
})
</script>
<style scoped>
.circle {
width: 20px;
height: 20px;
border-radius: 50%;
}
.red {
background-color: red;
}
.green {
background-color: greenyellow;
}
</style>