web vue 滑动选择 n宫格选中 九宫格选中
页面动态布局经常性要交给客户来操作,他们按时他们的习惯在同一个屏幕内显示若干个子视图,尤其是在医学影像领域对于影像的同屏显示目视对比显的更为重要。
来看看如下的用户体验:
设计为最多支持5行6列页面展示后,右侧的布局则动态跟随来显示更多影像图像,在目视范围内则可以做出更多读片等判断操作。
下面来给出实现代码。
首先给出页面代码,因页面较为复杂,这里只给核心处的代码,你只需要重点关注el-popover组件位置的使用即可:
<div class="layout-view flex-row jc-center" v-for="layItem in layoutSeriTools" :key="layItem.icon" :class="{ 'tool-item-hl': layItem.selected }" @click="seriesLayoutAction(layItem)"> <el-image v-if="layItem.tag != 4" class="layout-item" :src="layItem.icon"></el-image> <el-popover ref="boxPopover_0" v-else class="layout-item" popper-class="pop-grid-view" placement="right-start" trigger="hover"> <div class="v-box-view" @mouseleave="leaveBoxAction(0)"> <div class="v-box-item-view" :class="{ 'hili-box': ibox.selected }" v-for="(ibox, ixIndex) in layItem.child" :key="ixIndex" @mouseenter="hoverBoxAction(0, ibox)" @click="boxClickAction(0)"></div> </div> <el-image slot="reference" class="layout-item" :src="layItem.icon"></el-image> </el-popover> <el-image v-if="layItem.tag == 4" class="down-view" :src="require('@/assets/images/downArrow.png')"></el-image> </div>
我使用的elmentUI,其主题默认是白色,我根据页面修改了组件的样式:你想改就改,不改就忽略。
<style lang="scss" scoped> .dropdown-menu-view { background: #222; background-color: #222; border: 2px solid #343434; } .dropdown-menu-item-view { color: white; &:hover { background-color: rgba(2, 134, 240, 0.2); color: white; } } </style> <style> .popperView.el-select-dropdown { border: 2px solid #343434; } .popperView .el-select-dropdown__list { background-color: #222; } /* 自定义选中的选项背景色 */ .popperView .el-select-dropdown__item.selected { background-color: rgba(2, 134, 240, 0.2); color: white; } /* 自定义鼠标悬停的选项背景色 */ .popperView .el-select-dropdown__item:hover { background-color: #ecf5ff; } .popperView .el-select-dropdown__item { background-color: transparent; &:hover { background-color: rgba(2, 134, 240, 0.2); color: white; } } .el-popper[x-placement^=top] .popper__arrow::after { border-top-color: #343434; } .el-popper[x-placement^=top] .popper__arrow { border-top-color: #343434; } .el-popper[x-placement^=bottom] .popper__arrow::after { border-bottom-color: #343434; } .el-popper[x-placement^=bottom] .popper__arrow { border-bottom-color: #343434; } .el-popper[x-placement^=right] .popper__arrow { border-right-color: #343434; } .el-popper[x-placement^=right] .popper__arrow::after { border-right-color: #343434 !important; } .pop-grid-view.el-popper { background: #1a1a1a; background-color: #1a1a1a; border: 3px solid #343434; padding: 0px; border-radius: 0px; } </style>
数据定义,元素从左到右均在数组中定义,只有最后一个元素时,才会显示自定义宫格功能,所以,数据仍然定义在其child中,注意其他元素并没有child。
layoutSeriTools: [{ tag: 0, icon: require("@/assets/images/layout-1.png"), title: '', selected: true, toolsId: '' }, { tag: 1, icon: require("@/assets/images/layout-2.png"), title: '', selected: false, toolsId: '' }, { tag: 2, icon: require("@/assets/images/layout-3.png"), title: '', selected: false, toolsId: '' }, { tag: 3, icon: require("@/assets/images/layout-4.png"), title: '', selected: false, toolsId: '' }, { tag: 4, icon: require("@/assets/images/layout-5.png"), title: '', selected: false, toolsId: '', child: [] }],
给最后一个元素塞入5行6列的数据,因为VUE本身就是MVVM,即我们好数据,对数据进行直接操作时,页面则会动态渲染。我们不可能愚蠢的去手动一个一个塞!所以这里使用for循环来塞。cols代表第几列,rows代码第几行,通过求商、求余来控制方格的元数据。
let boxItem = aForm.layoutSeriTools.filter(p => p.tag == 4)[0] for (let i = 0; i < 30; i++) { let e = { selected: false, cols: i % 6, rows: parseInt(i / 6) } boxItem.child.push(e) }
通过上面的代码就已经可以正常的弹出定义的行列显示,现在添加业务数据的控制逻辑:
鼠标滑动到哪格中,小于这个格元数据的行、列则选中,否则不选中!这个方法则是核心!
hoverBoxAction(tag, item) { let list = tag == 0 ? this.layoutSeriTools.filter(p => p.tag == 4)[0].child : this.layoutPicTools.filter(p => p.tag == 4)[0].child let row = item.rows let col = item.cols list.forEach(m => { m.notClearn = false m.selected = m.cols <= col && m.rows <= row }); }, boxClickAction(tag) { let tList = tag == 0 ? this.layoutSeriTools:this.layoutPicTools let list = tList.filter(p => p.tag == 4)[0].child let nList = list.filter(p => p.selected == true) nList.forEach(m => { m.notClearn = true }); tList.filter(p=>p.selected == true).firstObject().selected = false tList.filter(p=>p.tag == 4).firstObject().selected = true this.$refs[`boxPopover_${tag}`][0].doClose() }, leaveBoxAction(tag) { //别有用意,不要随便改时间,只是为了动画同步 setTimeout(() => { let list = tag == 0 ? this.layoutSeriTools.filter(p => p.tag == 4)[0].child : this.layoutPicTools.filter(p => p.tag == 4)[0].child list.forEach(m => { if (!m.notClearn) { m.selected = false } }); }, 300); }
祝你使用丝滑!若有疑问,请发表评论或者私信沟通。