最终效果:

1、先写一个可以滚动的内容

可以滚动的内容

2、声明框选 有效区

编辑器的灵魂是什么:所有的操作都是在一个黑板上进行,我们只能在这个黑板上进行绘制、操作,这个黑板叫做编辑器有效区。

var selectContainer = document.getElementById('container');        //选框有效区

image.png

3、鼠标按下时,进入一个总的方法

selectContainer.onmousedown = function () {
    alert(2222222);        //测试在有效区内,鼠标按下响应的事件
}

4、鼠标按下:在容器里新添加一个方形div

鼠标点击后,浅蓝色方块出来了

var selection = document.createElement('div');

selectContainer.onmousedown = function (e) {        
    selection.style.cssText="width: 100px; height: 100px; background: lightblue; opacity: 0.4";
    document.getElementById('container').appendChild(selection);
}

这个浅蓝色的方块就是我们未来的框选框。但是框选框的起始位置(x,y),我们要相对于有效区绝对定位。所以,代码进一步写成:

#container {
    width: 400px;
    height: 300px;
    overflow-y: auto;
    position: relative;
    border: 1px solid #ddd;
}
selection.style.cssText="width: 100px; height: 100px; background: lightblue; opacity: 0.4; position: absolute";

并且此时我们要声明两个变量:水平坐标,垂直坐标(框选框左上角的点)

<script>
    var startX = 0;
    var startY = 0;
selectContainer.onmousedown = function (e) {        
    startX = e.clientX - selectContainer.offsetLeft + selectContainer.scrollLeft;
    startY = e.clientY - selectContainer.offsetTop + selectContainer.scrollTop;
    /* 鼠标相对于视口的水平坐标 - 外框container偏移的位置(固定) + 滚动偏移
    
    ***这里是很容易写出bug的地方***
    写框选框的时候,很多人会把框选框相对于整个页面定位
    但是这样的话,在我们框选住一个方块 同时又让编辑区内容滚动 的时候,
    框选框不会覆盖到滚动部分的内容,而是会出现框选框 傻傻地fixed在一个地方 的现象,也就是和编辑区的内容结合不起来。
    ***结束***
   
    */

得到了鼠标点击的位置后,我们试着把浅蓝色方块定位到鼠标点击的位置。

selection.style.left = startX;
selection.style.top = startY;

我们现在得到了鼠标点击的定位点,接下来就要找到鼠标放下的定位点和框选框的宽高。

5、找方块的范围
首先,我们的方块范围是通过鼠标移动的多少来决定的,所以我们要写一个鼠标按下后的移动事件:

selectContainer.onmousemove = function (e) {
    if (e.buttons == 1 || e.which == 1) {    //多加一个条件:鼠标左键按住
        alert("移动了!");
    }
}

然后,要让死的方块跟着鼠标拖拽的位置动起来。但是在这之前,我们要把刚刚的浅蓝色小方块重置样式(宽高设0,默认隐藏)

selection.style.cssText="width: 0; height: 0; background: lightblue; opacity: 0.4; position: absolute; display: none;";

重置过后,写动态框选框的代码,如下:

selection.style.display = "block";
selection.style.width = Math.abs(_x - startX) + "px";
selection.style.height = Math.abs(_y - startY) + "px";

6、鼠标放下的交互

selectContainer.onmouseup = function (e) {
    selection.style.display = "none";
}

7、框选框和备选节点

框选结束后,有一部分节点是被选中的状态,我们未来会对这些节点进行一些批量的操作。
所以,要有个装这些节点的空容器:

//首先获取所有可被选中的备选节点
var lines = document.getElementsByClassName("line");

//被选中节点的容器
var selectedEls = [];

再往前推,计算框选框选中了多少节点。

8、框选框和备选项的关系

selectContainer.onmouseup = function (e) {
    var a = selection.offsetLeft;
    var b = selection.offsetWidth;
    var c = selection.offsetTop;
    var d = selection.offsetHeight;

    for (var i = 0; i < lines.length; i++) {                
        var sr = lines[i].offsetWidth + lines[i].offsetLeft;        //备选项最右侧
        var sb = lines[i].offsetHeight + lines[i].offsetTop;        //备选项最底侧
        // 备选项 最右侧 sl > 框选框 水平偏移 a
        // 备选项 最底部 st > 框选框 垂直偏移 c
        // 备选项 距左侧距离 lines[i].offsetLeft < 框选框 水平偏移 a + 框选框宽度 b
        // 备选项 距顶部距离 lines[i].offsetTop < 框选框 垂直偏移 c + 框选框高度 d 
        if(sr > a && sb > c && lines[i].offsetLeft < a + b && lines[i].offsetTop < c + d) {
            lines[i].style.background = "#0082cc";
            selectedEls.push(lines[i]);
        } else {
            ......        
        }
    }    

    selection.style.display = "none";
}

美玲
1 声望0 粉丝