如何实现框选多个元素,并且可以进行放大缩小等操作?

想实现一个类似于下面这个图片的效果,这只是个简单的,后续可能还要加上放大缩小等操作。

图片描述

大家有什么好的组件或者思路嘛?

阅读 2.2k
2 个回答

这个也就是制造一个模拟框,覆盖上去,然后改变背景颜色,也就是鼠标拖拽事件,这里是你想要的效果

图片描述
框选同时按住 SHIFT 为增加选择
框选同时按住 ALT 为从已有选择种删除

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Batch Select</title>
    <style type="text/css">
    .flex-row {display:-webkit-flex;display:flex;-webkit-flex-direction:row;flex-direction:row;}
    .flex-row > .flex-main  {-webkit-flex:1 1 auto;flex:1 1 auto;}
    .flex-row > .flex-side  {-webkit-flex:0 0 auto;flex:0 0 auto;}

    .flex-column {display:-webkit-flex;display:flex;-webkit-flex-direction:column;flex-direction:column;}
    .flex-column > .flex-main   {-webkit-flex:1 1 auto;flex:1 1 auto;}
    .flex-column > .flex-side {-webkit-flex:0 0 auto;flex:0 0 auto;}

    .template {display:none;}

    .cell-matrix {position:relative;padding:0.5em;background-color:#EEE;
        -webkit-user-select: none;
        -moz-user-select: none;
        -ms-user-select: none;
        user-select: none;}
    .cell-matrix .select {position:absolute;display:none;border:1px dashed rgba(0,0,255,0.7);background-color:rgba(0,0,255,0.3);box-sizing:border-box;}
    .cell-matrix .cell-list {margin:0.5em 0;}
    .cell-matrix .cell-list .cell-group {white-space:nowrap;}
    .cell-matrix .cell-list .cell-group .cell {display:inline-block;background-color:#FFF;box-shadow:0 0 0 1px #CCC;}
    .cell-matrix .cell-list .cell-group .cell-select {background-color:#00F;}
    .cell-matrix .cell-list .cell-group .gap {display:inline-block;}
    .cell-data {white-space:pre;}
    </style>
    <script>
    document.addEventListener('DOMContentLoaded', function(){

        let domTpl = document.querySelector('.template .cell-group');

        let arrDomCellList = document.querySelectorAll('.cell-list');
        let i, domCellList, dom;
        for(i=0; i<arrDomCellList.length; i++)
        {
            domCellList = arrDomCellList[i];

            for(let j=0; j<4; j++)
            {
                dom = domTpl.cloneNode(true);
                domCellList.appendChild(dom);
            }
        }

        let domMatrix = document.querySelector('.cell-matrix');
        let MODE_SET = 1;
        let MODE_ADD = 2;
        let MODE_DEL = 3;
        let SelectArea = {
            domBase : domMatrix,
            dom : domMatrix.querySelector('.select'),
            on : false,
            mode : MODE_SET,
            x1 : 0,
            y1 : 0,
            x2 : 0,
            y2 : 0,
        };
        function update_select_cell()
        {
            let x1 = Math.min(SelectArea.x1, SelectArea.x2) + SelectArea.domBase.offsetLeft - SelectArea.domBase.scrollLeft;
            let y1 = Math.min(SelectArea.y1, SelectArea.y2) + SelectArea.domBase.offsetTop - SelectArea.domBase.scrollTop;
            let x2 = Math.max(SelectArea.x1, SelectArea.x2) + SelectArea.domBase.offsetLeft - SelectArea.domBase.scrollLeft;
            let y2 = Math.max(SelectArea.y1, SelectArea.y2) + SelectArea.domBase.offsetTop - SelectArea.domBase.scrollTop;

            let arrData = [];

            let arrDomCellList = document.querySelectorAll('.cell-list');
            let i, domCellList;
            for(i=0; i<arrDomCellList.length; i++)
            {
                domCellList = arrDomCellList[i];

                let data = '';

                let arrDomCell = domCellList.querySelectorAll('.cell');
                let j, domCell, rect, flag;
                for(j=0; j<arrDomCell.length; j++)
                {
                    domCell = arrDomCell[j];

                    rect = domCell.getBoundingClientRect();
                    flag = ! (x2 < rect.left
                        || y2 < rect.top
                        || x1 > rect.right
                        || y1 > rect.bottom);

                    switch(SelectArea.mode)
                    {
                        case MODE_ADD:
                            if(flag === true)
                            {
                                data += '1';
                                domCell.classList.add('cell-select');
                            }
                            else
                            {
                                data += (domCell.classList.contains('cell-select')?'1':'0');
                            }
                            break;
                        case MODE_DEL:
                            if(flag === true)
                            {
                                data += '0';
                                domCell.classList.remove('cell-select');
                            }
                            else
                            {
                                data += (domCell.classList.contains('cell-select')?'1':'0');
                            }
                            break;
                        default:
                            if(flag === true)
                            {
                                data += '1';
                                domCell.classList.add('cell-select');
                            }
                            else
                            {
                                data += '0';
                                domCell.classList.remove('cell-select');
                            }
                            break;
                    }
                }

                arrData.push(data);
            }

            return arrData;
        }
        function update_select_rect()
        {
            if(SelectArea.on === false)
            {
                SelectArea.dom.style.display = 'none';
                let arrData = update_select_cell();
                document.querySelector('.cell-data').innerHTML = arrData.join('\n');

                SelectArea.x1 = 0;
                SelectArea.y1 = 0;
                SelectArea.x2 = 0;
                SelectArea.y2 = 0;
                return;
            }

            SelectArea.dom.style.display = 'block';
            SelectArea.dom.style.top     = Math.min(SelectArea.y1, SelectArea.y2) + 'px';
            SelectArea.dom.style.left    = Math.min(SelectArea.x1, SelectArea.x2) + 'px';
            SelectArea.dom.style.width   = Math.abs(SelectArea.x1 - SelectArea.x2) + 'px';
            SelectArea.dom.style.height  = Math.abs(SelectArea.y1 - SelectArea.y2) + 'px';
        }
        domMatrix.addEventListener('mousedown', function($evt){
            if(($evt.buttons & 0x01) !== 0x01)
                return;

            SelectArea.on = true;
            SelectArea.x1 = $evt.clientX - SelectArea.domBase.offsetLeft + SelectArea.domBase.scrollLeft;
            SelectArea.y1 = $evt.clientY - SelectArea.domBase.offsetTop + SelectArea.domBase.scrollTop;
            SelectArea.x2 = SelectArea.x1;
            SelectArea.y2 = SelectArea.y1;

            update_select_rect();
        });
        domMatrix.addEventListener('mouseup', function($evt){
            if(SelectArea.on === false)
                return;

            if(($evt.buttons & 0x01) !== 0x00)
                return;

            if($evt.shiftKey === true)
                SelectArea.mode = MODE_ADD;
            else if($evt.altKey === true)
                SelectArea.mode = MODE_DEL;
            else
                SelectArea.mode = MODE_SET;

            SelectArea.on = false;
            SelectArea.x2 = $evt.clientX - SelectArea.domBase.offsetLeft + SelectArea.domBase.scrollLeft;
            SelectArea.y2 = $evt.clientY - SelectArea.domBase.offsetTop + SelectArea.domBase.scrollTop;

            update_select_rect();
        });
        domMatrix.addEventListener('mousemove', function($evt){
            if(SelectArea.on === false)
                return;

            if(($evt.buttons & 0x01) !== 0x01)
                return;

            SelectArea.x2 = $evt.clientX - SelectArea.domBase.offsetLeft + SelectArea.domBase.scrollLeft;
            SelectArea.y2 = $evt.clientY - SelectArea.domBase.offsetTop + SelectArea.domBase.scrollTop;

            update_select_rect();
        });
    });
    </script>
</head>
<body>
<div class="cell-matrix">
    <div class="select"></div>
    <div class="flex-row cell-list">
        <div class="flex-side">星期一</div>
        <div class="gap">&ensp;</div>
    </div>
    <div class="flex-row cell-list">
        <div class="flex-side">星期二</div>
        <div class="gap">&ensp;</div>
    </div>
    <div class="flex-row cell-list">
        <div class="flex-side">星期三</div>
        <div class="gap">&ensp;</div>
    </div>
    <div class="flex-row cell-list">
        <div class="flex-side">星期四</div>
        <div class="gap">&ensp;</div>
    </div>
    <div class="flex-row cell-list">
        <div class="flex-side">星期五</div>
        <div class="gap">&ensp;</div>
    </div>
    <div class="flex-row cell-list">
        <div class="flex-side">星期六</div>
        <div class="gap">&ensp;</div>
    </div>
    <div class="flex-row cell-list">
        <div class="flex-side">星期日</div>
        <div class="gap">&ensp;</div>
    </div>
</div>
<div class="cell-data"></div>
<div class="template">
    <div class="flex-side cell-group">
        <div class="cell">&ensp;</div>
        <div class="cell">&ensp;</div>
        <div class="cell">&ensp;</div>
        <div class="cell">&ensp;</div>
        <div class="cell">&ensp;</div>
        <div class="cell">&ensp;</div>
        <div class="cell">&ensp;</div>
        <div class="cell">&ensp;</div>
        <div class="cell">&ensp;</div>
        <div class="cell">&ensp;</div>
        <div class="cell">&ensp;</div>
        <div class="cell">&ensp;</div>
        <div class="gap">&ensp;</div>
    </div>
</div>
</body>
</html>
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题