<html>
<head>
<title>框选</title>
<style>
body,
html {
margin: 0;
padding: 0;
}
#selectBox {
width: 300px;
height: 400px;
padding: 10px;
}
#selectBox>.selectBlock {
width: 30px;
height: 30px;
margin-left: 5px;
margin-top: 5px;
display: inline-block;
border: 1px solid #999;
}
</style>
</head>
<body>
<div id="selectBox">
<div class="selectBlock"></div>
<div class="selectBlock"></div>
<div class="selectBlock"></div>
<div class="selectBlock"></div>
<div class="selectBlock"></div>
<div class="selectBlock"></div>
<div class="selectBlock"></div>
<div class="selectBlock"></div>
<div class="selectBlock"></div>
<div class="selectBlock"></div>
<div class="selectBlock"></div>
<div class="selectBlock"></div>
<div class="selectBlock"></div>
<div class="selectBlock"></div>
<div class="selectBlock"></div>
<div class="selectBlock"></div>
<div class="selectBlock"></div>
<div class="selectBlock"></div>
<div class="selectBlock"></div>
<div class="selectBlock"></div>
<div class="selectBlock"></div>
<div class="selectBlock"></div>
<div class="selectBlock"></div>
<div class="selectBlock"></div>
<div class="selectBlock"></div>
<div class="selectBlock"></div>
<div class="selectBlock"></div>
<div class="selectBlock"></div>
<div class="selectBlock"></div>
</div>
</body>
<script>
/*
* 功能:将对象转成字符串
* 参数:对象,属性名与属性值之间插入字符
*/
function objToStr(obj, char) {
if (typeof obj !== 'object' || !obj) return;
var str = '';
for (var key in obj) {
str += key + char + obj[key] + ';';
}
return str;
}
/*
* 功能:阻止事件冒泡与默认事件
* 参数:事件对象
*/
function clearEvent(event) {
event.stopPropagation ? event.stopPropagation() : event.cancelBubble = true;//后者为IE阻止事件冒泡属性
event.preventDefault ? event.preventDefault() : event.returnValue = false;//后者为IE阻止默认事件属性
}
/*
* 功能:将类数组转成数组
* 参数:类数组对象
*/
function objToArray(obj) {
return Array.prototype.slice.call(obj)
}
/*
* 功能:判断节点是否在DOM对象中
*/
Object.prototype.exist = function () {
if (typeof this !== 'undefined' && this.length >= 1) {
return true;
}
return false;
}
/*
* 初始化变量
*/
var mouseStopStatus,//鼠标停止状态
mouseOnStatus,//鼠标按下状态
startX = 0,//记录模拟弹框X坐标,默认开始X坐标,初始为0
startY = 0;//记录模拟弹框Y坐标,默认开始Y坐标,初始为0
//获取外层盒子
var selectBox = document.getElementById('selectBox');
//定义一个数组,存储选中后的元素
var selectedBlocks = [];
(function () {
//鼠标按下事件
document.onmousedown = function (e) {
//阻止事件冒泡与默认
clearEvent(e);
//当不是按下鼠标左键触发,不执行后续代码,左键的值是1。
if (e.buttons !== 1 || e.which !== 1) return;
//如果是按下左键,模拟一个弹框盖上去,这里为了体检良好,特意延迟
mouseStopStatus = setTimeout(function () {
//记录鼠标按下状态
mouseOnStatus = true;
//当前光标X坐标减去盒子内部距离最左边的距离加上盒子与左边的滚动距离,则为模拟弹框的X坐标
//当前光标Y坐标减去盒子内部距离最顶部的距离加上盒子与顶部的滚动距离,则为模拟弹框的Y坐标
startX = e.clientX - selectBox.offsetLeft + selectBox.scrollLeft;
startY = e.clientY - selectBox.offsetTop + selectBox.scrollTop;
//开始创建一个模拟弹框,为标签div元素
var selMask = document.createElement('div');
//设置模拟弹框样式
var selStyle = {
position: "absolute",
width: 0,
height: 0,
margin: 0,
padding: 0,
border: "1px dashed #666",
'background-color': "#bbb",
'z-index': 1000,
opacity: 0.6,
display: "none"
};
selMask.style.cssText = objToStr(selStyle, ':');
//为弹框加id
selMask.id = 'selMask';
//添加到盒子中去
document.body.appendChild(selMask);
}, 400);
//鼠标拖动事件
document.onmousemove = function (e) {
//如果鼠标按下状态为false,则不执行
if (!mouseOnStatus) return;
//还是处理一次事件
clearEvent(e);
//获取拖动过后最开始模拟框的X与Y坐标
var moveX = e.clientX - selectBox.offsetLeft + selectBox.scrollLeft;
var moveY = e.clientY - selectBox.offsetTop + selectBox.scrollTop;
//获取当前盒子的内部高度
var clientH = selectBox.clientHeight;
//判断如果拖动过后模拟框的Y左标大于盒子的内部高度并且盒子距离顶部的滚动距离小于等于盒子的内部高度
if (moveY >= clientH && selectBox.scrollTop <= clientH) {
//盒子的滚动高度就等于拖动的Y坐标距离减去盒子内部高度
selectBox.scrollTop = moveY - clientH;
}
//当光标的Y坐标距离小于盒子的距离顶部的距离,并且盒子的距离顶部距离大于0
if (e.clientY <= selectBox.offsetTop && selectBox.scrollTop > 0) {
//则盒子距离顶部的距离等于光标的Y坐标距离减去盒子内部距离顶部的距离
selectBox.scroll = Math.abs(e.clientY - selectBox.offsetTop);
}
//显示模拟弹框
var _selMask = document.getElementById('selMask');
_selMask.style.display = 'block';
//模拟弹框的左偏移与上偏移取拖动的坐标与开始坐标两者的最小值
_selMask.style.left = Math.min(moveX, startX) + 'px';
_selMask.style.top = Math.min(moveY, startY) + 'px';
//模拟弹框的宽高等于拖动后的坐标减去拖动前的坐标
_selMask.style.width = Math.abs(moveX - startX) + 'px';
_selMask.style.height = Math.abs(moveY - startY) + 'px';
}
}
//鼠标拖动停止
document.onmouseup = function (e) {
//同样如果鼠标未按下则不执行后续操作
if (!mouseOnStatus) return;
//同样处理一下事件
clearEvent(e);
//获取模拟弹框与盒子内的块元素
var _selMask = document.getElementById('selMask'),
selectBlock = document.getElementsByClassName('selectBlock');
//取得模拟弹框的内部左顶部距离,内部宽与高
var l = _selMask.offsetLeft,
t = _selMask.offsetTop,
w = _selMask.offsetWidth,
h = _selMask.offsetHeight;
for (var i = 0, len = selectBlock.length; i < len; i++) {
//取得盒子内块元素的实际大小
var sbl = selectBlock[i].offsetLeft + selectBlock[i].offsetWidth,
sbt = selectBlock[i].offsetTop + selectBlock[i].offsetHeight;
//判断如果模拟弹框拖动距离小于盒子内的实际大小,并且盒子左顶部距离要小于模拟框距离之和,则添加选中的元素存储进数组
if (l < sbl && t < sbt && selectBlock[i].offsetLeft < l + w && selectBlock[i].offsetTop < t + h) {
//改变选中块背景颜色
selectBlock[i].style.backgroundColor = '#2693f0';
selectedBlocks.push(selectBlock[i])
} else {
selectBlock[i].style.backgroundColor = '';
}
}
console.log('选中块的元素:', selectedBlocks)
if (_selMask) {
// 移除模拟框
document.body.removeChild(_selMask);
}
// 解除模拟框引用,然后初始化值
_selMask = null; startX = 0; startY = 0; selectedBlocks = [];
//关闭鼠标按下状态
mouseOnStatus = false;
}
})()
</script>
</html>
Output
300px
You can jump to the latest bin by adding /latest
to your URL
Keyboard Shortcuts
Shortcut | Action |
---|---|
ctrl + [num] | Toggle nth panel |
ctrl + 0 | Close focused panel |
ctrl + enter | Re-render output. If console visible: run JS in console |
Ctrl + l | Clear the console |
ctrl + / | Toggle comment on selected lines |
ctrl + ] | Indents selected lines |
ctrl + [ | Unindents selected lines |
tab | Code complete & Emmet expand |
ctrl + shift + L | Beautify code in active panel |
ctrl + s | Save & lock current Bin from further changes |
ctrl + shift + s | Open the share options |
ctrl + y | Archive Bin |
Complete list of JS Bin shortcuts |
JS Bin URLs
URL | Action |
---|---|
/ | Show the full rendered output. This content will update in real time as it's updated from the /edit url. |
/edit | Edit the current bin |
/watch | Follow a Code Casting session |
/embed | Create an embeddable version of the bin |
/latest | Load the very latest bin (/latest goes in place of the revision) |
/[username]/last | View the last edited bin for this user |
/[username]/last/edit | Edit the last edited bin for this user |
/[username]/last/watch | Follow the Code Casting session for the latest bin for this user |
/quiet | Remove analytics and edit button from rendered output |
.js | Load only the JavaScript for a bin |
.css | Load only the CSS for a bin |
Except for username prefixed urls, the url may start with http://jsbin.com/abc and the url fragments can be added to the url to view it differently. |