思路
通过定位的方式,借助固定格子宽度的计算, 使得任务块的渲染仅仅需要计算就可以实现了
<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-码上掘金