无插件实现一个甘特图组件

开发 · 15 天前 · 23 人浏览

思路

通过定位的方式,借助固定格子宽度的计算, 使得任务块的渲染仅仅需要计算就可以实现了
<div class="tableList" v-for="(item,index) in tableData" :key="index" :style="{width:taskWidth+'px'}">
    <div class="taskPoint" :style="{width:item.offsetWidth+'px',left:item.leftMargin + 'px'}"></div>
 </div>

核心代码1: 通过渐变重复背景实现格子效果

.tableList{
    height: 40px;
    border: 1px solid #DDDDDD;
    border-left: 0px;
    border-top: 0px;
    margin-left: -1px;
    position: relative;
    display: flex;
    align-items: center;
    width: 4000px;
    box-sizing:border-box;
    /*  以40px为间隔 从第1px 到40px部分都是透明,起点则是渲染为灰色 */
    background: repeating-linear-gradient(to right, #DDDDDD,  transparent 1px, transparent 40px); 
}

核心代码2:通过日期计算得到月日的宽度占用

因为固定了每一个格子宽度为40,此时顶部的日期计算按照天数计算即可

for(let i = 0;i<month;i++){
    // 得到当前月一共多少天  setDate(0) 设置为当月最后一天,getDate() 返回当月最后一天
    let day = new Date(new Date(new Date().setMonth(i+1)).setDate(0)).getDate()
    for(let j = 1; j <= day; j++){
      // 从一月开始循环插入天数据,固定是 40px; 还要判断一下是否为周末 以及是否是当天
      let isToday = +new Date(new Date(new Date().setMonth(i)).setDate(j)) === +new Date()
      let isWeeked = new Date(new Date(new Date().setMonth(i)).setDate(j)).getDay() // 0和6表示周末
      dayData.value.push({
        day:j,
        isToday,
        isWeekend:isWeeked === 0 || isWeeked === 6
      })
    }
    // 得到月数据和宽度
    monthData.value.push({
      month:`${year}-${String(i+1).padStart(2,0)}`,
      width:day * 40
    })
  }

核心代码3: 通过定位实现任务条的渲染和定位

tableData.value.forEach(item=>{
    // 得到今年的1月1号
    let current = new Date(new Date().setMonth(0)).setDate(1)
    let leftMargin = getDiffDate(current,item.startDate) * 40
    let offsetWidth = getDiffDate(item.startDate,item.endDate) * 40 + 40
    item.leftMargin = leftMargin
    item.offsetWidth = offsetWidth
  })

完整代码

在此基础上再进行如 季度、月、年的计算也是可行的,甚至是多条数据渲染也可以OK的
Gantt-码上掘金

甘特图
Theme Jasmine by Kent Liao