vue3框选

一、前言

项目中经常会遇到文件列表相关的需求,其中框选文件是比较常见的需求,因此提取了一个小组件,如大家有更好的实现方式,可以评论区交流一下。

demo链接:code.juejin.cn/api/raw/731...

二、如何实现

1.容器

第一步,创建多个块,使用数组记录并动态设置active以高亮边框。

js 复制代码
<div 
    class="box" 
    :class="{
        'active': activeList.includes(index)
    }" 
    v-for="(item, index) in 50"
>{{ index }}</div>

第二步,使用getBoundingClientRect计算盒子信息,用于后续位置判定。

js 复制代码
const calcBox = (arr, dom, baseScrollTop) => {
    const length = dom.children.length;
    for(let i = 0; i < length; i++) {
        let child = dom.children[i];
        let domData = child.getBoundingClientRect();
        let obj = {
            index: i,
            dom: child,
            position: [
                domData.x,
                domData.y + baseScrollTop,
                domData.width,
                domData.height,
            ]
        }
        arr.push(obj);
    }
}

2.计算选择框是否包含块

根据选择框的left,top,width,height,以及前期收集的盒子数据数组判断是否处于框内。

从x轴方向分析,有三种情况需要考虑,y轴同理。

根据框的四维和盒子的思维做判断

js 复制代码
const calcSelect = (left, top, width, height, boxList) => {
    const arr = new Set()
    for (let i = 0; i < boxList.length; i++) {
        const p = boxList[i].position
        if (
            (left <= p[0] && left + width > p[0]) ||
            (left > p[0] && left < p[0] + p[2] && width > 0)
        ) {
            if (
                (top <= p[1] && top + height > p[1]) ||
                (top > p[1] && top < p[1] + p[3] && height > 0)
            ) {
                arr.add(boxList[i].index)
            } else {
                arr.delete(boxList[i].index)
            }
        } else {
            arr.delete(boxList[i].index)
        }
    }
    return Array.from(arr)
}

3.鼠标事件中记录需要的值

使用mouseevent中的clientX和clientY记录鼠标位置,同时需要考虑页面原本的滚动高度。

移动中需考虑整体方向是向左还是向右,会影响到选择框的思维绘制。

js 复制代码
const mousedown = (e) => {
    let baseL = e.clientX,
        baseT = e.clientY,
        baseScrollTop = document.children[0].scrollTop, // html根节点,需根据实际场景替换
        boxList = []
    calcBox(boxList, dragSelectDom.value, baseScrollTop);
    activeList.value = []
    document.onmousemove = (ev) => {
        showDrag.value = true
        const xOffset = ev.clientX - baseL
        const yOffset = ev.clientY - baseT
        const width = Math.abs(xOffset)
        const height = Math.abs(yOffset)
        const left = xOffset < 0 ? ev.clientX : baseL
        const top = yOffset < 0 ? ev.clientY : baseT
        const scrollTop = document.children[0].scrollTop
        updateRect(left, top + scrollTop, width, height); // 这个函数用于修改选择框css属性
        activeList.value = []
        activeList.value = calcSelect(left, top + scrollTop, width, height, boxList)
    }
    document.onmouseup = () => {
        showDrag.value = false
        document.onmousemove = null
        document.onmouseup = null
    }
}

最后将mousedown事件挂载到根节点上即可

三、后续事项

1.首先是判断算法优化,目前是每次移动都需要判断全部块是否有相交,比较耗性能,块越多越卡。

2.还需考虑拖拽触底时候的滚动,可以用requestAnimationFrame模拟滚动,在相应的判断中要增加滚动差的判断。

3.横向滚动

4.针对实际应用,会有无限滚动加载的应用场景,需及时刷新容器数据。

相关推荐
顾平安1 小时前
Promise/A+ 规范 - 中文版本
前端
聚名网1 小时前
域名和服务器是什么?域名和服务器是什么关系?
服务器·前端
桃园码工1 小时前
4-Gin HTML 模板渲染 --[Gin 框架入门精讲与实战案例]
前端·html·gin·模板渲染
沈剑心1 小时前
如何在鸿蒙系统上实现「沉浸式」页面?
前端·harmonyos
一棵开花的树,枝芽无限靠近你2 小时前
【PPTist】组件结构设计、主题切换
前端·笔记·学习·编辑器
m0_748237052 小时前
Chrome 关闭自动添加https
前端·chrome
prall2 小时前
实战小技巧:下划线转驼峰篇
前端·typescript
开心工作室_kaic2 小时前
springboot476基于vue篮球联盟管理系统(论文+源码)_kaic
前端·javascript·vue.js
川石教育2 小时前
Vue前端开发-缓存优化
前端·javascript·vue.js·缓存·前端框架·vue·数据缓存
搏博2 小时前
使用Vue创建前后端分离项目的过程(前端部分)
前端·javascript·vue.js