两天前,客户方提出了便捷工作台的需求,通俗点来说,可通过拖拽、增减等操作,将菜单拖入到想放置的模块中,同时可对大模块拖拽排序,最终以配置的模块或菜单,在首页进行展示。该需求,实现逻辑上其实很简单明了,无非是确定拖拽区域,拖拽对象,按照一定规则操作菜单,但在大的功能做完之后,遗留了一些小的bug,这些小bug容易让人遗漏。因此,在这里记录一下。

一、实现流程

目前项目适用框架:vue2+ant-design-vue

拖拽组件:vuedraggable

  • 页面布局首页以flex布局去实现,完成固定两行,列数自适应的布局。

弹窗采用ant-design提供的模态框组件去封装,同时根据业务需求,接入vuedraggable组件。这里代码比较简单,直接贴图,具体实现不做赘述。

二、遇到的问题

  • 2.1、弹框引发滚动穿透> 问题描述:在打开的弹窗中,设置滚动区域,当滚动到弹窗底部或头部,同时超出父级元素滚动区域时,会出现父级div同时滚动现象,也就是所谓的滚动穿透。

如何处理:监听弹窗元素滚动开始start方法,在该方法中,将根元素滚动属性隐藏,对弹窗滚动结束end方法监听,恢复根元素的滚动属性。

<draggable @start="start" @end="end"></draggable>

start() {// 防止拖动时,滚动穿透document.getElementById('app').style.overflow = 'hidden'
},
end() {document.getElementById('app').style.overflow = ''
}, 
  • 2.2、关闭弹窗后,首页展示区域局部渲染> 问题描述:对弹窗内容操作之后,需要将弹窗中已经拖拽的元素,按照项目需求展示在首页某个区域中,由于vue只会在加载页面时渲染一次,因此关闭弹窗之后,首页区域不会重新渲染,因而出现了展示区域样式混乱现象。

如何处理:vue只有当组件内容获取样式发生改变之后,才会重新进行渲染,因此我们可以为组件设置key属性,key内容为当前时间值,由于时间值随时在改变,因此vue会重新渲染。

<div class="impact-quick-card-container" :key="new Date().getTime()"></div> 
  • 2.3、拖拽滚动区域> 问题描述:需要指定固定区域,进行拖拽操作,如何确认滚动区域?

如何处理:根据vuedraggable文档描述,可以设置handle属性,该属性中定义拖拽的元素,可以为需要退拽的区域dom设置该属性。

  • 2.4、多级元素拖动设计> 问题描述:需求为一个多层拖拽效果,即菜单可以拖拽到所属模块,同时所属模块也能互相拖动,用于排序,如何设置多级元素关联关系的元素拖动呢?

如何处理:首先将模块与菜单元素分层,内部菜单之间可拖动,设置group值为menu,外层模块元素区域,设置另外的group属性为module,通过group区别,来控制不同的拖拽分组。

<draggable group="module"><div v-for="(item, index) in modules" :key="index"><h3>{{ item.modelName }}</h3><draggable group="menu"><div v-for="(element, idx) in item.rows" :key="idx" class="move list-group-item "><span class="text" :title="element.benchName">{{ element.benchName }}</span><b class="list-group-item-icon" @click="subtractPage(item.rows, idx, element)">-</b></div></draggable></div>
</draggable> 
  • 2.5、拖拽时,无法同时滚动> 问题描述:当拖拽某个菜单元素且超过当前区域时,弹窗不向下滚动。

如何处理:vuedraggable文档提供了scrollSensitivity属性,用于描述拖拽距离滚动区域多远时,滚动条滚动。给draggable设置该属性,可以处理该问题。

<draggable group="menu" @start="start" :scrollSensitivity="250">
</draggable> 
  • 2.6、隐形滚动条> 问题描述:当出现滚动时,如何将滚动条做的更好看一些,也就是隐形滚动条,有滚动效果,但不出现浏览器原生滚动条。

如何处理:利用内外两层div包裹,通过css控制滚动区域,外层div滚动属性设置为hidden,内层利用position:fixed固定区域,同时设置overflow属性,这里要这与,如果想要隐藏浏览器的原生滚动条,需要设置内层区域高度或宽度高于外层区域。

<div class="impact-quick-card-container" :key="new Date().getTime()"><div class="quick-card-container"></div>
</div>

<style lang="less" scoped> .impact-quick-card-container {position: relative;height: 250px;overflow: hidden;.quick-card-container {display: flex;position: absolute;width: 100%;overflow-x: auto;overflow-y: hidden;}
} </style> 
  • 2.7、flex固定行的布局> 问题描述:如何利用flex布局,固定行,列随着设置动态变化。

如何处理:使用flex的column排序,解决不了该问题。只能通过writing-mode来处理。flex根元素设置writing-mode为vertical-lr,表示元素会从上到下垂直排列,其次flex子元素div上,设置writing-mode为horizontal-tb,表示该元素将水平从左到右排列,同时一定要设置子元素的flex宽度,使用50%将行划分为两行。

<div class="wrapper-content"><div class="module-wrapper" v-for="(menu, idx) in item.rows" :key="idx"></div>
</div>

<style lang="less" scoped> .wrapper-content {display: flex;writing-mode: vertical-lr;flex-wrap: wrap;padding: 15px 10px 5px 10px;height: 200px;.module-wrapper {flex: 0 0 50%;writing-mode: horizontal-tb;}
} </style> 
Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐