如何检测触摸屏设备上的悬停状态 - Vue 3

How to detect hover state on touchscreen device - Vue 3

在我的例子中,在桌面模式下,用户可以将鼠标悬停在元素上以显示菜单。用户还可以单击向服务器发出请求的元素。

在触摸屏模式下,我希望点击显示菜单而不是发出请求。

这似乎是不可能完成的任务,除非我开始走出 vue 并直接从 DOM 级别更改 css。

<script setup>
import { ref } from "vue";

const text = ref("whatever");
const isEditing = ref(false);
function sendToServer() {
  console.log("Sending request of ", text.value, " to server.")
  isEditing.value = false;
}
</script>

<template>
  <div class="wrapper">
    <span v-show="!isEditing" @click="sendToServer" @touchstart.prevent> {{ text }}</span>
    <input v-show="isEditing" v-model="text">
    <span @click="sendToServer" class="icon">➡️</span>
    <span @click="isEditing = !isEditing" class="icon">✏️</span>
  </div>
</template>

<style>
  .icon {
    opacity: 0;
  }
  
  .wrapper:hover .icon {
    opacity: 1;
  }
  
  .wrapper > span {
    cursor: pointer;
  }
</style>

Vue SFC playground link

“这似乎是不可能完成的任务,除非我开始走出 vue 并直接从 DOM 级别更改 css。”

我会说用 CSS-only 是不可能实现的,但是 Vue(恕我直言)似乎很强大并且很适合处理这个问题。

而不是使用 css :hover 您将需要使用状态来管理可见性(例如 isSelected

然后使用 @touchstart 切换可见性 - 这将仅适用于触摸设备和鼠标事件 @mouseover 显示和 @mouseout 隐藏。

处理一些边缘情况可能需要更多技巧,但这就是我实现它的方式。例如,您可能需要一个全局触摸事件侦听器,以便在用户单击文本外部时隐藏。

<script setup>
  import { ref } from "vue";

  const text = ref("whatever");
  const isEditing = ref(false);
  const isSelected = ref(false);
  function toggleIsSelected(){
        isSelected.value = !isSelected.value
  }
  function unselect(){
    isSelected.value = false;
  }
  function sendToServer() {
    console.log("Sending request of ", text.value, " to server.")
    isEditing.value = false;
  }
</script>

<template>
  <div class="wrapper">
    <span v-show="!isEditing"
          @click="sendToServer"
          @touchstart=toggleIsSelected
          @mouseover=toggleIsSelected
          @mouseout=unselect
    > {{ text }}</span>
    <input v-show="isEditing" v-model="text">
    <span v-show=isSelected @click="sendToServer" class="icon">➡️</span>
    <span v-show=isSelected @click="isEditing = !isEditing" class="icon">✏️</span>
  </div>
</template>

<style>
  .wrapper > span {
    cursor: pointer;
  }
</style>