手写顺序流程图组件

效果图

完整代码

html 复制代码
<template>
  <div>
    <div class="container" :style="{ width: `${spacingX * (colNum - 1) + itemWidth * colNum}px` }">
      <div
        v-for="(item, i) in recordList"
        :key="i"
        class="list-box"
        :style="{
          marginTop: i < colNum ? '0' : `${spacingY}px`,
          marginRight: i % (2 * colNum) === colNum - 1 || i % (2 * colNum) === colNum ? '0' : `${spacingX}px`,
          order: orderList[i] && orderList[i].order,
          visibility: orderList[i] && orderList[i].itemHide ? 'hidden' : 'visible'
        }"
      >
        <div class="cont-box" :style="{ width: itemWidth + 'px', height: itemHeight + 'px', backgroundColor: '#16a085' }">{{ item }}</div>
        <div v-if="i !== listLen - 1" class="arrow-box" :style="arrowStyle[orderList[i] && orderList[i].arrow]">
          <div class="line-tip" />
          <div class="arrow-tip" />
        </div>
      </div>
    </div>
  </div>
</template>

<script>
export default {
  name: 'FlowPath',
  data() {
    return {
      itemWidth: 75, // item宽度
      itemHeight: 75, // item高度
      colNum: 1, // 显示的列数
      spacingX: 40, // 列间距
      spacingY: 40, // 行间距
      rawList: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18], // 原始数据
      recordList: [], // 列表数据
      arrowStyle: { right: {}, down: {}, left: {}}, // 箭头样式
      orderList: [], // 列表排序序号
      listLen: '' // 列表数据长度
    }
  },
  mounted() {
    this.listLen = this.rawList.length
    this.initFun() // 初始化方法
    window.addEventListener('resize', this.initFun) // 页面宽度变化监听器
  },
  beforeDestroy() {
    window.removeEventListener('resize', this.initFun) // 组件销毁时移除 resize 事件监听器,避免内存泄漏
  },
  methods: {
    /* 初始化方法 */
    initFun() {
      const pageWidth = document.documentElement.clientWidth // 获取页面宽度(可视区域宽度)
      const minTotalWidth = this.itemWidth + this.spacingX // 每个 item(包含间距) 期望的最小总宽度为 minTotalWidth(单位:px)
      const newNum = Math.floor(pageWidth / minTotalWidth) // 计算 colNum,向下取整
      this.colNum = Math.max(newNum, 1) // 限制 colNum 的最小值,比如至少为 1 列
      // 更新箭头样式和列表样式,因为 colNum 变化了,相关布局依赖 colNum 列数
      this.setArrowStyle() // 设置箭头样式
      this.setOrderList() // 设置列表样式
    },
    /* 设置箭头样式 */
    setArrowStyle() {
      const left = {
        width: this.spacingX + 'px',
        top: this.itemHeight / 2 + 'px',
        left: -this.spacingX + 'px'
      }
      const right = {
        width: this.spacingX + 'px',
        top: this.itemHeight / 2 + 'px',
        right: -this.spacingX + 'px',
        transform: 'rotate(180deg)'
      }
      const down = {
        width: this.spacingY + 'px',
        left: this.itemWidth / 2 + 'px',
        bottom: -this.spacingY + 'px',
        transform: 'rotate(-90deg)',
        transformOrigin: 0
      }
      this.arrowStyle = { right, left, down }
    },
    /* 设置列表样式 */
    setOrderList() {
      this.recordList = JSON.parse(JSON.stringify(this.rawList))
      this.orderList = [] // 列表排序序号
      const n = this.colNum // 显示的列数
      const dbn = n * 2 // 列数 * 2
      // 添加占位的 item 项
      const arrLen = this.listLen
      const remainder = (arrLen - 1) % dbn
      if (remainder >= n && remainder < dbn) {
        const diff = dbn - 1 - remainder
        for (let i = 0; i < diff; i++) {
          this.orderList[arrLen + i] = {
            itemHide: true,
            order: arrLen + i
          }
          this.recordList[arrLen + i] = null
        }
      }
      // 设置 item 的箭头方向和顺序
      this.recordList.map((item, index) => {
        const i = index % dbn	// 余数
        if (i >= 0 && i < n) {
          this.orderList[index] = {
            order: index,
            arrow: i !== n - 1 ? 'right' : 'down'
          } // 不用改变顺序
        } else {
          this.orderList[index] = {
            order: index + ((n - 1) - 2 * (i - n)), // i - n 是与最近一侧的距离
            arrow: i !== dbn - 1 ? 'left' : 'down',
            itemHide: this.orderList[index]?.itemHide
          } // 需要改变顺序
        }
      })
    }
  }
}
</script>

<style scoped lang="scss">
.container {
  display: flex;
  flex-wrap: wrap;
  box-sizing: border-box;
  overflow: hidden;
  .list-box {
    position: relative;
    font-size: 20px;
    box-sizing: border-box;
    .cont-box {
    }
  }
}
/* 箭头区域 */
.arrow-box {
  $bgColor: #303133;
  position: absolute;
  // 线条样式
  .line-tip {
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    left: 3px;
    width: 90%;
    height: 2px;
    background-color: $bgColor;
  }
  // 箭头样式
  .arrow-tip {
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    left: 1px;
    width: 0;
    height: 0;
    border-top: 8px solid transparent;
    border-bottom: 8px solid transparent;
    border-right: 8px solid $bgColor;
  }
}
</style>
相关推荐
qiaochuanbiao3 小时前
三种方式修改AI生成的流程图,实现无损放大
流程图
GIS开发特训营7 天前
常见二三维GIS数据分类及处理流程图
学习·流程图·gis·gis开发·webgis
JZC_xiaozhong14 天前
OA 审批流与业务流程引擎区别:企业流程自动化进阶
运维·自动化·流程图·bpm·业务流程管理·流程设计可视化·流程监控
杨筱毅17 天前
【Android】Handler/Looper机制相关的类图和流程图
android·java·流程图
时光追逐者17 天前
一个使用 WPF 开发的 Diagram 画板工具(包含流程图FlowChart,思维导图MindEditor)
c#·.net·wpf·流程图
helloworddm18 天前
Orleans 流系统握手机制流程图
流程图
做科研的周师兄22 天前
【机器学习入门】8.2 主成分分析:一文吃透主成分分析(PCA)—— 从原理到核心逻辑
人工智能·算法·决策树·机器学习·流程图
做科研的周师兄1 个月前
【机器学习入门】7.1 决策树 —— 像 “判断流程图” 一样做分类
决策树·机器学习·流程图
东风西巷1 个月前
draw.io(免费流程图制作工具) 中文绿色版
学习·电脑·流程图·软件需求·draw.io
aesthetician1 个月前
ReactFlow:构建交互式节点流程图的完全指南
前端·流程图·react