Vue3中如何阻止拖拽按钮时触发@click事件?
问题
我制作了可拖拽按钮,用户可在屏幕任意位置拖动它,点击按钮时会弹出通知。但存在问题:拖拽按钮的操作会被判定为@click事件,导致通知自动弹出,我希望阻止该场景下的点击事件。
原代码:
<script setup> import { ref } from 'vue' import IconSoundFilled from '~icons/ant-design/sound-filled' import { useDraggable } from '@vueuse/core' import PageSubtitle from '../../common/components/Atom/PageSubtitle.vue' import { useTimestamp } from '@vueuse/core' const visible = ref<boolean>(false) const el = ref<HTMLElement | null>(null) const { x, y, style } = useDraggable(el, { initialValue: { x: 500, y: 60 } }) const noticeList: object[] = [ { title: 'yo' }, { title: 'yo' }, { title: 'yo' }, { title: 'yo' }, { title: 'yo' }, { title: 'yo' } ] const timestamp = useTimestamp({ offset: 0 }) const date = new Date(timestamp.value) </script> <template> <button ref="el" :style="style" class="item bg-gray-dark fixed z-10 h-[54px] w-[54px] rounded-full shadow-lg" @click="visible = !visible" > <button class="bg-red absolute top-0.5 right-0.5 h-[15px] w-[15px] rounded-full text-xs font-bold text-white" > 1 </button> <div class="flex justify-center"> <IconSoundFilled class="hover:text-red text-xl text-white" /> </div> </button> <div v-if="visible" class="bg-white-light border-gray fixed h-96 w-4/6 overflow-auto rounded-md border border-solid px-6 py-2" > <div class="mb-3 flex justify-center"> <PageSubtitle text="Notice" class="right-auto" /> </div> <div v-for="(item, index) in noticeList.slice().reverse()" :key="index" class="flex gap-6 text-sm" > <IconSoundFilled v-if="index == 0" class="text-red text-xl" /> <IconSoundFilled v-else class="text-xl text-black" /> {{ item.title }} {{ date }} <br /> <br /> </div> </div> </template>
解决方法
核心思路是利用useDraggable返回的isDragging状态,区分拖拽操作和纯点击操作,仅在非拖拽状态下触发弹窗切换。
修改后的完整代码
<script setup> import { ref } from 'vue' import IconSoundFilled from '~icons/ant-design/sound-filled' import { useDraggable } from '@vueuse/core' import PageSubtitle from '../../common/components/Atom/PageSubtitle.vue' import { useTimestamp } from '@vueuse/core' const visible = ref<boolean>(false) const el = ref<HTMLElement | null>(null) // 解构出useDraggable内置的isDragging状态 const { x, y, style, isDragging } = useDraggable(el, { initialValue: { x: 500, y: 60 } }) const noticeList: object[] = [ { title: 'yo' }, { title: 'yo' }, { title: 'yo' }, { title: 'yo' }, { title: 'yo' }, { title: 'yo' } ] const timestamp = useTimestamp({ offset: 0 }) const date = new Date(timestamp.value) // 封装点击逻辑,仅在非拖拽状态下切换弹窗 const toggleNotice = () => { if (!isDragging.value) { visible.value = !visible.value } } </script> <template> <button ref="el" :style="style" class="item bg-gray-dark fixed z-10 h-[54px] w-[54px] rounded-full shadow-lg" @click="toggleNotice" > <button class="bg-red absolute top-0.5 right-0.5 h-[15px] w-[15px] rounded-full text-xs font-bold text-white" > 1 </button> <div class="flex justify-center"> <IconSoundFilled class="hover:text-red text-xl text-white" /> </div> </button> <div v-if="visible" class="bg-white-light border-gray fixed h-96 w-4/6 overflow-auto rounded-md border border-solid px-6 py-2" > <div class="mb-3 flex justify-center"> <PageSubtitle text="Notice" class="right-auto" /> </div> <div v-for="(item, index) in noticeList.slice().reverse()" :key="index" class="flex gap-6 text-sm" > <IconSoundFilled v-if="index == 0" class="text-red text-xl" /> <IconSoundFilled v-else class="text-xl text-black" /> {{ item.title }} {{ date }} <br /> <br /> </div> </div> </template>
关键说明
isDragging是useDraggable内置的响应式状态,拖拽过程中自动变为true,拖拽结束后恢复false- 通过点击事件中对
isDragging.value的判断,精准过滤拖拽操作带来的误触发,仅在纯点击时切换弹窗可见性
内容的提问来源于stack exchange,提问作者BrownEyedSoul
相关产品推荐
相关产品推荐

