背景:

在使用vuedraggable做一个拖动应用图片排序的场景下,在android、iOS、chrome模拟移动设备 的情况,应用图片用的是svg,大概率会出现ghost元素不消失,也不触发end事件的诡异情况。

注意

PC端使用chrome 调试模式下,不开启模拟移动设备不会出现这种情况,开启来模拟移动设备也会出现。

解决办法

给svg元素设置一个css样式,即可;

svg {

pointer-events: none;

}

原因分析

根据上面出现,没有触发end事件,查看vuedraggable源代码,可以看到vuedraggable是通过监听类似:touchend,mouseup,pointerup类似这样的事件,认为拖动结束,从而完成后续动作,移除ghost元素,并触发end事件。

分析步骤:

在chrome 调试下监听上面的三个touchend,mouseup,pointerup,发现只要出现上面的情况,这些事件都不会触发。从而可以判断是原来浏览器没有触发事件,在页面是移除图标,再此拖动,发现可以正常拖动排序。从而判断问题出现在图标上,图标使用的svg。
看浏览器性能面板,是不是拖动svg会造成大量渲染,从而导致浏览器卡顿,从而没有触发上面的事件,经过实验,并不是这个原因
猜测鼠标移动svg上,因为svg本身就具有动画的效果,是不是和外面的事件冲突,阻挡了事件触发,实验在svg上用绝对定位放了一个空白的元素,发现问题解决。在这个思路上继续找相关的答案,找到css属性 pointer-events

pointer-events

【 CSS 属性指定在什么情况下 (如果有) 某个特定的图形元素可以成为鼠标事件的 target" 】。具体参考 pointer-events MDN的说明。

语法:

pointer-events属性被指定为从下面的值列表中选择的一个关键字。

  • auto
    与pointer-events属性未指定时的表现效果相同,对于SVG内容,该值与visiblePainted效果相同
  • none
    元素永远不会成为鼠标事件的target。但是,当其后代元素的pointer-events属性指定其他值时,鼠标事件可以指向后代元素,在这种情况下,鼠标事件将在捕获或冒泡阶段触发父元素的事件侦听器。
  • visiblePainted
    只适用于SVG。元素只有在以下情况才会成为鼠标事件的目标:
    visibility属性值为visible,且鼠标指针在元素内部,且fill属性指定了none之外的值
    visibility属性值为visible,鼠标指针在元素边界上,且stroke属性指定了none之外的值
  • visibleFill
    只适用于SVG。只有在元素visibility属性值为visible,且鼠标指针在元素内部时,元素才会成为鼠标事件的目标,fill属性的值不影响事件处理。
  • visibleStroke
    只适用于SVG。只有在元素visibility属性值为visible,且鼠标指针在元素边界时,元素才会成为鼠标事件的目标,stroke属性的值不影响事件处理。
  • visible
    只适用于SVG。只有在元素visibility属性值为visible,且鼠标指针在元素内部或边界时,元素才会成为鼠标事件的目标,fill和stroke属性的值不影响事件处理。
  • painted
    只适用于SVG。元素只有在以下情况才会成为鼠标事件的目标:
    鼠标指针在元素内部,且fill属性指定了none之外的值
    鼠标指针在元素边界上,且stroke属性指定了none之外的值
    visibility属性的值不影响事件处理。
  • fill
    只适用于SVG。只有鼠标指针在元素内部时,元素才会成为鼠标事件的目标,fill和visibility属性的值不影响事件处理。
  • stroke
    只适用于SVG。只有鼠标指针在元素边界上时,元素才会成为鼠标事件的目标,stroke和visibility属性的值不影响事件处理。
  • all
    只适用于SVG。只有鼠标指针在元素内部或边界时,元素才会成为鼠标事件的目标,fill、stroke和visibility属性的值不影响事件处理。
    根据上面的属性说明,可以看到默认的情况下,svg:visiblePainted,我们使用的svg是从sketch 软件导出的,里面确实包含fill, stroke属性,最终我们选择粗暴的方式,设置为 “none” 解决。