效果如图
鼠标滑动效果
关联性效果
文章来源:https://www.toymoban.com/news/detail-642576.html
<template >
<div class="main" ref="predecessor">
<div class="search">
<div class="search-item">
<div class="search-item-label">
部门
</div>
<Treeselect v-model="dept"
:options="deptOptions"
show-count
placeholder="请选择部门"
@change="changeDept()"
/>
<!-- <el-cascader v-model="dept" clearable placeholder="请选择部门" >
<el-option v-for="item in deptOptions" :key="item.id" :label="item.label" :value="item.id">
</el-option>
</el-cascader> -->
</div>
<div class="search-item">
<div class="search-item-label">
周期
</div>
<el-cascader v-model="TypeSelectValue" :options="cycleTypeSelect" :props="{
checkStrictly: true,
expandTrigger: 'hover'
}" @change="handleChange" />
</div>
</div>
<div class="main-predecessor">
<div v-for="(item, index) in predecessorList" :key="'father' + index" class="father-predecessor">
<div v-for="(itm, idx) in item" :key="itm.id">
<div v-if="itm.status === 0 && itm.display === true" :id="itm.id" class="children-predecessor-big"
@mouseenter="enter(index, idx)" @mouseleave="leave()"
:style="changeCardList.indexOf(itm.id) === -1 ? '' : 'background:rgba(206, 210, 232, 0.87)'"
@click="clickDownsize(index, idx)">
<div class="caption">{{ itm.okrUserOrDept }}</div>
<Vptip :content="itm.okrOContent" :width="'100%'" style="max-width: 500px;margin-bottom: 10px;">
<span class="O-list" :style="changeOList.indexOf(itm.id) === -1 ? '' : 'color:#8198fe;font-weight: 700;'">O:
{{
`${itm.okrOContent}` }}</span>
</Vptip>
<div v-for="(im, indx) in itm.okrKrConfigList">
<Vptip :content="im.okrKrContent" :width="'100%'" style="max-width: 500px;">
<span class="kr-list"
:style="changeKrList.indexOf(im.id) === -1 ? '' : 'color:#8198fe;font-weight: 700;'">
KR{{ indx + 1 }}: {{ `${im.okrKrContent}` }}
</span>
</Vptip>
</div>
<div class="button">
<el-button type="text" class="open" v-if="itm.isHeader && !itm.buttonDisplay" :disabled="timeout !== 0"
@click.stop="commencementAll(index, itm.id, idx)" icon="el-icon-caret-bottom" />
<el-button type="text" class="open" v-if="itm.isHeader && itm.buttonDisplay" :disabled="timeout !== 0"
@click.stop="implicitAll(index, itm.id, idx)" icon="el-icon-caret-top" />
</div>
</div>
<div v-if="itm.status === 1 && itm.display === true" :id="itm.id" class="children-predecessor-middle"
@mouseenter="enter(index, idx)" @mouseleave="leave()"
:style="changeCardList.indexOf(itm.id) === -1 ? '' : 'background:rgba(206, 210, 232, 0.87)'"
@click="clickDownsize(index, idx)">
<div class="caption">{{ itm.okrUserOrDept }}</div>
<Vptip :content="itm.okrOContent" :width="'100%'" style="max-width: 500px;">
<span class="O-list" :style="changeOList.indexOf(itm.id) === -1 ? '' : 'color:#8198fe;font-weight: 700;'">O:
{{
`${itm.okrOContent}` }}</span>
</Vptip>
<div class="button">
<el-button type="text" class="open" v-if="itm.isHeader && !itm.buttonDisplay" :disabled="timeout !== 0"
@click.stop="commencementAll(index, itm.id, idx)" icon="el-icon-caret-bottom" />
<el-button type="text" class="open" v-if="itm.isHeader && itm.buttonDisplay" :disabled="timeout !== 0"
@click.stop="implicitAll(index, itm.id, idx)" icon="el-icon-caret-top" />
</div>
</div>
<div v-if="itm.status === 2 && itm.display === true" :id="itm.id" class="children-predecessor-small"
@mouseenter="enter(index, idx)" @mouseleave="leave()"
:style="changeCardList.indexOf(itm.id) === -1 ? '' : 'background:rgba(206, 210, 232, 0.87)'"
@click="clickDownsize(index, idx)">
<div class="caption">{{ itm.okrUserOrDept }}</div>
<div class="button">
<el-button type="text" class="open" v-if="itm.isHeader && !itm.buttonDisplay" :disabled="timeout !== 0"
@click.stop="commencementAll(index, itm.id, idx)" icon="el-icon-caret-bottom" />
<el-button type="text" class="open" v-if="itm.isHeader && itm.buttonDisplay" :disabled="timeout !== 0"
@click.stop="implicitAll(index, itm.id, idx)" icon="el-icon-caret-top" />
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script >
import { deptTreeSelect } from '@/api/system/user'
import okrConstant from '@/utils/okr/okrConstant'
import { getOkrPredecessor } from '@/api/okr/okrPredecessor'
import LeaderLine from 'leader-line'
import Vptip from "@/components/vptip" // 自定义Tooltip 文字提示
import Treeselect from '@riophae/vue-treeselect'
import '@riophae/vue-treeselect/dist/vue-treeselect.css'
export default {
name: 'okrPredecessor',
components: {
Vptip,Treeselect
},
data() {
return {
// 级联选择器下拉框
selectOKrForm: {
// 年份搜索值
okrCycleYear: okrConstant.yearDecade()[0].value,
// 季度搜索值
okrCycleQuarter: okrConstant.currentMonthIsQuarter(),
// 月份搜索值
okrCycleMonth: '',
},
TypeSelectValue: okrConstant.currentMonthIsQuarter(),
cycleTypeSelect: okrConstant.yearDecade(),
// 部门列表
deptOptions: [],
// 部门数据
dept: undefined,
// 控制按钮的倒计时
timeout: 0,
// 线条的数组
lineList: {},
// 接口返回的循环数据
predecessorListAll: [],
// 继承的渲染数据
predecessorList: [
// [
// {
// id: 0,
// // 展开还是缩小状态
// status: 0,
// // 能否展开或者缩小下一级
// isHeader: true,
// // 目前在显示还是隐藏
// display: true,
// // 当前按钮是展开还是隐藏
// buttonDisplay: true,
// // 父级相关的id合集
// fatherUserId: []
// }
// ]
],
// 所有的线条
allLineList: [],
// 应该画出来的线
drawLineList: [],
// 隐藏的数组list
displayList: [],
// 变色的卡片ID
changeCardList: [],
// 变色的KRID
changeKrList: [],
// 变色的OID
changeOList: [],
// 变色的线段
changeDrawLineList: []
}
},
watch:{
dept(){
this.search()
}
},
// 注册监听
mounted() {
// 获取部门列表
this.getDept()
window.addEventListener('resize', this.getScroll)
// 监听div滚动事件
let scrollView = this.$refs.predecessor
scrollView.addEventListener("scroll", this.positionLine);
document.body.style.overflow = 'hidden'
this.search()
},
// 销毁前
beforeDestroy() {
document.body.style.overflow = ''
// 销毁线条
this.removeLines()
},
// 销毁监听,防止内存泄露
destroyed() {
window.removeEventListener('resize', this.getScroll)
},
methods: {
// 获取部门列表
getDept() {
deptTreeSelect().then(response => {
this.deptOptions = response.data[0].children
})
},
// 鼠标移出事件(将O和KR两个数组归0)
leave() {
// 变色的KRID
this.changeKrList = []
// 变色的OID
this.changeOList = []
// 变色的卡片ID
this.changeCardList = []
// 线段颜色恢复
this.resumption()
// 特殊线段归0
this.changeDrawLineList = []
},
// 鼠标移入事件
enter(index, idx) {
// 变色的KRID
this.changeKrList = []
// 变色的OID
this.changeOList = []
// 变色的卡片ID
this.changeCardList = []
// 获取到第一层DIV之后首先对上下紧挨的关系层进行循环
// 寻找相关的父级
this.findFatherList(index, idx)
// 寻找相关的子集
this.findChildrenList(index, idx)
// 先将他本身的数据push进去
if (this.predecessorList[index][idx].okrKrConfigList) {
for (let i = 0; i < this.predecessorList[index][idx].okrKrConfigList.length; i++) {
this.changeKrList.push(this.predecessorList[index][idx].okrKrConfigList[i].id)
}
}
this.changeOList.push(this.predecessorList[index][idx].id)
this.changeCardList.push(this.predecessorList[index][idx].id)
// 获取线段变化线段
this.getChangeLine()
// 更改相关线段
this.changeLineColor()
},
// 获取相关需要更改线段
getChangeLine() {
this.changeDrawLineList = []
// 判断开头结尾都在变色的卡片之中
for (let j = 0; j < this.drawLineList.length; j++) {
if (this.changeCardList.indexOf(Number(this.drawLineList[j].start)) !== -1 && this.changeCardList.indexOf(Number(this.drawLineList[j].end)) !== -1) {
this.changeDrawLineList.push(this.drawLineList[j])
}
}
},
// 恢复相关线段颜色
resumption() {
for (let i = 0; i < this.changeDrawLineList.length; i++) {
this.twiceGetLine(this.changeDrawLineList[i].start, this.changeDrawLineList[i].end, i)
}
},
// 更改相关线段颜色
changeLineColor() {
for (let i = 0; i < this.changeDrawLineList.length; i++) {
this.changeGetLine(this.changeDrawLineList[i].start, this.changeDrawLineList[i].end, i)
}
},
// 寻找相关的子集
findChildrenList(index, idx) {
// 对所有的线段进行遍历(因为只有O能够继承,所以子集直接往下找,只要有就是要变色)
for (let i = 0; i < this.drawLineList.length; i++) {
// 寻找到以此为开头的数据
if (this.drawLineList[i].start === String(this.predecessorList[index][idx].id)) {
// 对页面数据进行遍历寻找出此ID的位置,为后续获取KR做准备
for (let x = 0; x < this.predecessorList.length; x++) {
if (this.predecessorList[x]) {
for (let y = 0; y < this.predecessorList[x].length; y++) {
// 寻找到线段结束点位的内容
if (String(this.predecessorList[x][y].id) === this.drawLineList[i].end) {
// 变色的OID
this.changeOList.push(this.predecessorList[x][y].id)
// 变色的卡片ID
this.changeCardList.push(this.predecessorList[x][y].id)
// 对KRLIST进行遍历,渲染KRLIST
for (let z = 0; z < this.predecessorList[x][y].okrKrConfigList.length; z++) {
// 将所有相关kr进行push
this.changeKrList.push(this.predecessorList[x][y].okrKrConfigList[z].id)
}
// 删除递归根节点功能
// this.findChildrenList(x, y)
}
}
}
}
}
}
},
// 寻找相关的父级
findFatherList(index, idx) {
let fatherList = this.predecessorList[index][idx].extendsKrs
// 对FATHERlIST进行遍历
for (let i = 0; i < fatherList.length; i++) {
// 只要是存在的Oid卡片就跟随变色(需要两点之间还存在连线关系)
for (let j = 0; j < this.drawLineList.length; j++) {
if (this.drawLineList[j].start === String(fatherList[i].okrId) && this.drawLineList[j].end === String(this.predecessorList[index][idx].id)) {
this.changeCardList.push(fatherList[i].okrId)
// 如果继承的是KR(O不变色,但是KR需要变色)
if (fatherList[i].krId !== null) {
this.changeKrList.push(fatherList[i].krId)
} else {
// 如果继承的是O,那么OKR全部变色,并且继续寻找上一层的OKR
// 将变色Opush进入O的数组
this.changeOList.push(fatherList[i].okrId)
// 将变色O所对应的KR全部push进入数组(遍历寻找对应O)
for (let x = 0; x < this.predecessorList.length; x++) {
if (this.predecessorList[x]) {
for (let y = 0; y < this.predecessorList[x].length; y++) {
// 找出对应的ID
if (fatherList[i].okrId === this.predecessorList[x][y].id) {
// 对ID中的OKR进行循环push
for (let z = 0; z < this.predecessorList[x][y].okrKrConfigList.length; z++) {
// 将所有相关kr进行push
this.changeKrList.push(this.predecessorList[x][y].okrKrConfigList[z].id)
}
// 寻找完O之后,将后生成的O继续进行上层寻找循环
// 删除递归根节点功能
// this.findFatherList(x, y)
}
}
}
}
}
}
}
}
},
// 级联改变方法
handleChange(value) {
this.selectOKrForm.okrCycleYear = ''
this.selectOKrForm.okrCycleQuarter = ''
this.selectOKrForm.okrCycleMonth = ''
value.forEach((element, index) => {
switch (index) {
case 0: this.selectOKrForm.okrCycleYear = element; break
case 1: this.selectOKrForm.okrCycleQuarter = element; break
case 2: this.selectOKrForm.okrCycleMonth = element; break
}
})
this.search()
},
// 搜索
search() {
let params = {
okrUserDept: this.dept,
okrCycleYear: this.selectOKrForm.okrCycleYear,
okrCycleQuarter: this.selectOKrForm.okrCycleQuarter,
okrCycleMonth: this.selectOKrForm.okrCycleMonth
}
// 跑接口之前销毁所有线条
this.removeLines()
// 获取继承关系详细数据
getOkrPredecessor(params).then(res => {
// 所有的线条
this.allLineList = []
// 应该画出来的线
this.drawLineList = []
// 页面渲染数据
this.predecessorList = []
this.predecessorListAll = res.data
// 递归逻辑
for (let i = 0; i < this.predecessorListAll.length; i++) {
for (let j = 0; j < this.predecessorListAll[i].inheritedToOkrId.length; j++) {
let level = this.predecessorListAll[i].level
let fatherUserId = []
// 获取fatherList
for (let x = 0; x < this.predecessorListAll[i].inheritedToOkrId[j].extendsKrs.length; x++) {
if (fatherUserId.indexOf(this.predecessorListAll[i].inheritedToOkrId[j].extendsKrs[x].okrId) === -1) {
fatherUserId.push(this.predecessorListAll[i].inheritedToOkrId[j].extendsKrs[x].okrId)
}
}
// 如果此层级还不存在先重置层级
if (!this.predecessorList[level]) {
this.predecessorList[level] = []
}
this.predecessorList[level].push(this.predecessorListAll[i].inheritedToOkrId[j])
this.predecessorList[level][this.predecessorList[level].length - 1].fatherUserId = fatherUserId
this.predecessorList[level][this.predecessorList[level].length - 1].status = 2
this.predecessorList[level][this.predecessorList[level].length - 1].isHeader = false
this.predecessorList[level][this.predecessorList[level].length - 1].display = true
this.predecessorList[level][this.predecessorList[level].length - 1].buttonDisplay = true
}
}
// 寻找父子关系的连线
this.findLineList()
// 更改header属性判断是否可以当标头
this.whetherIsHeader()
// 刷新数组变化导致的数据更改
this.$forceUpdate()
// 画线(页面加载有一个动画,需要等动画完毕再开始加载线条保证线条的稳定性)
setTimeout(() => { this.drawLine() }, 500)
})
},
// 判断是否可以当标头,是否含有展开收起属性
whetherIsHeader() {
// 对二维数组进行遍历
for (let x = 0; x < this.predecessorList.length; x++) {
// 判断此层级中是否有内容
if (this.predecessorList[x]) {
for (let y = 0; y < this.predecessorList[x].length; y++) {
// 对当前所有连线进行遍历
for (let i = 0; i < this.allLineList.length; i++) {
// 如果存在以此ID为开头的线段,证明为header,isHeader属性为true
if (String(this.predecessorList[x][y].id) === this.allLineList[i].start) {
this.predecessorList[x][y].isHeader = true
}
}
}
}
}
},
// 寻找父子关系的连线
findLineList() {
// 对二维数组进行循环
for (let i = 0; i < this.predecessorList.length; i++) {
if (this.predecessorList[i]) {
for (let j = 0; j < this.predecessorList[i].length; j++) {
// 对父级进行循环
if (this.predecessorList[i][j].fatherUserId) {
for (let x = 0; x < this.predecessorList[i][j].fatherUserId.length; x++) {
if (this.existent(this.predecessorList[i][j].fatherUserId[x], this.predecessorList[i][j].id)) {
this.allLineList.push(
{
start: String(this.predecessorList[i][j].fatherUserId[x]),
end: String(this.predecessorList[i][j].id)
}
)
}
}
}
}
}
}
// 将数据同步到渲染的线段中,默认全部显示
this.drawLineList = JSON.parse(JSON.stringify(this.allLineList))
},
// 验证是否存在该条数据
existent(start, end) {
// 对二维数组进行遍历
for (let i = 0; i < this.predecessorList.length; i++) {
if (this.predecessorList[i]) {
for (let j = 0; j < this.predecessorList[i].length; j++) {
if (this.predecessorList[i][j].id === start) {
// 如果开始符合,看结束是否存在
for (let x = 0; x < this.predecessorList.length; x++) {
if (this.predecessorList[x]) {
for (let y = 0; y < this.predecessorList[x].length; y++) {
if (this.predecessorList[x][y].id === end) {
return true
}
}
}
}
}
}
}
}
return false
},
// 点击展开
// 准备开始展开递归将所有关联的数据进行处理
commencementAll(index, id, idx) {
this.timeout = 1
// 防抖
setTimeout(() => {
this.timeout = 0
}, 500)
// 更改按钮
let changeIndex
for (let i = 0; i < this.predecessorList[index].length; i++) {
if (this.predecessorList[index][i].id === id) {
changeIndex = i
}
}
// 更改按钮状态
this.predecessorList[index][changeIndex].buttonDisplay = true
// 目前已经确认隐藏的id标题
// 把跟原标题有关的数据全都找出来再进行删除
let oldIdList = this.displayList
// 所有可以改回状态的ID
let deleteIdList = [id]
// 新的ID集合
let newIdList = []
// 进行遍历寻找不需要删除的数组
for (let i = index; i < this.predecessorList.length; i++) {
if (this.predecessorList[i]) {
for (let j = 0; j < this.predecessorList[i].length; j++) {
if (this.arbitrarily(deleteIdList, this.predecessorList[i][j].fatherUserId)) {
deleteIdList.push(this.predecessorList[i][j].id)
}
}
}
}
// 生成新数组
for (let i = 0; i < oldIdList.length; i++) {
let haveId = true
for (let j = 0; j < deleteIdList.length; j++) {
if (deleteIdList[j] === oldIdList[i]) {
haveId = false
}
}
if (haveId) {
newIdList.push(oldIdList[i])
}
}
// 当前禁止当头的数据 this.displayList
this.displayList = [...newIdList]
// 更改页面
this.commencement(index, id)
// 更改页面显示
this.enter(index, idx)
},
// 点击收起
implicitAll(index, id, idx) {
this.timeout = 1
// 防抖
setTimeout(() => {
this.timeout = 0
}, 1000)
// 更改按钮
let changeIndex
for (let i = 0; i < this.predecessorList[index].length; i++) {
if (this.predecessorList[index][i].id === id) {
changeIndex = i
}
}
// 更改按钮状态
this.predecessorList[index][changeIndex].buttonDisplay = false
// 寻找子集
this.findImplicit(index, id)
// 更改页面
this.implicit(index, id)
// 更改页面显示
this.enter(index, idx)
},
// 展开隐藏后续内容
commencement(index, id) {
// 操作线条
// 销毁线条
this.removeLines()
// 线条数组清零
let newDrawLineList = []
// 对目前所有线条进行循环
for (let i = 0; i < this.allLineList.length; i++) {
let remain = false
for (let j = 0; j < this.displayList.length; j++) {
if (this.allLineList[i].start === String(this.displayList[j])) {
remain = true
}
}
if (remain === false) {
newDrawLineList.push(this.allLineList[i])
}
}
// 操作卡片
// 寻找各个子集,并且观察子集是不是只有这一个fatherUserId
for (let i = index; i < this.predecessorList.length; i++) {
if (this.predecessorList[i]) {
for (let j = 0; j < this.predecessorList[i].length; j++) {
// 如果先前的隐藏那么展开后按钮状态为打开
if (this.predecessorList[i][j].display === false) {
this.predecessorList[i][j].buttonDisplay = true
}
// 只有从无到有的才进行回显
this.predecessorList[i][j].display = true
if (this.including(this.displayList, this.predecessorList[i][j].fatherUserId)) {
this.predecessorList[i][j].display = false
}
}
}
}
// 验证画线数据结尾是否实际存在
let trueLineList = []
for (let i = 0; i < newDrawLineList.length; i++) {
if (this.trueDiv(newDrawLineList[i].end)) {
trueLineList.push(newDrawLineList[i])
}
}
// 新的画线数据
this.drawLineList = trueLineList
// 重新画线
setTimeout(() => { this.drawLine() }, 50)
},
// 隐藏后续内容
implicit(index, id) {
// 操作线条
// 销毁线条
this.removeLines()
// 线条数组清零
let newDrawLineList = []
// 对目前所有线条进行循环
for (let i = 0; i < this.allLineList.length; i++) {
let remain = false
for (let j = 0; j < this.displayList.length; j++) {
if (this.allLineList[i].start === String(this.displayList[j])) {
remain = true
}
}
if (remain === false) {
newDrawLineList.push(this.allLineList[i])
}
}
// 操作卡片
// 寻找各个子集,并且观察子集是不是只有这一个fatherUserId
for (let i = index; i < this.predecessorList.length; i++) {
if (this.predecessorList[i]) {
for (let j = 0; j < this.predecessorList[i].length; j++) {
if (this.including(this.displayList, this.predecessorList[i][j].fatherUserId)) {
this.predecessorList[i][j].display = false
}
}
}
}
// 验证画线数据结尾是否实际存在
let trueLineList = []
for (let i = 0; i < newDrawLineList.length; i++) {
if (this.trueDiv(newDrawLineList[i].end)) {
trueLineList.push(newDrawLineList[i])
}
}
// 新的画线数据
this.drawLineList = trueLineList
// 重新画线
setTimeout(() => { this.drawLine() }, 50)
},
// div节点是否是实际存在的
trueDiv(id) {
for (let i = 0; i < this.predecessorList.length; i++) {
if (this.predecessorList[i]) {
for (let j = 0; j < this.predecessorList[i].length; j++) {
if (String(this.predecessorList[i][j].id) === id && this.predecessorList[i][j].display === true) {
return true
}
}
}
}
return false
},
// 寻找子集
findImplicit(index, id) {
// 目前已经确认隐藏的id标题
this.displayList.push(id)
// 进行遍历寻找
for (let i = index; i < this.predecessorList.length; i++) {
if (this.predecessorList[i]) {
for (let j = 0; j < this.predecessorList[i].length; j++) {
if (this.including(this.displayList, this.predecessorList[i][j].fatherUserId)) {
this.displayList.push(this.predecessorList[i][j].id)
}
}
}
}
let newArr = [];
for (let i = 0; i < this.displayList.length; i++) {
if (!newArr.includes(this.displayList[i])) {
newArr.push(this.displayList[i])
}
}
// 隐藏的数组数据: this.displayList
this.displayList = [...newArr]
},
// 判断子数组中是否存在任意包含关系,不需要全等,只要有一个就行
arbitrarily(list, fatherUserId) {
let x = 0
for (let i = 0; i < list.length; i++) {
for (let j = 0; j < fatherUserId.length; j++) {
if (list[i] === fatherUserId[j]) {
x++
}
}
}
if (x !== 0) {
return true
}
return false
},
// 判断子数组中是否存在包含关系
including(list, fatherUserId) {
let x = 0
for (let i = 0; i < list.length; i++) {
for (let j = 0; j < fatherUserId.length; j++) {
if (list[i] === fatherUserId[j]) {
x++
}
}
}
if (x === fatherUserId.length && fatherUserId.length !== 0) {
return true
}
return false
},
// 重新定位各线
positionLine() {
for (let i = 0; i < this.drawLineList.length; i++) {
let nameLine = this.drawLineList[i].start + '' + this.drawLineList[i].end
// 判断线段是否真实存在
if (this.lineList[nameLine] !== undefined) {
this.lineList[nameLine].position()
}
}
},
// 开始画线
drawLine() {
for (let i = 0; i < this.drawLineList.length; i++) {
this.getLine(this.drawLineList[i].start, this.drawLineList[i].end, i)
}
},
// 点击展开缩小重新定位线条
hideLines() {
for (let i = 0; i < this.drawLineList.length; i++) {
let nameLine = this.drawLineList[i].start + '' + this.drawLineList[i].end
this.lineList[nameLine].position()
}
},
// 隐藏线条
hideLine(start, end) {
let nameLine = start + end
this.lineList[nameLine].hide()
},
// 销毁线条
removeLines() {
for (let i = 0; i < this.drawLineList.length; i++) {
let nameLine = this.drawLineList[i].start + '' + this.drawLineList[i].end
this.lineList[nameLine].remove()
}
},
// 点击展开
clickDownsize(index, idx) {
// 卡片三种状态互相切换
if (this.predecessorList[index][idx].status === 0) {
this.predecessorList[index][idx].status = 1
} else if (this.predecessorList[index][idx].status === 1) {
this.predecessorList[index][idx].status = 2
} else {
this.predecessorList[index][idx].status = 0
}
let predecessor = JSON.parse(JSON.stringify(this.predecessorList))
this.predecessorList = []
this.predecessorList = JSON.parse(JSON.stringify(predecessor))
setTimeout(() => { this.positionLine() }, 50)
},
// 画线
changeGetLine(start, end, i) {
let lineStart = document.getElementById(start)
let lineEnd = document.getElementById(end)
let styleOption = {
color: 'red', // 指引线颜色
endPlug: '', // 指引线结束点的样式 hand,disc
size: 2, // 线条尺寸
startSocket: 'bottom', //在指引线开始的地方从元素左侧开始
endSocket: 'top', //在指引线开始的地方从元素右侧结束
// hide: true, // 绘制时隐藏,默认为false,在初始化时可能会出现闪烁的线条
// startPlugColor: '#ff3792', // 渐变色开始色
// endPlugColor: '#fff386', // 渐变色结束色
gradient: false, // 使用渐变色
outLineColor: 'blue',
path: 'fluid', // straight,arc,fluid,magnet,grid
// dash: {
// // 虚线样式
// animation: true // 让线条滚动起来
// },
hide: true,
}
let nameLine = start + end
this.lineList[nameLine].setOptions(styleOption)
/** 显示效果
* draw 绘制线条
* fade 淡入
* none 无效果,即直接显示
*/
// let showEffectName = 'draw'
// // 动画参数
// let animOptions = {
// // duration: 1000, //持续时长
// // timing: 'ease-in' // 动画函数
// }
// this.lineList[nameLine].show()
// this.lineList[nameLine].position()
},
// 恢复线段
twiceGetLine(start, end, i) {
let lineStart = document.getElementById(start)
let lineEnd = document.getElementById(end)
let styleOption = {
color: '#6a6a6a', // 指引线颜色
endPlug: '', // 指引线结束点的样式 hand,disc
size: 2, // 线条尺寸
startSocket: 'bottom', //在指引线开始的地方从元素左侧开始
endSocket: 'top', //在指引线开始的地方从元素右侧结束
// hide: true, // 绘制时隐藏,默认为false,在初始化时可能会出现闪烁的线条
// startPlugColor: '#ff3792', // 渐变色开始色
// endPlugColor: '#fff386', // 渐变色结束色
gradient: false, // 使用渐变色
outLineColor: '#6a6a6a',
path: 'fluid', // straight,arc,fluid,magnet,grid
// dash: {
// // 虚线样式
// animation: true // 让线条滚动起来
// },
hide: true,
}
let nameLine = start + end
this.lineList[nameLine].setOptions(styleOption)
},
// 画线
getLine(start, end, i) {
let lineStart = document.getElementById(start)
let lineEnd = document.getElementById(end)
let styleOption = {
color: '#6a6a6a', // 指引线颜色
endPlug: '', // 指引线结束点的样式 hand,disc
size: 2, // 线条尺寸
startSocket: 'bottom', //在指引线开始的地方从元素左侧开始
endSocket: 'top', //在指引线开始的地方从元素右侧结束
// hide: true, // 绘制时隐藏,默认为false,在初始化时可能会出现闪烁的线条
// startPlugColor: '#ff3792', // 渐变色开始色
// endPlugColor: '#fff386', // 渐变色结束色
gradient: false, // 使用渐变色
outLineColor: '#6a6a6a',
path: 'fluid', // straight,arc,fluid,magnet,grid
// dash: {
// // 虚线样式
// animation: true // 让线条滚动起来
// },
hide: true,
}
let nameLine = start + end
this.$set(this.lineList, `${nameLine}`, null)
this.lineList[nameLine] = new LeaderLine(lineStart, lineEnd, styleOption)
/** 显示效果
* draw 绘制线条
* fade 淡入
* none 无效果,即直接显示
*/
// let showEffectName = 'draw'
// // 动画参数
// let animOptions = {
// // duration: 1000, //持续时长
// // timing: 'ease-in' // 动画函数
// }
this.lineList[nameLine].show()
this.lineList[nameLine].position()
},
}
}
</script>
<style>
.leader-line {
z-index: -1
}
</style>
<style lang="scss" scoped >
.search-item-label {
width: 30%;
font-size: 14px;
color: #333;
font-weight: 600;
}
.search-item {
width: 40%;
display: flex;
align-items: center;
margin-right: 5%;
}
.vue-treeselect{
width: 80%;
}
.search {
margin-left: 20px;
margin-top: 20px;
width: 500px;
display: flex;
justify-content: space-between;
.el-button+.el-button {
margin-left: 0px;
}
}
.main {
height: calc(100vh - 84px);
overflow-x: scroll;
overflow-y: scroll;
}
.main-predecessor {
min-width: 1100px;
width: fit-content;
min-height: calc(100vh - 94px);
}
.father-predecessor {
display: flex;
justify-content: space-around;
align-items: flex-start;
}
.children-predecessor-big {
width: 250px;
height: 200px;
border: 1px solid #f8f8f8;
margin: 60px 10px;
border-radius: 6px;
box-shadow: rgba(136, 165, 191, 0.48) 6px 2px 16px 0px, rgba(255, 255, 255, 0.8) -6px -2px 16px 0px;
background-color: rgba(255, 255, 255, 0.95);
position: relative;
}
.children-predecessor-middle {
width: 200px;
height: 80px;
border: 1px solid #f8f8f8;
margin: 60px 10px;
border-radius: 6px;
box-shadow: rgba(136, 165, 191, 0.48) 6px 2px 16px 0px, rgba(255, 255, 255, 0.8) -6px -2px 16px 0px;
background-color: rgba(255, 255, 255, 0.95);
position: relative;
}
.children-predecessor-small {
width: 130px;
height: 50px;
border: 1px solid #f8f8f8;
margin: 60px 10px;
border-radius: 6px;
box-shadow: rgba(136, 165, 191, 0.48) 6px 2px 16px 0px, rgba(255, 255, 255, 0.8) -6px -2px 16px 0px;
background-color: rgba(255, 255, 255, 0.95);
position: relative;
}
.button {
position: absolute;
text-align: center;
bottom: -10px;
left: 0;
width: 100%;
height: 20px;
}
.caption {
text-align: center;
line-height: 30px;
}
.icon {
cursor: pointer;
float: right;
font-size: 20px;
line-height: 30px;
color: #158BBB;
margin-right: 10px;
}
::v-deep .open {
padding: 0 !important;
border: 1px solid #b4b4b4;
box-shadow: rgba(135, 138, 141, 0.48) 6px 2px 16px 0px, rgba(255, 255, 255, 0.8) -6px -2px 16px 0px;
background-color: rgba(255, 255, 255, 0.95);
border-radius: 50%;
}
.O-list {
margin-left: 10px;
font-size: 18px;
}
.kr-list {
margin-left: 10px;
font-size: 16px;
}
::v-deep .small-select {
.el-input__inner {
width: 120px;
}
}
</style>
文章来源地址https://www.toymoban.com/news/detail-642576.html
到了这里,关于vue手写多对多关联图,连线用leader-line的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!