效果图
推荐组合效果
推荐与双表头固定效果组合,实现如上例中横表头(日期)纵向固定,纵表头(类型)横向固定效果。 参照连接 表头固定,表身滚动实例
Vue.js 引入
< script src= "https://cdn.bootcss.com/vue/2.6.10/vue.js" > < / script>
CSS 代码
<style>
table {
border-collapse : collapse;
border-width : 1;
}
p {
width : 100px;
}
th,
td {
min-width : 20px;
text-align : center;
border-width : 1px;
border-style : solid;
border-color : #666;
}
th {
background-color : #34B4A0;
}
span {
border-radius : 50%;
height : 10px;
width : 10px;
display : block;
display : inline-block;
}
.yellow {
background-color : #F9A100;
border : #FCAA00 1px solid;
}
.green {
background-color : #34B4A0;
border : #46D8BC 1px solid;
}
.red {
background-color : #FF0D0D;
border : #FF2E2E 1px solid
}
.purple {
background-color : #8B64FF;
border : #8B64FF 1px solid;
}
.blue {
background-color : #299CED;
border : #299CED 1px solid;
}
</style>
vue 页面
< div id = " demo" >
< table>
< caption> Vue.JS 制作甘特图</ caption>
< thead>
< tr>
< th rowspan = " 2" colspan = " 2" > 项目/时间</ th>
< th :colspan = " days(day)" v-for = " (day, index) in AllMonths" > {{day|longDateToMonth}}</ th>
</ tr>
< tr>
< th v-for = " (day, index) in Dateinterval" > {{day|longDateToDay}}</ th>
</ tr>
</ thead>
< tbody>
< tr v-for = " (item, index) in jsonData" >
< td :rowspan = " colNum(item, index)" v-if = " showFormType(item, index)" >
< p>
{{item.formType}}
</ p>
</ td>
< td>
< p> {{item.type}}</ p>
</ td>
< td v-for = " day in Dateinterval" >
< span :class = " spanShow(item.value, day).color" v-show = " spanShow(item.value, day).show" > </ span>
</ td>
</ tr>
</ tbody>
</ table>
</ div>
javascript 代码
< script>
var fDate = function ( value) {
return value < 10 ? '0' + value : value;
}
Date. prototype. format = function ( ) {
return this . getFullYear ( ) + '-' + fDate ( this . getMonth ( ) + 1 ) + '-' + fDate ( this . getDate ( ) ) ;
} ;
var getAllDay = function ( startDate, endDate) {
var allDays = [ ] ;
var a = startDate. split ( '-' ) ;
var b = endDate. split ( '-' ) ;
var uDb = new Date ( ) . setUTCFullYear ( a[ 0 ] , a[ 1 ] - 1 , a[ 2 ] ) ;
var uDe = new Date ( ) . setUTCFullYear ( b[ 0 ] , b[ 1 ] - 1 , b[ 2 ] ) ;
for ( var i = uDb; i <= uDe; i = i + 24 * 60 * 60 * 1000 ) {
allDays. push ( new Date ( parseInt ( i) ) . format ( ) ) ;
}
return allDays;
} ;
var getAllMonth = function ( startDate, endDate) {
var allMonth = [ ] ;
var a = startDate. split ( '-' ) ;
var b = endDate. split ( '-' ) ;
var uDb = new Date ( ) . setUTCFullYear ( a[ 0 ] , a[ 1 ] - 1 , a[ 2 ] ) ;
var uDe = new Date ( ) . setUTCFullYear ( b[ 0 ] , b[ 1 ] - 1 , new Date ( b[ 0 ] , b[ 1 ] , 0 ) . getDate ( ) ) ;
while ( uDb <= uDe) {
allMonth. push ( new Date ( uDb) . getFullYear ( ) + '-' + fDate ( new Date ( uDb) . getMonth ( ) + 1 ) ) ;
uDb = new Date ( uDb) . setMonth ( new Date ( uDb) . getMonth ( ) + 1 ) ;
}
return allMonth;
} ;
< / script>
< script>
var demo = new Vue ( {
el: '#demo' ,
data: {
jsonData: sourceData. data,
startDate: sourceData. startDate,
endDate: sourceData. endDate,
AllMonths: getAllMonth ( sourceData. startDate, sourceData. endDate) ,
Dateinterval: getAllDay ( sourceData. startDate, sourceData. endDate) ,
} ,
methods: {
spanShow: function ( valArray, currentDate) {
var show = false ;
var color = "" ;
var filter = this . $options. filters[ 'strDateToTimeStamp' ] ;
for ( var i = 0 ; i < valArray. length; i++ ) {
var inInterval = false ;
inInterval = filter ( valArray[ i] . fromDate) <= filter ( currentDate) && filter (
currentDate) <= filter ( valArray[ i] . toDate)
if ( inInterval) {
color = valArray[ i] . spanClass;
}
show = show || inInterval;
}
return {
show: show,
color: color
} ;
} ,
days: function ( strDate) {
debugger ;
var sArr = this . startDate. split ( '-' ) ;
var eArr = this . endDate. split ( '-' ) ;
var arr = strDate. split ( '-' ) ;
if ( '' + arr[ 0 ] + arr[ 1 ] < '' + sArr[ 0 ] + sArr[ 1 ] || '' + arr[ 0 ] + arr[ 1 ] > '' + eArr[ 0 ] +
eArr[ 1 ] ) {
return 0 ;
}
if ( '' + arr[ 0 ] + arr[ 1 ] === '' + sArr[ 0 ] + sArr[ 1 ] ) {
return new Date ( arr[ 0 ] , arr[ 1 ] , 0 ) . getDate ( ) - new Date ( sArr[ 0 ] + '-' + sArr[ 1 ] + '-' +
sArr[ 2 ] )
. getDate ( ) + 1 ;
}
if ( '' + arr[ 0 ] + arr[ 1 ] === '' + eArr[ 0 ] + eArr[ 1 ] ) {
return new Date ( eArr[ 0 ] + '-' + eArr[ 1 ] + '-' + eArr[ 2 ] ) . getDate ( )
}
return new Date ( arr[ 0 ] , arr[ 1 ] , 0 ) . getDate ( ) ;
} ,
showFormType: function ( item, index) {
var show = true ;
if ( index > 0 && item. formType == this . jsonData[ index - 1 ]
. formType) {
show = false ;
}
return show;
} ,
colNum: function ( item, index) {
var iCount = 0 ;
if ( ! ( index > 0 && item. formType == this . jsonData[ index - 1 ]
. formType) ) {
this . jsonData. forEach ( ele => {
if ( item. formType == ele. formType) {
iCount++ ;
}
} ) ;
}
return iCount;
}
} ,
filters: {
strDateToTimeStamp: function ( strDate) {
return Date. parse ( strDate) ;
} ,
longDateToDay: function ( longDate) {
return fDate ( new Date ( Date. parse ( longDate) ) . getDate ( ) ) ;
} ,
longDateToMonth: function ( longDate) {
return fDate ( new Date ( Date. parse ( longDate) ) . getMonth ( ) + 1 ) ;
}
}
} )
< / script>
JSON 实例数据(为了方便,直接写在JS中)
< script>
var sourceData = {
'startDate' : '2018-12-01' ,
'endDate' : '2019-01-31' ,
'data' : [ {
"formType" : "DFM" ,
"type" : "计划" ,
"value" : [ {
"fromDate" : "2018-12-01" ,
"toDate" : "2018-12-06" ,
"spanClass" : "green"
} , {
"fromDate" : "2018-12-10" ,
"toDate" : "2018-12-11" ,
"spanClass" : "green"
} , {
"fromDate" : "2018-12-15" ,
"toDate" : "2018-12-16" ,
"spanClass" : "green"
} ]
} ,
{
"formType" : "DFM" ,
"type" : "实际" ,
"value" : [ {
"fromDate" : "2018-12-01" ,
"toDate" : "2018-12-07" ,
"spanClass" : "red"
} , {
"fromDate" : "2018-12-10" ,
"toDate" : "2018-12-11" ,
"spanClass" : "blue"
} , {
"fromDate" : "2018-12-15" ,
"toDate" : "2018-12-16" ,
"spanClass" : "blue"
} ]
} , {
"formType" : "DFM" ,
"type" : "客户回复" ,
"value" : [ {
"fromDate" : "2018-12-09" ,
"toDate" : "2018-12-09" ,
"spanClass" : "purple"
} , {
"fromDate" : "2018-12-14" ,
"toDate" : "2018-12-14" ,
"spanClass" : "purple"
} , {
"fromDate" : "2018-12-18" ,
"toDate" : "2018-12-18" ,
"spanClass" : "purple"
} ]
} ,
{
"formType" : "开模检讨" ,
"type" : "实际" ,
"value" : [ {
"fromDate" : "2018-12-20" ,
"toDate" : "2018-12-20" ,
"spanClass" : "yellow"
} ]
} ,
{
"formType" : "模具开发" ,
"type" : "计划" ,
"value" : [ {
"fromDate" : "2018-12-19" ,
"toDate" : "2019-01-10" ,
"spanClass" : "green"
} ]
} ,
{
"formType" : "模具开发" ,
"type" : "实际" ,
"value" : [ {
"fromDate" : "2018-12-19" ,
"toDate" : "2019-01-13" ,
"spanClass" : "red"
} ]
} , {
"formType" : "设计" ,
"type" : "计划" ,
"value" : [ {
"fromDate" : "2018-12-19" ,
"toDate" : "2018-12-21" ,
"spanClass" : "green"
} ]
} , {
"formType" : "设计" ,
"type" : "实际" ,
"value" : [ {
"fromDate" : "2018-12-19" ,
"toDate" : "2018-12-21" ,
"spanClass" : "yellow"
} ]
} , {
"formType" : "加工" ,
"type" : "计划" ,
"value" : [ {
"fromDate" : "2018-12-22" ,
"toDate" : "2019-01-06" ,
"spanClass" : "green"
} ]
} ,
{
"formType" : "加工" ,
"type" : "客户回复" ,
"value" : [ {
"fromDate" : "2018-12-22" ,
"toDate" : "2019-01-08" ,
"spanClass" : "purple"
} ]
} ,
{
"formType" : "加工" ,
"type" : "实际" ,
"value" : [ {
"fromDate" : "2018-12-22" ,
"toDate" : "2019-01-09" ,
"spanClass" : "red"
} ]
} ,
] ,
} ;
< / script>