首先看一下效果:
實現的思路:
- 先設置一個容器的,容器中放上10×10的小格子,同時監聽容器的進入和離開方法。
- 每個小格子上設置鼠標進入的方法,同時傳入當前的序號,計算出當前的行和列,改變背景顏色。
- 監聽容器的是從那個位置進入,只有從左邊和上邊進入有效。
相關的核心代碼:
- 判斷鼠標移入元素的方向——上下左右,核心代碼:
var direction = Math.round((((Math.atan2(y, x) * (180 / Math.PI)) + 180) / 90) + 3) % 4;
相關解釋參考這篇文章:
https://www.cnblogs.com/liuyanxia/p/5666892.html
相關代碼:
// 判斷鼠標是否從左上進入
direct(e) {
const x = e.offsetX - 230 / 2; //鼠標進入的X座標-盒子寬度的一半
const y = e.offsetY - 230 / 2; //鼠標進入的y座標-盒子寬度的一半
const direction =
(Math.round((Math.atan2(y, x) * (180 / Math.PI) + 180) / 90) + 3) % 4;
if (direction === 0 || direction === 3) {
this.isLeftTop = true;
} else {
this.isLeftTop = false;
}
}
- 判斷當前滑入到那個小窗格,改變背景顏色
// 獲取鼠標進入方格的位置,進行背景渲染
getMousePlace(index) {
this.isOn = true;
if (!this.isLeftTop || this.isSelected) {
return;
}
const x = Math.floor(index % 10);
const y = Math.floor(index / 10);
const children = this.$refs.wallRow.children;
for (let i = 0; i < this.divList.length; i++) {
const childrenx = Math.floor(i % 10);
const childreny = Math.floor(i / 10);
if (childrenx < x + 1 && childreny < y + 1) {
children[i].className = "bgColor";
this.rows = x + 1;
this.cols = y + 1;
} else {
children[i].className = "";
}
}
}
- 點擊時關閉繪製狀態
// 選定行列
selected(index) {
this.isSelected = true;
const data = {
rows: this.rows,
cols: this.cols
};
}
整體代碼如下:
<template>
<div class="custom-style">
<div class="word">
<span>{{ rows }}×{{ cols }}</span>
</div>
<ul class="wall-row" ref="wallRow" @mouseenter="direct($event)" @mouseleave="clearSelect">
<li
v-for="(item, index) in divList"
:key="index"
@mouseenter="getMousePlace(index)"
@click="selected"
></li>
</ul>
<div class="wall-cancel">
<button @click="cancel">重置</button>
</div>
</div>
</template>
<script>
export default {
props: {
isBlur: {
type: Boolean
}
},
data() {
return {
divList: [], // 方格列表數組
rows: 1, // 行
cols: 1, // 列
isLeftTop: true, // 鼠標是否從左上方進入
isSelected: false, // 是否選中電視牆行列
isOn: false
};
},
created() {
this.divList.length = 100; // 方格個數 10*10
},
mounted() {
this.autoSelect();
},
methods: {
// 自動根據vuex中行列選中對應方格
autoSelect() {
this.rows = 1;
this.cols = 1;
this.selectRowCol(this.rows, this.cols);
},
// 獲取鼠標進入方格的位置,進行背景渲染
getMousePlace(index) {
this.isOn = true;
if (!this.isLeftTop || this.isSelected) {
return;
}
const x = Math.floor(index % 10);
const y = Math.floor(index / 10);
const children = this.$refs.wallRow.children;
for (let i = 0; i < this.divList.length; i++) {
const childrenx = Math.floor(i % 10);
const childreny = Math.floor(i / 10);
if (childrenx < x + 1 && childreny < y + 1) {
children[i].className = "bgColor";
this.rows = x + 1;
this.cols = y + 1;
} else {
children[i].className = "";
}
}
},
// 當鼠標移出選擇區域,如未選定行列,則重置方格 1*1
clearSelect() {
this.isOn = false;
if (this.isSelected) {
return;
}
const children = this.$refs.wallRow.children;
for (let i = 0; i < this.divList.length; i++) {
if (i != 0) {
children[i].className = "";
}
}
this.rows = 1;
this.cols = 1;
},
// 選定行列
selected(index) {
this.isSelected = true;
const data = {
rows: this.rows,
cols: this.cols
};
},
// 判斷鼠標是否從左上進入
direct(e) {
const x = e.offsetX - 230 / 2; //鼠標進入的X座標-盒子寬度的一半
const y = e.offsetY - 230 / 2; //鼠標進入的y座標-盒子寬度的一半
const direction =
(Math.round((Math.atan2(y, x) * (180 / Math.PI) + 180) / 90) + 3) % 4;
if (direction === 0) {
this.isLeftTop = true;
} else if (direction === 1) {
this.isLeftTop = false;
} else if (direction === 2) {
this.isLeftTop = false;
} else {
this.isLeftTop = true;
}
},
// 點擊取消,重置方格 1*1
cancel() {
const children = this.$refs.wallRow.children;
for (let i = 0; i < this.divList.length; i++) {
if (i != 0) {
children[i].className = "";
}
}
this.rows = 1;
this.cols = 1;
this.isSelected = false;
},
// 改變行列數
handleTypeChange() {
this.selectRowCol(this.rows, this.cols);
this.isSelected = true;
},
// 渲染方格
selectRowCol(rows, cols) {
const children = this.$refs.wallRow.children;
for (let i = 0; i < this.divList.length; i++) {
const childrenx = Math.floor(i % 10);
const childreny = Math.floor(i / 10);
if (childrenx < rows && childreny < cols) {
children[i].className = "bgColor";
} else {
children[i].className = "";
}
}
},
// 點擊保存,將數據同步到vuex,並關閉下拉框
save() {
const data = {
rows: this.rows,
cols: this.cols
};
}
}
};
</script>
<style scoped lang="css">
.custom-style {
position: absolute;
margin: 0;
padding: 0;
height: 440px;
width: 400px;
left: 50%;
top: 50%;
margin-left: -200px;
margin-top: -210px;
}
.word {
display: block;
width: 100%;
height: 20px;
font-size: 13px;
background-color: #e2eef6;
}
.word span {
line-height: 20px;
text-align: center;
}
.wall-row {
width: 400px;
height: 400px;
padding: 0;
margin: 0;
display: block;
position: relative;
}
.wall-row li {
list-style: none;
width: 39px;
height: 40px;
border: 0.5px solid #fff;
float: left;
background-color: #ebf0f4;
}
.wall-row .bgColor {
background-color: #00b4ff;
}
.word-cancel {
width: 100%;
height: 20px;
display: flex;
justify-content: center;
align-items: center;
}
</style>