一、实现如图所示功能
文章来源地址https://www.toymoban.com/news/detail-502964.html
二、鼠标mousedown事件和click事件重复,不设置click事件可以达到相同效果
// 代码如下
<template>
<el-dialog
title="时间段选择"
:visible.sync="dialogVisible"
:close-on-click-modal="false"
custom-class="custom-dialog-style"
width="1000px"
:close="close"
>
<div class="container">
<div class="wrap">
<div class="left">
<div class="merge-column">星期/时间</div>
<div class="td-title" v-for="(weekItem, index) in week" :key="index">{{ weekItem }}</div>
</div>
<div class="right">
<div class="top">
<div class="merge-row">00:00-12:00</div>
<div class="merge-row">12:00-24:00</div>
<div class="unit" v-for="(item, index) in 24" :key="index">{{ index }}</div>
</div>
<div class="bottom" @mousedown="handleMouseDown">
<div
:style="'width:' + mask_width + 'left:' + mask_left + 'height:' + mask_height + 'top:' + mask_top"
v-show="positionList.is_show_mask"
class="mask"
></div>
// 鼠标mousedown事件和click事件重复,不设置click事件可以达到相同效果 @click="handleClickSelected(item)"
<div
class="select-item"
v-for="(item, index) in dataItem"
:key="index"
:class="{selected: item.selected ? true : false}"
></div>
</div>
</div>
</div>
</div>
<div slot="footer">
<el-button @click="close">取 消</el-button>
<el-button type="primary" @click="submit">确 定</el-button>
</div>
</el-dialog>
</template>
<script>
const positionList = {
is_show_mask: false,
box_screen_left: 0, // 盒子距离浏览器左侧的距离
box_screen_top: 0, //盒子距离浏览器顶部的距离
start_x: 0,
start_y: 0,
end_x: 0,
end_y: 0
};
export default {
data() {
return {
dialogVisible: false,
week: ["星期一", "星期二", "星期三", "星期四", "星期五", "星期六", "星期日"],
totalNum: 336,
dataItem: [],
isClick: true,
positionList: {...positionList}
};
},
computed: {
mask_width() {
return `${Math.abs(this.positionList.end_x - this.positionList.start_x)}px;`;
},
mask_height() {
return `${Math.abs(this.positionList.end_y - this.positionList.start_y)}px;`;
},
mask_left() {
return `${Math.min(this.positionList.start_x, this.positionList.end_x) - this.positionList.box_screen_left}px;`;
},
mask_top() {
return `${Math.min(this.positionList.start_y, this.positionList.end_y) - this.positionList.box_screen_top}px;`;
}
},
methods: {
init() { // ref 调用init弹窗即可
this.dialogVisible = true;
this.initList();
},
initList() {
for (let i = 1; i <= this.totalNum; i++) {
let map = {
selected: false,
key: i
};
this.dataItem.push(map);
}
},
setData(value) {
this.initList();
value.forEach((v) => {
this.dataItem[v-1].selected = true;
});
},
handleMouseDown(event) {
this.positionList.is_show_mask = true;
this.positionList.start_x = event.clientX;
this.positionList.start_y = event.clientY;
this.positionList.end_x = event.clientX;
this.positionList.end_y = event.clientY;
this.positionList.box_screen_left = document.querySelector(".bottom").getBoundingClientRect().left;
this.positionList.box_screen_top = document.querySelector(".bottom").getBoundingClientRect().top;
document.body.addEventListener("mousemove", this.handleMouseMove); //监听鼠标移动事件
document.body.addEventListener("mouseup", this.handleMouseUp); //监听鼠标抬起事件
},
handleMouseMove(event) {
this.positionList.end_x = event.clientX;
this.positionList.end_y = event.clientY;
},
handleMouseUp(event) {
document.body.removeEventListener("mousemove", this.handleMouseMove);
document.body.removeEventListener("mouseup", this.handleMouseUp);
this.positionList = {...positionList};
this.positionList.is_show_mask = false;
this.handleDomSelect();
this.resSetXY();
},
handleDomSelect() {
const dom_mask = window.document.querySelector(".mask");
// getClientRects()方法 每一个盒子的边界矩形的矩形集合
const rect_select = dom_mask.getClientRects()[0];
document.querySelectorAll(".select-item").forEach((node, index) => {
const rects = node.getClientRects()[0];
if (this.collide(rects, rect_select) === true) {
this.dataItem[index].selected = !this.dataItem[index].selected;
}
});
},
collide(rect1, rect2) {
const maxX = Math.max(rect1.x + rect1.width, rect2.x + rect2.width);
const maxY = Math.max(rect1.y + rect1.height, rect2.y + rect2.height);
const minX = Math.min(rect1.x, rect2.x);
const minY = Math.min(rect1.y, rect2.y);
return maxX - minX <= rect1.width + rect2.width && maxY - minY <= rect1.height + rect2.height;
},
resSetXY() {
this.positionList.start_x = 0;
this.positionList.start_y = 0;
this.positionList.end_x = 0;
this.positionList.end_y = 0;
},
handleClickSelected(item) {
item.selected = !item.selected;
},
close() {
this.dialogVisible = false;
this.dataItem = [];
},
submit() {
const list = [];
for (let i = 0; i < this.dataItem.length; i++) {
if (this.dataItem[i].selected == true) {
list.push(this.dataItem[i].key);
}
}
if (list.length == 0) {
this.$message({
message: "请选择时间段",
type: "warning"
});
return;
} else {
this.close();
this.$emit("event-data", list);
}
}
}
};
</script>
<style lang="scss" scoped>
.container {
.wrap {
display: flex;
border: 1px solid #f1f1f1;
border-bottom: 0;
.left {
.merge-column {
width: 4vw;
height: 6vh;
padding: 3px 5px;
min-width: 76px;
min-height: 55px;
display: flex;
align-items: center;
border-right: 1px solid #f1f1f1;
border-bottom: 1px solid #f1f1f1;
}
.td-title {
width: 4vw;
height: 3vh;
min-height: 27px;
min-width: 76px;
padding: 3px 5px;
text-align: center;
border-right: 1px solid #f1f1f1;
border-bottom: 1px solid #f1f1f1;
}
&:last-child {
border-bottom: 0;
}
}
.right {
display: flex;
flex-wrap: wrap;
.top {
width: 100%;
display: flex;
flex-wrap: wrap;
align-content: flex-start;
.merge-row {
width: 50%;
height: 3vh;
padding: 3px 5px;
min-width: 420px;
min-height: 27px;
text-align: center;
border-right: 1px solid #f1f1f1;
border-bottom: 1px solid #f1f1f1;
&:nth-child(2) {
border-right: 0;
}
}
.unit {
width: calc(100% / 24);
height: 3vh;
padding: 3px 5px;
min-width: 35px;
min-height: 27px;
text-align: center;
border-right: 1px solid #f1f1f1;
border-bottom: 1px solid #f1f1f1;
&:last-child {
border-right: 0;
}
}
}
.bottom {
width: 100%;
position: relative;
display: flex;
flex-wrap: wrap;
.mask {
position: absolute;
background: #409eff;
opacity: 0.4;
z-index: 100;
left: 0;
top: 0;
}
.select-item {
width: calc(100% / 48);
height: 3vh;
min-width: 17px;
min-height: 27px;
cursor: pointer;
padding: 3px 5px;
border-right: 1px solid #f1f1f1;
border-bottom: 1px solid #f1f1f1;
&:hover {
background: #f1f1f1;
}
}
.selected {
background: #7bc8ff;
&:hover {
background: #7bc8ff;
}
}
*:nth-child(48n + 1) {
border-right: 0;
}
}
}
}
}
</style>
参考文章:https://blog.csdn.net/qq_37656005/article/details/123656240
文章来源:https://www.toymoban.com/news/detail-502964.html
到了这里,关于vue2 实现鼠标左键拖拽实现框选功能的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!