手写顺序流程图组件

效果图

完整代码

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>
相关推荐
檐下翻书1734 天前
公司组织架构调整工具 在线可视化编辑平台
论文阅读·人工智能·信息可视化·架构·去中心化·流程图
程序员JerrySUN4 天前
别再把 HTTPS 和 OTA 看成两回事:一篇讲透 HTTPS 协议、安全通信机制与 Mender 升级加密链路的完整文章
android·java·开发语言·深度学习·流程图
GOWIN革文品牌咨询5 天前
工业软件越专业越难卖?用“表达可读化”把架构图、流程图、数据图讲清
流程图
min1811234565 天前
PC流程图模板大全 中文定制化满足不同行业需求
架构·pdf·流程图
min1811234565 天前
组织结构图导出PDF 高清无水印在线生成
网络·人工智能·架构·pdf·流程图·copilot
檐下翻书1735 天前
企业组织架构图导出Word 在线编辑免费工具
人工智能·信息可视化·去中心化·word·流程图·ai编程
檐下翻书1735 天前
PC流程图模板大全 中文定制化满足不同行业需求
论文阅读·信息可视化·数据挖掘·数据分析·流程图
xiami_world5 天前
深度评测:5款AI流程图生成工具——图像识别、Mermaid支持与文档解析能力对比
人工智能·ai·信息可视化·ai作画·流程图
a1117765 天前
堆叠式流程图编辑器(html 开源)
开发语言·前端·javascript·开源·编辑器·html·流程图
min1811234565 天前
在线绘制跨职能流程图电脑端简单操作优化部门协作效率
人工智能·系统架构·pdf·流程图