html5中嵌套拖拽问题

422 阅读1分钟

1. 需求

做一个视频投屏墙的弹窗,弹窗可以拖拽,里面的视频也要可以拖拽调换顺序,项目是vue的

image.png

2. 基础代码结构

    <!-- 使用了vue-draggable-resizable 插件作为弹窗主题可拖拽的部分 -->
    <vue-draggable-resizable
      :resizable="false"
      :draggable="true"
      @dragging="containerDragging"
      :w="960"
      v-show="videosscreenshow"
      class="videosPopover"
      style="border: none"
    >
    <!-- 头部 -->
    <div class="header"></div> 
    <!-- 主体部分,也就是视频墙 -->
    <div v-for="videoGridItem in item.gridIndex" draggable="true"  @dragstart="videoDragstart" @dragend="videoDragend" @drop="videoDragenter" @dragover="dragover" :id="['videogrid_'+videosGroupValue+'_'+item.gridIndex+'_'+videoGridItem]" class="js_videogrid">
                    <div class="deleteVideo" title="删除" @click="delVideo('video_'+(index+1)+'_'+item.gridIndex+'_'+videoGridItem)">x</div>
                    <video class="js-media" name="videoElement" :id="['video_'+(index+1)+'_'+item.gridIndex+'_'+videoGridItem]" autoplay >
                      <p>你的浏览器不支持 HTML5 Video。</p>
                    </video>
                  </div>
    </vue-draggable-resizable>

3. 出现的第一个问题

主体部分我是用draggable="true"实现的,当拖动里面的视频块的时候,整个弹窗会跟着动,这个问题比较明显,就是没有阻止子元素的拖拽事件冒泡,稍作修改,加上stop指令阻止冒泡:

<div v-for="videoGridItem in item.gridIndex" draggable="true" @dragstart.stop="videoDragstart" @dragend.stop="videoDragend" @drop.stop="videoDragenter" @dragover.stop="dragover" :id="['videogrid_'+videosGroupValue+'_'+item.gridIndex+'_'+videoGridItem]" class="js_videogrid">
                    <div class="deleteVideo" title="删除" @click="delVideo('video_'+(index+1)+'_'+item.gridIndex+'_'+videoGridItem)">x</div>
                    <video class="js-media" name="videoElement" :id="['video_'+(index+1)+'_'+item.gridIndex+'_'+videoGridItem]" autoplay >
                      <p>你的浏览器不支持 HTML5 Video。</p>
                    </video>
                  </div>

4. 出现的第二个问题

拖拽视频调整顺序后,鼠标抬起,但弹窗依旧跟着动,像粘在鼠标上了一样。。。

拖拽修改前.gif

5. 分析问题解决问题

鼠标左键抬起,拖拽的效果还在,而且是从子节点传递到父节点的事件,虽然我已经将拖拽开始事件阻止冒泡了(dragstart.stop),但是应该还是有什么事件漏出去给父节点了,那这个事件是什么呢? 只有鼠标按下去的事件了mousedown,所以将子节点的mousedown事件也阻止冒泡,修改后的代码:

<div v-for="videoGridItem in item.gridIndex" draggable="true" @mousedown.stop @dragstart.stop="videoDragstart" @dragend.stop="videoDragend" @drop.stop="videoDragenter" @dragover.stop="dragover" :id="['videogrid_'+videosGroupValue+'_'+item.gridIndex+'_'+videoGridItem]" class="js_videogrid">
                    <div class="deleteVideo" title="删除" @click="delVideo('video_'+(index+1)+'_'+item.gridIndex+'_'+videoGridItem)">x</div>
                    <video class="js-media" name="videoElement" :id="['video_'+(index+1)+'_'+item.gridIndex+'_'+videoGridItem]" autoplay >
                      <p>你的浏览器不支持 HTML5 Video。</p>
                    </video>
</div>

6. 最终效果与总结

拖拽视频修改后.gif

有些事件,是由多个事件组合而来的,比如click,就是由mousedown和mouseup组成的。涉及冒泡的时候要仔细考虑事件的顺序。