• 【技术博客】移动端的点击事件与Sticky Hover问题


    移动端的点击事件与Sticky Hover问题

    v1.0

    作者:ZBW

    TL;DR

    解决办法是:在:hover伪类外使用@media区分设备,在移动设备上使hover效果不生效。

    @media (hover: hover) {
        .desexp-text:hover  {
            opacity:1;
        }
    }
    

    这一方法的缺点是问题在带有触控的PC上仍可能存在,但对于大多移动设备来说足以应付了。

    前言

    笔者起初认为该问题是JS的点击事件绑定有误导致的,但之后却发现问题出在CSS上。因此本文除了解决问题外,也会介绍以下笔者的踩坑历程,顺带介绍一下移动端点击事件的不同。

    问题描述

    背景

    在Beta阶段,团队想要在项目中实现设计性实验复习的页面。该页面的主要使用方式是团队预先在整理好的复习资料中挖一些空,然后用户通过交互来显示/隐藏答案。计划的交互方式是:

    1. 鼠标放在空上,答案显示出来。鼠标移开答案消失

    2. 鼠标点一下空,答案显示,移开鼠标也不会消失。再次点击将恢复隐藏的状态。

    3. 实现一个清空答案的按钮,可以一键清空所有显示的答案。

    实现方式

    该功能的实现方式非常简单。对于1,直接使用CSS的:hover伪类配合透明度即可解决。对于2和3,可以使用JS来监听点击事件,并且根据点击事件和目前的显示状态对透明度进行切换。

    为了实现这一功能,首先我们对所有挖空的文本外套了两个html标签(span和text),并分别以class区分,形如:

    <span class='desexp-span'><text class='desexp-text'>被挖空的内容</text></span>
    

    并且分别以如下的CSS和JS实现上述的效果

    span.desexp-span {
        border-bottom: 1px solid rgb(200, 200, 200);
    }
    .desexp-text {
        opacity:0;
        transition: opacity 1s;
        -webkit-transition: opacity 1s;
    }
    .desexp-text:hover  {
        opacity:1;
    }
    
    var inners = document.getElementsByClassName("desexp-text");
    var myfunction = function () {
        if (this.style.opacity === 1)
            this.style.opacity = "";
        else
            this.style.opacity = 1;
    };
    for (var i = 0; i < inners.length; i++) {
        inners[i].addEventListener('click', myfunction, false);
    }
    

    清空答案的按钮实现也很简单(代码中是从iframe内读取内容):

        let inners = document.getElementById("desexp-iframe").contentWindow.document.getElementsByClassName("desexp-text");
        for (var i = 0; i < inners.length; i++) {
            inners[i].style.opacity = "";
        }
    

    实现的效果如下:

    问题

    该实现在PC端的浏览器下表现正常,但当使用手机进行操作时就会出现问题。

    在手机上点击挖空的位置,答案显示正常。当再次点击挖空时,答案却不会消失,而如果此时点击另一个空,之前的答案便会消失。除此之外清空答案按钮不起作用。

    关于移动端浏览器的点击事件

    自第一代iPhone于2007年发布以来,人们在手机上浏览网页的方式发生了很大的变化。2007年时大多数网页并没有考虑过在手机上被浏览的问题,为了在iPhone上方便浏览桌面网页,工程师们实现了双击放大的功能,使在手机浏览器上双击屏幕就能将网页内容放大。从而为了区分双击放大和点击操作,浏览器在监听到点击事件后,会等待300ms判断用户是否再次点击屏幕,只有300ms后才会触发正常的点击事件。

    初次发现问题后各种解决尝试:从点击事件本身下手

    cursor: pointer

    该方法来源于此:stackoverflow

    看起来iOS Safari中的点击事件是一个非常麻烦的问题,回答提出的解决办法非常简单,在CSS中开头添加:

    cursor: pointer
    

    区分设备分别使用click和touchend

    来源:如何解决移动端的点击事件?

    var clickEvent = 'ontouchend' in document ? 'touchend' : 'click';
    $(ele).on(clickEvent, function(event) {
        // 如果在移动端,一定要记得阻止默认事件
        event.preventDefault();
        // do something
    })
    

    以上的方法并不凑效。

    问题的根源:CSS中:hover伪类在移动端的表现问题

    实际上在笔者尝试了很多办法之后,意识到了问题的所在其实不在点击事件上,因为点击显示的效果是正常的,300ms的影响也不大,点击事件在设备上能够被正常触发。

    使用Chrome的响应式界面调试时发现,第二次触摸后标签上的style属性被正常移除了,说明JS代码工作正常。因而让文字透明度保持为1的也只有:hover属性了。

    经查资料后发现,:hover在移动端的表现类似于PC端的:focus,由于没有鼠标指针的存在,点击元素时:hover就会生效,并且直到点击别的地方时:hover的作用才会消失。

    除此之外,iOS Safari在以上问题上还存在bug,点击别的地方时:hover也不会消失,被称为Sticky Hover问题:iOS 'Sticky Hover' Fix。只有点击另一个可以被focus的元素时之前的hover才会失效

    解决办法

    来源:How to prevent sticky hover effects for buttons on touch devices

    该方法应用了CSS中的媒体查询(media query),检查浏览器是否支持hover功能。支持hover功能的设备往往具有独立的鼠标指针输入(不限于PC,也可能是某些游戏机内的浏览器,使用摇杆操作鼠标指针)。

    在CSS中应用方法如下:

    @media (hover: hover) {
        .desexp-text:hover  {
            opacity:1;
        }
    }
    

    简而言之,即用@media将:hover伪类的内容括起来即可。从而在不能使用鼠标指针的设备上就不存在该效果了。

    该方法的一些小问题是在一些支持触控的PC上原先的问题仍可能存在,但对于解决移动端问题来说该方法非常实用。

  • 相关阅读:
    redis的常用命令及php-redis的使用
    mysql数据库基本操作
    php接口数据安全解决方案
    如何防止api接口被恶意调用或攻击
    virtualBox安装及调试
    PHP常用扩展
    memcached安装与应用
    Jmeter的基础使用(4)——添加服务器的监控
    Jmeter的基础使用(3)——使用实操
    Jmeter的基础使用(2)——线程的添加以及基本使用
  • 原文地址:https://www.cnblogs.com/hardchoice/p/11008962.html
Copyright © 2020-2023  润新知