<template>
|
<div class="connect" id="connect" ref="connect" @mousemove="mousemove" @mouseup="(e) => touchend(e)">
|
<div class="answer" >
|
<div class="answer-box">
|
<div
|
class="answer-box-item"
|
v-for="(item, index) in leftArr"
|
:key="index"
|
ref="left"
|
@mousedown="(e) => touchstart(e, item, index)"
|
|
>
|
{{ item.label.txt }}
|
</div>
|
</div>
|
<div class="answer-box">
|
<div
|
class="answer-box-item"
|
v-for="(item, index) in rightArr"
|
:key="index"
|
ref="right"
|
>
|
{{ item.label.txt }}
|
</div>
|
</div>
|
</div>
|
<canvas
|
class="connect-canvasA"
|
:width="clientWidth"
|
:height="clientHeight"
|
ref="canvasA"
|
></canvas>
|
<canvas
|
class="connect-canvasB"
|
:width="clientWidth"
|
:height="clientHeight"
|
ref="canvasB"
|
></canvas>
|
</div>
|
</template>
|
|
<script>
|
export default {
|
data() {
|
return {
|
isDragging: false,
|
leftArr: [],
|
rightArr: [],
|
location: [],
|
canvasA: null,
|
canvasB: null,
|
leftDom: [],
|
rightDom: [],
|
clientWidth: 0,
|
clientHeight: 0,
|
scrollTop: 0,
|
debounce: false,
|
checkItem: null,
|
checkItemIndex:null
|
};
|
},
|
props: {
|
rawData: {
|
type: Object,
|
default: () => {
|
return {
|
left: [],
|
right: [],
|
};
|
},
|
},
|
value: {
|
type: Array,
|
default: () => {
|
return [];
|
},
|
},
|
item: {
|
type: Object,
|
default: () => {
|
return [];
|
},
|
},
|
},
|
watch: {
|
rawData: {
|
immediate: true,
|
handler(val) {
|
if (val.left && val.left.length) this.init();
|
},
|
},
|
},
|
mounted() {
|
// 添加滚动事件 监听 解决因为滚动引起的拖动线不对的问题
|
window.addEventListener(
|
"scroll",
|
(e) => {
|
// 加个防抖
|
if (this.debounce) clearTimeout(this.debounce);
|
this.debounce = setTimeout(() => {
|
this.debounce = false;
|
this.scrollTop = e.target.scrollTop;
|
}, 500);
|
},
|
true
|
);
|
let connect = this.$refs.connect;
|
this.clientWidth = connect.clientWidth;
|
this.clientHeight = connect.clientHeight;
|
this.canvasA = this.$refs.canvasA.getContext("2d");
|
this.canvasB = this.$refs.canvasB.getContext("2d");
|
this.$nextTick(() => {
|
this.drawing();
|
});
|
},
|
methods: {
|
init() {
|
this.leftArr = this.rawData.left.map((r) => {
|
return {
|
label: r,
|
line: [],
|
value: [],
|
};
|
});
|
this.rightArr = this.rawData.right.map((r) => {
|
return {
|
label: r,
|
};
|
});
|
// 等dom 渲染完成
|
this.$nextTick(() => {
|
this.leftDom = this.$refs.left.map((r, i) => {
|
return {
|
bom: r,
|
index: i,
|
};
|
});
|
this.rightDom = this.$refs.right.map((r, i) => {
|
return {
|
bom: r,
|
index: i,
|
};
|
});
|
this.value.map((r) => {
|
this.leftArr[r.left].line = this.attachment(r.left, r.right);
|
this.leftArr[r.left].value = [r.right];
|
});
|
this.drawing();
|
});
|
},
|
// 触摸结束
|
touchend(e, index) {
|
console.log("抬起", e,this.checkItem);
|
this.isDragging = false;
|
if (this.item.showAnswer) {
|
return false;
|
}
|
// let event = e.changedTouches[0];
|
// document.elementFromPoint 重点,根据x,y坐标 取当前元素 所有能运行的逻辑 都依托于这里。
|
let dom = document.elementFromPoint(e.pageX, e.pageY);
|
// 右边的dom是哪个
|
let right = this.rightDom.find((r) => r.bom === dom);
|
// 不管是哪个都清除掉 底部的线
|
this.canvasB.clearRect(0, 0, this.clientWidth, this.clientHeight);
|
// 如果不是右边的dom 直接把 线 干掉 -- 证明不是 没有拖到右边上
|
if (!right) {
|
this.checkItem.line = [];
|
return;
|
}
|
// 如果已有的不是我自己 直接替换掉上一个的
|
if (this.checkItem.value[0] !== right.index) {
|
let model = this.leftArr.find((r) => r.value[0] === right.index);
|
if (model) {
|
model.value = [];
|
model.line = [];
|
}
|
this.checkItem.value = [right.index];
|
}
|
// 重新赋值 线的 x y 轴
|
this.checkItem.line = this.attachment(this.checkItemIndex, right.index);
|
this.drawing();
|
let model = this.leftArr
|
.map((r, i) => {
|
return {
|
left: i,
|
right: r.value[0],
|
};
|
})
|
.filter((r) => r.right !== undefined);
|
// this.$emit("input", model);
|
this.item.userChoise = model;
|
// console.log(JSON.stringify(model));
|
},
|
// 触摸开始
|
touchstart(e, item,index) {
|
this.isDragging = true;
|
console.log("按下", e);
|
this.checkItem = item
|
this.checkItemIndex = index
|
e.stopPropagation();
|
// let event = e.targetTouches[0];
|
item.line = [
|
e.pageX,
|
e.pageY - this.$refs.connect.getBoundingClientRect().y + this.scrollTop,
|
];
|
},
|
// // 触摸中
|
// touchmove(e, item) {
|
// if(!this.isDragging) return false
|
// console.log('移动',e);
|
// if (this.item.showAnswer) {
|
// return false;
|
// }
|
// // let event = e.targetTouches[0];
|
// item.line[2] = e.pageX;
|
// item.line[3] = e.pageY - this.$refs.connect.getBoundingClientRect().y + this.scrollTop;
|
// this.backstrockline(item.line);
|
// },
|
|
// 移动中
|
mousemove(e) {
|
if (!this.isDragging) return false;
|
if (this.item.showAnswer) {
|
return false;
|
}
|
console.log('移动',e);
|
this.checkItem.line[2] = e.pageX;
|
this.checkItem.line[3] =
|
e.pageY - this.$refs.connect.getBoundingClientRect().y + this.scrollTop;
|
this.backstrockline(this.checkItem.line);
|
},
|
|
// 拖动的时候画线
|
backstrockline(val) {
|
let canvasB = this.canvasB;
|
canvasB.clearRect(0, 0, this.clientWidth, this.clientHeight);
|
canvasB.save();
|
canvasB.beginPath();
|
canvasB.lineWidth = 2;
|
canvasB.moveTo(val[0], val[1]);
|
canvasB.lineTo(val[2], val[3]);
|
canvasB.strokeStyle = "#0C6";
|
canvasB.stroke();
|
canvasB.restore();
|
},
|
// 渲染出拖动之后的线
|
drawing() {
|
let canvasA = this.canvasA;
|
this.canvasA.clearRect(0, 0, this.clientWidth, this.clientHeight);
|
canvasA.beginPath();
|
canvasA.lineWidth = 2;
|
for (let i = 0; i < this.leftArr.length; i++) {
|
const line = this.leftArr[i].line;
|
console.log(line);
|
console.log(this.leftArr[i]);
|
if (line.length) {
|
canvasA.moveTo(line[0], line[1]);
|
canvasA.lineTo(line[2], line[3]);
|
}
|
}
|
canvasA.strokeStyle = "#0C6";
|
canvasA.stroke();
|
},
|
// 根据 左边 和右边的 index,换算出 左右的X,Y轴坐标
|
attachment(index, rightIndex) {
|
let leftEvent = this.leftDom[index].bom;
|
let rightEvent = this.rightDom[rightIndex].bom;
|
// 为了让线都在中间 x轴不用改 最简单
|
let leftX = leftEvent.clientWidth + leftEvent.offsetLeft;
|
let rightX = rightEvent.offsetLeft;
|
let leftY = leftEvent.offsetTop + leftEvent.clientHeight / 2;
|
let rightY = rightEvent.offsetTop + rightEvent.clientHeight / 2;
|
return [leftX, leftY, rightX, rightY];
|
},
|
mouseup() {
|
console.log("大盒子抬起", this.isDragging);
|
this.isDragging = false;
|
},
|
},
|
};
|
</script>
|
|
<style lang="less" scoped>
|
.connect {
|
position: relative;
|
padding: 10px;
|
|
&-canvasA {
|
position: absolute;
|
left: 0px;
|
top: 0px;
|
z-index: 1;
|
}
|
|
&-canvasB {
|
position: absolute;
|
left: 0px;
|
top: 0px;
|
z-index: 0;
|
}
|
}
|
|
.answer {
|
width: 100%;
|
display: flex;
|
justify-content: space-between;
|
|
&-box {
|
display: flex;
|
flex-direction: column;
|
justify-content: space-between;
|
width: 40%;
|
text-align: center;
|
|
&-item {
|
z-index: 2;
|
// display: inline-flex;
|
padding: 10px;
|
border-radius: 4px;
|
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
|
margin-bottom: 20px;
|
line-height: 40px;
|
padding: 20px 0;
|
}
|
|
&-item:last-child {
|
margin-bottom: 0;
|
}
|
}
|
}
|
|
.connect {
|
-webkit-user-select: none; /* Safari */
|
-moz-user-select: none; /* Firefox */
|
-ms-user-select: none; /* IE10+/Edge */
|
user-select: none; /* 标准语法 */
|
}
|
</style>
|