横道图,当初记录一下代码

参考:https://blog.csdn.net/qq_3359...
依据以上参考的思路,做了优化,然而整体还是有些区别的。

思路:

1.依据表格的开始与完结工夫,记录每条数据的开始与完结工夫戳,并比照出所有表格最开始的工夫与最晚工夫
2.依据表格最开始的工夫与最晚工夫,记录展现列(eg:[{year: 2015,months: [],days: []}]),细节就是每个月都记录开始日与完结日的工夫戳,每天天也记录时间戳
3.利用展现列的工夫戳,来动静计算

备注:一开始做的时候,每个单元格只计算出本人的单元格内条幅宽度而后优化就是把每个单元格去掉,每行只留下一个就能够了,而后算出总体条幅宽度计算,起初发现当你的列足够少,那么单元格的宽度是不固定的,那么此种办法就不适合了,因而依然在列少时,应用第一次做的,每个单元格只计算出本人的单元格内条幅,在代码中有体现

效果图

代码

HTML:

<template>    <div style="padding: 20px;">        <h1 style="text-align: center;">横道图</h1>        <div class="barchart">            <el-table                :data="tableData"                :span-method="objectSpanMethod"                border                >                <el-table-column                    fixed                    align="center"                    prop="name"                    label="阶段名称"                    width="100"                    key="-1"                    >                </el-table-column>                <el-table-column                    fixed                    align="center"                    prop="state"                    label="状态"                    width="80"                    key="-2"                    >                <template slot-scope="scope">                    <span v-if="scope.$index % 2 === 0">打算工期</span>                    <span v-else>理论工期</span>                </template>                </el-table-column>                <el-table-column                    fixed                    align="center"                    prop="beginDate"                    label="开始工夫"                    width="100"                    key="-3"                    >                    <template slot-scope="scope">                        <span>{{scope.row.beginDate}}</span>                    </template>                </el-table-column>                <el-table-column                    fixed                    align="center"                    prop="endDate"                    label="完结工夫"                    width="100"                    key="-4"                    >                    <template slot-scope="scope">                        <span>{{scope.row.endDate}}</span>                    </template>                </el-table-column>                <el-table-column                    fixed                    align="center"                    prop="days"                    label="工期(天)"                    width="100"                    key="-5"                    >                </el-table-column>                <!-- 渲染工夫(年|月) -->                <el-table-column                    v-if="IsShowyear"                    v-for="(item, index) in showMonths"                    :label="item.year"                    prop="showMonths"                    align="center"                    :key="index"                >                    <el-table-column                        v-for="(it, index1) in item.months"                        :label="it.str"                        prop="str"                        min-width="30"                        style="padding: 0; margin: 0;"                        align="center"                        :key="index1"                    >                        <template slot-scope="scope" class="progressCon">              <div v-if="getCellDateWidth > 0">                <div                v-if="index === 0 && index1 === 0 && scope.$index % 2 === 0"                class="progressUpon"                :style="{width:optimizeCalcWidth(scope.row),left:optimizeCalcLeft(scope.row)}"                ></div>                <div                v-else-if="index === 0 && index1 === 0 && scope.$index % 2 !== 0"                class="progressDownon"                :style="{width:optimizeCalcWidth(scope.row),left:optimizeCalcLeft(scope.row)}"                ></div>              </div>              <div v-else>                <div                v-if="scope.$index % 2 === 0"                :class="scope.row.beginTimeStamp <= it.endTimeStamp && scope.row.endTimeStamp >= it.beginTimeStamp ? 'progressUpon' : '' "                :style="{width:scope.row.beginTimeStamp <= it.endTimeStamp && scope.row.endTimeStamp >= it.beginTimeStamp ? calcwidth(scope.row,it) : '0px',left:scope.row.beginTimeStamp <= it.endTimeStamp && scope.row.endTimeStamp >= it.beginTimeStamp ? calcLeft(scope.row,it) : '0px'}"                ></div>                <div v-else                :class="scope.row.beginTimeStamp <= it.endTimeStamp && scope.row.endTimeStamp >= it.beginTimeStamp  ? 'progressDownon' : '' "                :style="{width:scope.row.beginTimeStamp <= it.endTimeStamp && scope.row.endTimeStamp >= it.beginTimeStamp ? calcwidth(scope.row,it) : '0px',left:scope.row.beginTimeStamp <= it.endTimeStamp && scope.row.endTimeStamp >= it.beginTimeStamp ? calcLeft(scope.row,it) : '0px'}"                ></div>              </div>                        </template>                    </el-table-column>                </el-table-column>                <!-- 渲染工夫(月|日) -->                <el-table-column                    v-if="!IsShowyear"                    v-for="(item, index) in showMonths"                    :label="item.year"                    prop="year"                    align="center"                    :key="index"                >                    <el-table-column                        v-for="(it, index1) in item.months"                        :label="it.str"                        prop="str"                        style="padding: 0; margin: 0;"                        align="center"                        :key="index1"                    >                        <el-table-column                            v-for="(itm, index2) in item.days[index1].daysArr"                            :label="itm.day"                            prop="day"                            min-width="30"                            style="padding: 0; margin: 0;"                            align="center"                            :key="index2"                        >                            <template slot-scope="scope" class="progressCon">                <div v-if="getCellDateWidth > 0">                  <div                  v-if="index === 0 && index1 === 0 && index2 === 0 && scope.$index % 2 === 0"                  class="progressUpon"                  :style="{width:optimizeCalcWidth(scope.row),left:optimizeCalcLeft(scope.row)}"                  ></div>                  <div                  v-else-if="index === 0 && index1 === 0 && index2 === 0 && scope.$index % 2 !== 0"                  class="progressDownon"                  :style="{width:optimizeCalcWidth(scope.row),left:optimizeCalcLeft(scope.row)}"                  ></div>                </div>                <div v-else>                  <div                  v-if="scope.$index % 2 === 0"                  :class="scope.row.beginTimeStamp <= itm.timestamp && scope.row.endTimeStamp >= itm.timestamp ? 'progressUpon' : '' "                  style="width:calc(100% + 2px)"                  ></div>                  <div v-else                  :class="scope.row.beginTimeStamp <= itm.timestamp && scope.row.endTimeStamp >= itm.timestamp  ? 'progressDownon' : '' "                  style="width:calc(100% + 2px)"                  ></div>                </div>                            </template>                        </el-table-column>                    </el-table-column>                </el-table-column>            </el-table>        </div>    </div></template>

JAVASCRIPT

<script>export default {        name: 'Barchart',        data() {            return {                showMonths:[],                tableData: [],                minDay:"", // 最小日期                maxDay:"", // 最大日期                IsShowyear:true // 显示年|月 、 月|日            }        },        computed:{      // 获取最小日期-月开始工夫戳      minDayTimeStamp() {        if(this.IsShowyear){          return this.showMonths[0].months[0].beginTimeStamp        }else{          return this.showMonths[0].days[0].daysArr[0].timestamp        }      },      // 获取最大日期工夫戳      maxDayTimeStamp() {        let Length = this.showMonths.length // 年有多少个        // 如果显示年|月 与 月|日 是不同的        if(this.IsShowyear){          let monthsLength = this.showMonths[Length - 1].months.length  //月有多少个          return this.showMonths[Length - 1].months[monthsLength - 1].endTimeStamp        }else{          let daysLength = this.showMonths[Length - 1].days.length          let daysarrLength = this.showMonths[Length - 1].days[daysLength - 1].daysArr.length  //天有多少个          return this.showMonths[Length - 1].days[daysLength - 1].daysArr[daysarrLength - 1].timestamp + 86400000  //+86400000 是因为工夫戳都是0点这样+1天的工夫戳,就示意最晚一天的最初的工夫        }      },      // 最大日期与最小日期的工夫戳差      maxAndminDayTimeStamp() {        return this.maxDayTimeStamp - this.minDayTimeStamp      },      // 获取日期单元格宽度 => 如果返回0则只用之前第一版的计算方法      getCellDateWidth() {        let num = 0 // 获取日期单元格数量        if(this.IsShowyear){          // 月数量          for(let i = 0;i < this.showMonths.length;i++){            num += this.showMonths[i].months.length          }        }else{          // 天数量          for(let i = 0;i < this.showMonths.length;i++){            for(let j = 0;j < this.showMonths[i].days.length;j++){              num += this.showMonths[i].days[j].daysArr.length            }          }        }        // 每个单元格最小30宽度        let MaxWidth = window.screen.width        let CellNum = MaxWidth / 30 > 0 ? MaxWidth / 30  : 0        if(num >= CellNum){ // 页面宽 / 单元格最小宽度 = 最多放下的值          return num * 30        }else{          // 单元格的值,就不能是最小值30了          // 须要获取dom的宽度,在进行计算,然而dom还未渲染实现,因而这里就不思考了,间接只用第一版的办法动静计算          // TODO          return 0        }      }        },        created() {            // 这里能够发送申请            this.tableData = [{            "id": 1,            "name": "王小虎2",            "state": "打算工期",            "beginDate": "2016-05-01",            "endDate": "2016-05-30",            "days": "1000"          }, {            "id": 1,            "name": "王小虎3",            "state": "打算工期",            "beginDate": "2016-05-15",            "endDate": "2016-05-22",            "days": "1000"          }, {            "id": 2,            "name": "王小虎3",            "state": "打算工期",            "beginDate": "2016-05-01",            "endDate": "2016-05-20",            "days": "1000"          }, {            "id": 2,            "name": "王小虎3",            "state": "打算工期",            "beginDate": "2016-05-01",            "endDate": "2016-05-20",            "days": "1000"          }, {            "id": 3,            "name": "王小虎3",            "state": "打算工期",            "beginDate": "2016-05-01",            "endDate": "2016-05-02",            "days": "1000"          }, {            "id": 3,            "name": "王小虎3",            "state": "打算工期",            "beginDate": "2016-05-01",            "endDate": "2016-05-02",            "days": "1000"          }, {            "id": 4,            "name": "王小虎3",            "state": "打算工期",            "beginDate": "2016-05-15",            "endDate": "2016-05-22",            "days": "1000"          }, {            "id": 4,            "name": "王小虎3",            "state": "打算工期",            "beginDate": "2016-05-15",            "endDate": "2016-05-22",            "days": "1000"          }, {            "id": 5,            "name": "王小虎3",            "state": "打算工期",            "beginDate": "2016-05-01",            "endDate": "2016-05-20",            "days": "1000"          }, {            "id": 5,            "name": "王小虎3",            "state": "打算工期",            "beginDate": "2016-05-01",            "endDate": "2016-05-20",            "days": "1000"          }, {            "id": 6,            "name": "王小虎3",            "state": "打算工期",            "beginDate": "2016-05-01",            "endDate": "2016-05-02",            "days": "1000"          }, {            "id": 6,            "name": "王小虎3",            "state": "打算工期",            "beginDate": "2016-05-01",            "endDate": "2016-05-02",            "days": "1000"          }, {            "id": 7,            "name": "王小虎3",            "state": "打算工期",            "beginDate": "2016-05-15",            "endDate": "2016-05-22",            "days": "1000"          }, {            "id": 7,            "name": "王小虎3",            "state": "打算工期",            "beginDate": "2016-05-15",            "endDate": "2016-05-22",            "days": "1000"          }, {            "id": 8,            "name": "王小虎3",            "state": "打算工期",            "beginDate": "2016-05-01",            "endDate": "2016-05-20",            "days": "1000"          }, {            "id": 8,            "name": "王小虎3",            "state": "打算工期",            "beginDate": "2016-05-01",            "endDate": "2016-05-20",            "days": "1000"          }, {            "id": 9,            "name": "王小虎3",            "state": "打算工期",            "beginDate": "2016-05-01",            "endDate": "2016-05-02",            "days": "1000"          }, {            "id": 9,            "name": "王小虎3",            "state": "打算工期",            "beginDate": "2016-05-01",            "endDate": "2016-05-02",            "days": "1000"          }]            this.setrowspans() // 设置合并            this.getChartTitle() // 渲染的信息        },        methods: {      optimizeCalcWidth(val) {       let SumNum = this.maxAndminDayTimeStamp       let diffNum = this.IsShowyear ? val.endTimeStamp - val.beginTimeStamp : val.endTimeStamp + 84600000 - val.beginTimeStamp  // 完结日期 - 开始日期       let rate = Math.round(diffNum / SumNum * 10000) / 100.00 //失去百分比       let widthPx = this.getCellDateWidth * rate / 100.00       return widthPx + 'px'      },      optimizeCalcLeft(val) {        let SumNum = this.maxAndminDayTimeStamp        let diffNum = val.beginTimeStamp - this.minDayTimeStamp // 开始日期 - 整个月开始日期        let rate = Math.round(diffNum / SumNum * 10000) / 100.00 //失去百分比        let leftPx = this.getCellDateWidth * rate / 100.00        return leftPx + 'px'      },      // 计算图表的Left      calcLeft(val,date) {          // 如果本月的最大工夫戳都没有完结工夫长,那么就可判断          if(val.endTimeStamp > date.endTimeStamp){              // 如果本月开始日期小于开始日期              if(val.beginTimeStamp > date.beginTimeStamp){                  // 进行判断                  let diffNum = val.beginTimeStamp - date.beginTimeStamp                  let SumNum = date.endTimeStamp - date.beginTimeStamp                  let rate =  100 - Math.round(diffNum / SumNum * 10000) / 100.00                  // 地位判断                  return rate+"%"              }          }else if(val.endTimeStamp > date.beginTimeStamp && val.endTimeStamp < date.endTimeStamp){                  // 进行判断                  if(val.beginTimeStamp > date.beginTimeStamp){                      // 都在一个单元格中                      let diffNum = val.beginTimeStamp - date.beginTimeStamp                      let SumNum = date.endTimeStamp - date.beginTimeStamp                      let rate =  Math.round(diffNum / SumNum * 10000) / 100.00                      // 地位判断                      return rate+"%"                  }              }          return '0px'      },      // 计算图表的Width      calcwidth(val,date) {          if(this.IsShowyear){              // 如果是 年|月              // 1. 如果本月的最大工夫戳都没有完结工夫长,那么就可设置100%              // 2. 如果本月的最小工夫戳比完结工夫长,那么设置0              // 3. 如果本月的最小工夫戳没有完结工夫长,那么进行判断              if(val.endTimeStamp > date.endTimeStamp){                  // 如果本月开始日期小于开始日期                  if(val.beginTimeStamp > date.beginTimeStamp){                      // 进行判断                      let diffNum = val.beginTimeStamp - date.beginTimeStamp                      let SumNum = date.endTimeStamp - date.beginTimeStamp                      let rate = Math.round(diffNum / SumNum * 10000) / 100.00                      return 'calc('+ rate +'% + 2px)' // 完结工夫超过本月最大工夫戳间接+2px                  }                  return 'calc(100% + 2px)'              }else if(val.endTimeStamp < date.beginTimeStamp){                  return '0px'              }else if(val.endTimeStamp > date.beginTimeStamp && val.endTimeStamp < date.endTimeStamp){                  // 进行判断                  if(val.beginTimeStamp > date.beginTimeStamp){                      // 都在一个单元格中                      let SumNum = date.endTimeStamp - date.beginTimeStamp // 全月多多数                      let diffNum = val.endTimeStamp - val.beginTimeStamp // 过程多多数                      diffNum = diffNum === 0 ?  86400000 : diffNum                      let rate = Math.round(diffNum / SumNum * 10000) / 100.00                      return 'calc('+ rate +'%)'                  }else{                      // 不在一个单元格中,则不须要判断任何信息                      let diffNum = val.endTimeStamp - date.beginTimeStamp                      let SumNum = date.endTimeStamp - date.beginTimeStamp                      let rate = Math.round(diffNum / SumNum * 10000) / 100.00                      return 'calc('+ rate +'%)'                  }              }          }else{              // 如果是 月|日              // 1.如果开始工夫大于 天的工夫戳,则为0              // 2.如果完结工夫小于 天的工夫戳,则为100%              if(val.beginTimeStamp > date.timestamp){                  return '0px'              }else if(val.beginTimeStamp < date.timestamp && val.endTimeStamp > date.timestamp){                  return 'calc(100% + 2px)'              }          }          return '0px'      },            //取得数据雷同的行数(网络复制)            objectSpanMethod({ row, column, rowIndex, columnIndex }) {                if (columnIndex === 0) {                    return {                        rowspan: row.rowspan,                        colspan: 1                    };                }            },            // 依据id去分组(网络复制)            setrowspans() {                // 先给所有的数据都加一个v.rowspan = 1                this.tableData.forEach(v => {                    v.rowspan = 1;                });                // 双层循环                for (let i = 0; i < this.tableData.length; i++) {                    // 内层循环,下面曾经给所有的行都加了v.rowspan = 1                    // 这里进行判断                    // 如果以后行的id和下一行的id相等                    // 就把以后v.rowspan + 1                    // 下一行的v.rowspan - 1                    for (let j = i + 1; j < this.tableData.length; j++) {                        //此处可依据雷同字段进行合并,此处是依据的id                        if (this.tableData[i].id === this.tableData[j].id) {                            this.tableData[i].rowspan++;                            this.tableData[j].rowspan--;                        }                    }                    // 这里跳过曾经反复的数据                    i = i + this.tableData[i].rowspan - 1;                }            },            // 渲染表格头,首先是年月,如2018年11月            getChartTitle(startDate, endDate){                var chartTable = this.tableData;                // 筹备日期,为了避免屡次赋值属性,导致计算属性从新计算,决定只赋值一次        let maxDayParams = "",minDayParams = ""                for(var i = 0; i < chartTable.length; i++){                    var StartDate = chartTable[i].beginDate;                    var EndDate = chartTable[i].endDate;                    var mainObj = chartTable[i];                    // 打算日期                    maxDayParams === "" ? maxDayParams = EndDate : ''                    minDayParams === "" ? minDayParams = StartDate : ""                    maxDayParams = this.compareDate(EndDate,maxDayParams,true)                    minDayParams = this.compareDate(StartDate,minDayParams,false)                    var days = this.GetNumberOfDays(StartDate,EndDate) // 计算工期                    this.tableData[i].days = days + 1 // 加一是因为没算结算当天                    // 记录时间戳                    this.tableData[i].beginTimeStamp = this.getTimeStamp(StartDate)                    this.tableData[i].endTimeStamp = this.getTimeStamp(EndDate)                }        this.minDay = minDayParams        this.maxDay = maxDayParams                console.log("小:"+this.minDay)                console.log("大:"+this.maxDay)                this.getYearArr()                console.log(this.showMonths)            },            // 获取须要的格局的年月日信息            getYearArr(){                // 如果有一个日期相差超过366天,依照年,不超过则按天                var days = this.GetNumberOfDays(this.minDay,this.maxDay)                if(days >= 365){                    //须要记录月份                    this.IsShowyear = true                }else{                    //须要记录天数                    this.IsShowyear = false                }                // 获取须要格局的年月信息                let yearArr = []; // 存年                let minYear = new Date(this.minDay).getFullYear();                let maxYear = new Date(this.maxDay).getFullYear();                // 保留年                if(minYear === maxYear){                    yearArr.push({                        year: minYear+"",                        months: [],        // 放月的数组                        days: []                    })                }else{                    for(let i = minYear;i <= maxYear;i++){                        yearArr.push({                            year: i+"",                            months: [],        // 放月的数组                            days: []                        })                    }                }                // 保留月                for(let i = 0;i < yearArr.length;i++){                    let minMonth = 1                    if(i === 0){                        minMonth = new Date(this.minDay).getMonth() + 1;                    }                    // 1.eg:2016年9月 至 2019年01月                    // 2.如果只有一个年,那么月份就是最小月到最大月                    if(yearArr.length > 1){                        // 如果是最初一年,那么就要判断是否到最初一个月                        if(yearArr.length - 1 === i){                            let maxMonth = new Date(this.maxDay).getMonth() + 1;                            let _maxDay = new Date(this.maxDay).getDate() // 最大日期 天数                            let j = 1                            while(j <= maxMonth){                                let monthsDays = this.getLastDay(yearArr[i].year, j); // 获取月份一共有多少天                                let timestampstr = this.getTimeStamp(yearArr[i].year +"-"+  (j > 9 ? j : '0'+j) + "-" + monthsDays)                                let timestampstr1 = this.getTimeStamp(yearArr[i].year +"-"+  (j > 9 ? j : '0'+j) + "-01")                                yearArr[i].months.push({str:j+"月",num:j,endTimeStamp:timestampstr,beginTimeStamp:timestampstr1});// 记录最大最小的工夫戳                                // 如果显示月|天 才用记录天                                if(!this.IsShowyear){                                    yearArr[i].days[yearArr[i].days.length] = {year: "",month: "",daysArr: {}}                                    yearArr[i].days[yearArr[i].days.length - 1].year = yearArr[i].year    // 赋值年                                    yearArr[i].days[yearArr[i].days.length - 1].month = j;    // 赋值月                                    yearArr[i].days[yearArr[i].days.length - 1].daysArr = []                                    // 如果完结月,不是到本月最初一天,而是截止到最                                    if(j === maxMonth){                                        monthsDays = _maxDay                                    }                                    for(let k = 1; k <= monthsDays; k++){                                        timestampstr = this.getTimeStamp(yearArr[i].year +"-"+  (j > 9 ? j : '0'+j) + "-" + (k > 9 ? k : '0'+k))                                        yearArr[i].days[yearArr[i].days.length - 1].daysArr.push({day: k+"",timestamp:timestampstr});// 赋值天                                    }                                }                                j++                            }                        }else{                            if(i === 0){                                let j = minMonth                                let _minDay = new Date(this.minDay).getDate() // 最小日期 天数                                while(j <= 12){                                    let monthsDays = this.getLastDay(yearArr[i].year, j); // 获取月份一共有多少天                                    let timestampstr = this.getTimeStamp(yearArr[i].year +"-"+  (j > 9 ? j : '0'+j) + "-" + monthsDays)                                    let timestampstr1 = this.getTimeStamp(yearArr[i].year +"-"+  (j > 9 ? j : '0'+j) + "-01")                                    yearArr[i].months.push({str:j+"月",num:j,endTimeStamp:timestampstr,beginTimeStamp:timestampstr1});// 记录最大最小的工夫戳                                    // 如果显示月|天 才用记录天                                    if(!this.IsShowyear){                                        yearArr[i].days[yearArr[i].days.length] = {year: "",month: "",daysArr: {}}                                        yearArr[i].days[yearArr[i].days.length - 1].year = yearArr[i].year    // 赋值月                                        yearArr[i].days[yearArr[i].days.length - 1].month = j     // 赋值月                                        yearArr[i].days[yearArr[i].days.length - 1].daysArr = []                                        for(let k = 1; k <= monthsDays; k++){                                            // 如果开始月,就不从1日开始,而是从最开始的日期那天开始算起                                            if(k === 1 && j === minMonth){                                                k = _minDay                                            }                                            timestampstr = this.getTimeStamp(yearArr[i].year +"-"+  (j > 9 ? j : '0'+j) + "-" + (k > 9 ? k : '0'+k))                                            yearArr[i].days[yearArr[i].days.length - 1].daysArr.push({day: k+"",timestamp:timestampstr});// 赋值天                                        }                                    }                                    j++                                }                            }else{                                let j = 1                                while(j <= 12){                                    let monthsDays = this.getLastDay(yearArr[i].year, j); // 获取月份一共有多少天                                    let timestampstr = this.getTimeStamp(yearArr[i].year +"-"+  (j > 9 ? j : '0'+j) + "-" + monthsDays)                                    let timestampstr1 = this.getTimeStamp(yearArr[i].year +"-"+  (j > 9 ? j : '0'+j) + "-01")                                    yearArr[i].months.push({str:j+"月",num:j,endTimeStamp:timestampstr,beginTimeStamp:timestampstr1});// 记录最大最小的工夫戳                                    // 如果显示月|天 才用记录天                                    if(!this.IsShowyear){                                        yearArr[i].days[yearArr[i].days.length] = {year: "",month: "",daysArr: {}}                                        yearArr[i].days[yearArr[i].days.length - 1].year = yearArr[i].year    // 赋值年                                        yearArr[i].days[yearArr[i].days.length - 1].month = j // 赋值月                                        yearArr[i].days[yearArr[i].days.length - 1].daysArr = []                                        for(let k = 1; k <= monthsDays; k++){                                            timestampstr = this.getTimeStamp(yearArr[i].year +"-"+  (j > 9 ? j : '0'+j) + "-" + (k > 9 ? k : '0'+k))                                            yearArr[i].days[yearArr[i].days.length - 1].daysArr.push({day: k+"",timestamp:timestampstr});// 赋值天                                        }                                    }                                    j++                                }                            }                        }                    }else{                        // 如果只有一年那么没有必要判断是否记录天                        let maxMonth = new Date(this.maxDay).getMonth() + 1;                        let _minMonth = minMonth                        let _minDay = new Date(this.minDay).getDate() // 最小日期 天数                        let _maxDay = new Date(this.maxDay).getDate() // 最大日期 天数                        while(_minMonth <= maxMonth){                            let monthsDays = this.getLastDay(yearArr[i].year, _minMonth); // 获取月份一共有多少天                            let timestampstr = this.getTimeStamp(yearArr[i].year +"-"+  (_minMonth > 9 ? _minMonth : '0'+_minMonth) + "-" + monthsDays)                            let timestampstr1 = this.getTimeStamp(yearArr[i].year +"-"+  (_minMonth > 9 ? _minMonth : '0'+_minMonth) + "-01")                            yearArr[i].months.push({str:_minMonth+"月",num:_minMonth,endTimeStamp:timestampstr,beginTimeStamp:timestampstr1});// 记录最大最小的工夫戳                            yearArr[i].days[yearArr[i].days.length] = {year: "",month: "",daysArr: {}}                            yearArr[i].days[yearArr[i].days.length - 1].year = yearArr[i].year     // 赋值月                            yearArr[i].days[yearArr[i].days.length - 1].month = _minMonth    // 赋值月                            yearArr[i].days[yearArr[i].days.length - 1].daysArr = []                            // 如果完结月,不是到本月最初一天,而是截止到最                            if(_minMonth === maxMonth){                                monthsDays = _maxDay                            }                            for(let k = 1; k <= monthsDays; k++){                                // 如果开始月,就不从1日开始,而是从最开始的日期那天开始算起                                if(k === 1 && _minMonth === minMonth){                                    k = _minDay                                }                                timestampstr = this.getTimeStamp(yearArr[i].year +"-"+  (_minMonth > 9 ? _minMonth : '0'+_minMonth) + "-" + (k > 9 ? k : '0'+k))                                yearArr[i].days[yearArr[i].days.length - 1].daysArr.push({day: k+"",timestamp:timestampstr});// 赋值天                            }                            _minMonth++                        }                    }                }                this.showMonths = yearArr            },            // 获取月的最初一天            getLastDay(myyear, mymonth){                var new_date = new Date(myyear, mymonth, 0);                return new_date.getDate();            },            // 取得天数            GetNumberOfDays(date1,date2){                //date1:开始日期,date2完结日期                var a1 = Date.parse(new Date(date1));                var a2 = Date.parse(new Date(date2));                var day = parseInt((a2-a1)/ 86400000);//外围:工夫戳相减,而后除以天数                return day            },            // 工夫比拟 true 比大            compareDate(dateTime1,dateTime2,condition = true)            {                var formatDate1 = new Date(dateTime1)                var formatDate2 = new Date(dateTime2)                if(formatDate1 >= formatDate2)                {                    return condition ? dateTime1 : dateTime2                }                else                {                    return condition ? dateTime2 : dateTime1                }            },            // 获取工夫戳            getTimeStamp(val){                return new Date(val).getTime()            },        },    }</script>

CSS

<style>/* 边框粗一点 */.barchart .el-table--border td,.barchart .el-table--border th {        border-width: 2px;    }  /* 单元格padding */  .barchart .el-table--border th:first-child .cell, .el-table--border td:first-child .cell{    padding: 0px;  }    .barchart .el-table th > .cell{    padding: 0px;    }    /* 单元格高度 */    .barchart .el-table--medium th,.barchart  .el-table--medium td {~~~~        padding: 0px 0px !important;            height: 25px !important;    }    .barchart .progressCon{        padding: 0;        margin: 0;        position: relative;    }    .barchart .progressUpon{        background: rgb(38, 84, 124);        height: 1em;        /* width: calc(100% + 2px); // +2是因为边框线为2px*/        z-index: 2;        position: absolute;        top: 25%;        left:0px    }    .barchart .progressDownon{        background: rgb(255,209,102);        height: 1em;        /* width: calc(100% + 2px); // +2是因为边框线为2px*/        z-index: 2;        position: absolute;        top: 25%;        left:0px    }</style>

右侧图表与左侧的滚动条独立互不影响

效果图

代码

html
<template><div class="barchart"    v-loading="rendering"    element-loading-text="拼命加载中"    element-loading-spinner="el-icon-loading"    element-loading-background="rgba(0, 0, 0, 0.8)">            <div class="left">        <el-table            :data="tableData"            :span-method="objectSpanMethod"            border            >            <el-table-column                align="center"                prop="name"                label="阶段名称"                width="100"                key="-1"                >            </el-table-column>            <el-table-column                align="center"                prop="state"                label="状态"                width="80"                key="-2"                >            <template slot-scope="scope">                <span v-if="scope.$index % 2 === 0">打算工期</span>                <span v-else>理论工期</span>            </template>            </el-table-column>            <el-table-column                align="center"                prop="beginDate"                label="开始工夫"                width="100"                key="-3"                >                <template slot-scope="scope">                    <span>{{scope.row.beginDate}}</span>                </template>            </el-table-column>            <el-table-column                align="center"                prop="endDate"                label="完结工夫"                width="100"                key="-4"                >                <template slot-scope="scope">                    <span>{{scope.row.endDate}}</span>                </template>            </el-table-column>            <el-table-column                align="center"                prop="days"                label="工期(天)"                width="100"                key="-5"                >            </el-table-column>        </el-table>      </div>      <div class="right">        <el-table            :data="tableData"            border            >            <!-- 渲染工夫(年|月) -->            <el-table-column                v-if="IsShowyear"                v-for="(item, index) in showMonths"                :label="item.year"                prop="showMonths"                align="center"                :key="index"            >                <el-table-column                    v-for="(it, index1) in item.months"                    :label="it.str"                    prop="str"                    min-width="30"                    style="padding: 0; margin: 0;"                    align="center"                    :key="index1"                >                    <template slot-scope="scope" class="progressCon">                <div v-if="getCellDateWidth > 0">                  <div                  v-if="index === 0 && index1 === 0 && scope.$index % 2 === 0"                  class="progressUpon"                  :style="{width:optimizeCalcWidth(scope.row),left:optimizeCalcLeft(scope.row)}"                  ></div>                  <div                  v-else-if="index === 0 && index1 === 0 && scope.$index % 2 !== 0"                  class="progressDownon"                  :style="{width:optimizeCalcWidth(scope.row),left:optimizeCalcLeft(scope.row)}"                  ></div>                </div>                <div v-else>                  <div                  v-if="scope.$index % 2 === 0"                  :class="scope.row.beginTimeStamp <= it.endTimeStamp && scope.row.endTimeStamp >= it.beginTimeStamp ? 'progressUpon' : '' "                  :style="{width:scope.row.beginTimeStamp <= it.endTimeStamp && scope.row.endTimeStamp >= it.beginTimeStamp ? calcwidth(scope.row,it) : '0px',left:scope.row.beginTimeStamp <= it.endTimeStamp && scope.row.endTimeStamp >= it.beginTimeStamp ? calcLeft(scope.row,it) : '0px'}"                  ></div>                  <div v-else                  :class="scope.row.beginTimeStamp <= it.endTimeStamp && scope.row.endTimeStamp >= it.beginTimeStamp  ? 'progressDownon' : '' "                  :style="{width:scope.row.beginTimeStamp <= it.endTimeStamp && scope.row.endTimeStamp >= it.beginTimeStamp ? calcwidth(scope.row,it) : '0px',left:scope.row.beginTimeStamp <= it.endTimeStamp && scope.row.endTimeStamp >= it.beginTimeStamp ? calcLeft(scope.row,it) : '0px'}"                  ></div>                </div>                    </template>                </el-table-column>            </el-table-column>            <!-- 渲染工夫(月|日) -->            <el-table-column                v-if="!IsShowyear"                v-for="(item, index) in showMonths"                :label="item.year"                prop="year"                align="center"                :key="index"            >                <el-table-column                    v-for="(it, index1) in item.months"                    :label="it.str"                    prop="str"                    style="padding: 0; margin: 0;"                    align="center"                    :key="index1"                >                    <el-table-column                        v-for="(itm, index2) in item.days[index1].daysArr"                        :label="itm.day"                        prop="day"                        min-width="30"                        style="padding: 0; margin: 0;"                        align="center"                        :key="index2"                    >                        <template slot-scope="scope" class="progressCon">                  <div v-if="getCellDateWidth > 0">                    <div                    v-if="index === 0 && index1 === 0 && index2 === 0 && scope.$index % 2 === 0"                    class="progressUpon"                    :style="{width:optimizeCalcWidth(scope.row),left:optimizeCalcLeft(scope.row)}"                    ></div>                    <div                    v-else-if="index === 0 && index1 === 0 && index2 === 0 && scope.$index % 2 !== 0"                    class="progressDownon"                    :style="{width:optimizeCalcWidth(scope.row),left:optimizeCalcLeft(scope.row)}"                    ></div>                  </div>                  <div v-else>                    <div                    v-if="scope.$index % 2 === 0"                    :class="scope.row.beginTimeStamp <= itm.timestamp && scope.row.endTimeStamp >= itm.timestamp ? 'progressUpon' : '' "                    style="width:calc(100% + 2px)"                    ></div>                    <div v-else                    :class="scope.row.beginTimeStamp <= itm.timestamp && scope.row.endTimeStamp >= itm.timestamp  ? 'progressDownon' : '' "                    style="width:calc(100% + 2px)"                    ></div>                  </div>                        </template>                    </el-table-column>                </el-table-column>            </el-table-column>        </el-table>      </div>        </div></template>

JAVASCRIPT

<script>    export default {        name: 'Barchart',        data() {            return {                showMonths:[],                tableData: [],                minDay:"", // 最小日期                maxDay:"", // 最大日期                IsShowyear:true ,// 显示年|月 、 月|日                rendering:true // 遮罩层            }        },        computed:{      // 获取最小日期-月开始工夫戳      minDayTimeStamp() {        if(this.IsShowyear){          return this.showMonths[0].months[0].beginTimeStamp        }else{          return this.showMonths[0].days[0].daysArr[0].timestamp        }      },      // 获取最大日期工夫戳      maxDayTimeStamp() {        let Length = this.showMonths.length // 年有多少个        // 如果显示年|月 与 月|日 是不同的        if(this.IsShowyear){          let monthsLength = this.showMonths[Length - 1].months.length  //月有多少个          return this.showMonths[Length - 1].months[monthsLength - 1].endTimeStamp        }else{          let daysLength = this.showMonths[Length - 1].days.length          let daysarrLength = this.showMonths[Length - 1].days[daysLength - 1].daysArr.length  //天有多少个          return this.showMonths[Length - 1].days[daysLength - 1].daysArr[daysarrLength - 1].timestamp + 86400000        }      },      // 最大日期与最小日期的工夫戳差      maxAndminDayTimeStamp() {        return this.maxDayTimeStamp - this.minDayTimeStamp      },      // 获取日期单元格宽度 => 如果返回0则只用之前第一版的计算方法      getCellDateWidth() {        let num = 0 // 获取日期单元格数量        if(this.IsShowyear){          // 月数量          for(let i = 0;i < this.showMonths.length;i++){            num += this.showMonths[i].months.length          }        }else{          // 天数量          for(let i = 0;i < this.showMonths.length;i++){            for(let j = 0;j < this.showMonths[i].days.length;j++){              num += this.showMonths[i].days[j].daysArr.length            }          }        }        // 每个单元格最小30宽度        let MaxWidth = window.screen.width        let CellNum = MaxWidth / 30 > 0 ? MaxWidth / 30  : 0        if(num >= CellNum){ // 页面宽 / 单元格最小宽度 = 最多放下的值          return num * 30        }else{          // 单元格的值,就不能是最小值30了          // 须要获取dom的宽度,在进行计算,然而dom还未渲染实现,因而这里就不思考了,间接只用第一版的办法动静计算          return 0        }      }        },        created() {            // 这里能够发送网络申请            this.tableData = [{            "id": 1,            "name": "王小虎2",            "state": "打算工期",            "beginDate": "2016-05-01",            "endDate": "2016-05-30",            "days": "1000"          }, {            "id": 1,            "name": "王小虎3",            "state": "打算工期",            "beginDate": "2016-05-15",            "endDate": "2016-05-22",            "days": "1000"          }, {            "id": 2,            "name": "王小虎3",            "state": "打算工期",            "beginDate": "2016-05-01",            "endDate": "2016-05-20",            "days": "1000"          }, {            "id": 2,            "name": "王小虎3",            "state": "打算工期",            "beginDate": "2016-05-01",            "endDate": "2016-05-20",            "days": "1000"          }, {            "id": 3,            "name": "王小虎3",            "state": "打算工期",            "beginDate": "2016-05-01",            "endDate": "2016-05-02",            "days": "1000"          }, {            "id": 3,            "name": "王小虎3",            "state": "打算工期",            "beginDate": "2016-05-01",            "endDate": "2016-05-02",            "days": "1000"          }, {            "id": 4,            "name": "王小虎3",            "state": "打算工期",            "beginDate": "2016-05-15",            "endDate": "2016-05-22",            "days": "1000"          }, {            "id": 4,            "name": "王小虎3",            "state": "打算工期",            "beginDate": "2016-05-15",            "endDate": "2016-05-22",            "days": "1000"          }, {            "id": 5,            "name": "王小虎3",            "state": "打算工期",            "beginDate": "2016-05-01",            "endDate": "2016-05-20",            "days": "1000"          }, {            "id": 5,            "name": "王小虎3",            "state": "打算工期",            "beginDate": "2016-05-01",            "endDate": "2016-05-20",            "days": "1000"          }, {            "id": 6,            "name": "王小虎3",            "state": "打算工期",            "beginDate": "2016-05-01",            "endDate": "2016-05-02",            "days": "1000"          }, {            "id": 6,            "name": "王小虎3",            "state": "打算工期",            "beginDate": "2016-05-01",            "endDate": "2016-05-02",            "days": "1000"          }, {            "id": 7,            "name": "王小虎3",            "state": "打算工期",            "beginDate": "2016-05-15",            "endDate": "2016-05-22",            "days": "1000"          }, {            "id": 7,            "name": "王小虎3",            "state": "打算工期",            "beginDate": "2016-05-15",            "endDate": "2016-05-22",            "days": "1000"          }, {            "id": 8,            "name": "王小虎3",            "state": "打算工期",            "beginDate": "2016-05-01",            "endDate": "2016-05-20",            "days": "1000"          }, {            "id": 8,            "name": "王小虎3",            "state": "打算工期",            "beginDate": "2016-05-01",            "endDate": "2016-05-20",            "days": "1000"          }, {            "id": 9,            "name": "王小虎3",            "state": "打算工期",            "beginDate": "2016-05-01",            "endDate": "2016-05-02",            "days": "1000"          }, {            "id": 9,            "name": "王小虎3",            "state": "打算工期",            "beginDate": "2016-05-01",            "endDate": "2016-05-02",            "days": "1000"          }]            this.setrowspans() // 设置合并            this.getChartTitle() // 渲染的信息      // 设置右边表格的宽度            this.$nextTick(()=>{        let height = 0        let setHeight = setInterval(()=>{          if(height !== 0){            clearInterval(setHeight)          }else{            if(document.querySelector('.right .el-table__header-wrapper')){              height =  document.querySelector('.right .el-table__header-wrapper').offsetHeight              document.querySelector('.left .el-table__header th').setAttribute('style', 'height: '+height+'px !important')              console.log(height)              setTimeout(()=>{                this.rendering = false              },100)            }          }        },50)      })        },        methods: {      optimizeCalcWidth(val) {       let SumNum = this.maxAndminDayTimeStamp       let diffNum = this.IsShowyear ? val.endTimeStamp - val.beginTimeStamp : val.endTimeStamp + 84600000 - val.beginTimeStamp  // 完结日期 - 开始日期       let rate = Math.round(diffNum / SumNum * 10000) / 100.00 //失去百分比       let widthPx = this.getCellDateWidth * rate / 100.00       return widthPx + 'px'      },      optimizeCalcLeft(val) {        let SumNum = this.maxAndminDayTimeStamp        let diffNum = val.beginTimeStamp - this.minDayTimeStamp // 开始日期 - 整个月开始日期        let rate = Math.round(diffNum / SumNum * 10000) / 100.00 //失去百分比        let leftPx = this.getCellDateWidth * rate / 100.00        return leftPx + 'px'      },      // 计算图表的Left      calcLeft(val,date) {          // 如果本月的最大工夫戳都没有完结工夫长,那么就可判断          if(val.endTimeStamp > date.endTimeStamp){              // 如果本月开始日期小于开始日期              if(val.beginTimeStamp > date.beginTimeStamp){                  // 进行判断                  let diffNum = val.beginTimeStamp - date.beginTimeStamp                  let SumNum = date.endTimeStamp - date.beginTimeStamp                  let rate =  100 - Math.round(diffNum / SumNum * 10000) / 100.00                  // 地位判断                  return rate+"%"              }          }else if(val.endTimeStamp > date.beginTimeStamp && val.endTimeStamp < date.endTimeStamp){                  // 进行判断                  if(val.beginTimeStamp > date.beginTimeStamp){                      // 都在一个单元格中                      let diffNum = val.beginTimeStamp - date.beginTimeStamp                      let SumNum = date.endTimeStamp - date.beginTimeStamp                      let rate =  Math.round(diffNum / SumNum * 10000) / 100.00                      // 地位判断                      return rate+"%"                  }              }          return '0px'      },      // 计算图表的Width      calcwidth(val,date) {          if(this.IsShowyear){              // 如果是 年|月              // 1. 如果本月的最大工夫戳都没有完结工夫长,那么就可设置100%              // 2. 如果本月的最小工夫戳比完结工夫长,那么设置0              // 3. 如果本月的最小工夫戳没有完结工夫长,那么进行判断              if(val.endTimeStamp > date.endTimeStamp){                  // 如果本月开始日期小于开始日期                  if(val.beginTimeStamp > date.beginTimeStamp){                      // 进行判断                      let diffNum = val.beginTimeStamp - date.beginTimeStamp                      let SumNum = date.endTimeStamp - date.beginTimeStamp                      let rate = Math.round(diffNum / SumNum * 10000) / 100.00                      return 'calc('+ rate +'% + 2px)' // 完结工夫超过本月最大工夫戳间接+2px                  }                  return 'calc(100% + 2px)'              }else if(val.endTimeStamp < date.beginTimeStamp){                  return '0px'              }else if(val.endTimeStamp > date.beginTimeStamp && val.endTimeStamp < date.endTimeStamp){                  // 进行判断                  if(val.beginTimeStamp > date.beginTimeStamp){                      // 都在一个单元格中                      let SumNum = date.endTimeStamp - date.beginTimeStamp // 全月多多数                      let diffNum = val.endTimeStamp - val.beginTimeStamp // 过程多多数                      diffNum = diffNum === 0 ?  86400000 : diffNum                      let rate = Math.round(diffNum / SumNum * 10000) / 100.00                      return 'calc('+ rate +'%)'                  }else{                      // 不在一个单元格中,则不须要判断任何信息                      let diffNum = val.endTimeStamp - date.beginTimeStamp                      let SumNum = date.endTimeStamp - date.beginTimeStamp                      let rate = Math.round(diffNum / SumNum * 10000) / 100.00                      return 'calc('+ rate +'%)'                  }              }          }else{              // 如果是 月|日              // 1.如果开始工夫大于 天的工夫戳,则为0              // 2.如果完结工夫小于 天的工夫戳,则为100%              if(val.beginTimeStamp > date.timestamp){                  return '0px'              }else if(val.beginTimeStamp < date.timestamp && val.endTimeStamp > date.timestamp){                  return 'calc(100% + 2px)'              }          }          return '0px'      },            //取得数据雷同的行数            objectSpanMethod({ row, column, rowIndex, columnIndex }) {                if (columnIndex === 0) {                    return {                        rowspan: row.rowspan,                        colspan: 1                    };                }            },            setrowspans() {                // 先给所有的数据都加一个v.rowspan = 1                this.tableData.forEach(v => {                    v.rowspan = 1;                });                // 双层循环                for (let i = 0; i < this.tableData.length; i++) {                    // 内层循环,下面曾经给所有的行都加了v.rowspan = 1                    // 这里进行判断                    // 如果以后行的id和下一行的id相等                    // 就把以后v.rowspan + 1                    // 下一行的v.rowspan - 1                    for (let j = i + 1; j < this.tableData.length; j++) {                        //此处可依据雷同字段进行合并,此处是依据的id                        if (this.tableData[i].id === this.tableData[j].id) {                            this.tableData[i].rowspan++;                            this.tableData[j].rowspan--;                        }                    }                    // 这里跳过曾经反复的数据                    i = i + this.tableData[i].rowspan - 1;                }            },            // objectSpanMethod({ row, column, rowIndex, columnIndex }) {            //     if (columnIndex === 0) {            //         if (rowIndex % 2 === 0) {            //             return {            //                 rowspan: 2,            //                 colspan: 1            //             };            //         } else {            //             return {            //                 rowspan: 0,            //                 colspan: 0            //             };            //         }            //     }            // },            // 渲染表格头,首先是年月,如2018年11月            getChartTitle(startDate, endDate){                var chartTable = this.tableData;                // 筹备日期,为了避免屡次赋值属性,导致计算属性从新计算,决定只赋值一次        let maxDayParams = "",minDayParams = ""                for(var i = 0; i < chartTable.length; i++){                    var StartDate = chartTable[i].beginDate;                    var EndDate = chartTable[i].endDate;                    var mainObj = chartTable[i];                    // 打算日期                    maxDayParams === "" ? maxDayParams = EndDate : ''                    minDayParams === "" ? minDayParams = StartDate : ""                    maxDayParams = this.compareDate(EndDate,maxDayParams,true)                    minDayParams = this.compareDate(StartDate,minDayParams,false)                    var days = this.GetNumberOfDays(StartDate,EndDate) // 计算工期                    this.tableData[i].days = days + 1 // 加一是因为没算结算当天                    // 记录时间戳                    this.tableData[i].beginTimeStamp = this.getTimeStamp(StartDate)                    this.tableData[i].endTimeStamp = this.getTimeStamp(EndDate)                }        this.minDay = minDayParams        this.maxDay = maxDayParams                console.log("小:"+this.minDay)                console.log("大:"+this.maxDay)                this.getYearArr()                console.log(this.showMonths)            },            // 获取须要的格局的年月日信息            getYearArr(){                // 如果有一个日期相差超过366天,依照年,不超过则按天                var days = this.GetNumberOfDays(this.minDay,this.maxDay)                if(days >= 365){                    //须要记录月份                    this.IsShowyear = true                }else{                    //须要记录天数                    this.IsShowyear = false                }                // 获取须要格局的年月信息                let yearArr = []; // 存年                let minYear = new Date(this.minDay).getFullYear();                let maxYear = new Date(this.maxDay).getFullYear();                // 保留年                if(minYear === maxYear){                    yearArr.push({                        year: minYear+"",                        months: [],        // 放月的数组                        days: []                    })                }else{                    for(let i = minYear;i <= maxYear;i++){                        yearArr.push({                            year: i+"",                            months: [],        // 放月的数组                            days: []                        })                    }                }                // 保留月                for(let i = 0;i < yearArr.length;i++){                    let minMonth = 1                    if(i === 0){                        minMonth = new Date(this.minDay).getMonth() + 1;                    }                    // 1.eg:2016年9月 至 2019年01月                    // 2.如果只有一个年,那么月份就是最小月到最大月                    if(yearArr.length > 1){                        // 如果是最初一年,那么就要判断是否到最初一个月                        if(yearArr.length - 1 === i){                            let maxMonth = new Date(this.maxDay).getMonth() + 1;                            let _maxDay = new Date(this.maxDay).getDate() // 最大日期 天数                            let j = 1                            while(j <= maxMonth){                                let monthsDays = this.getLastDay(yearArr[i].year, j); // 获取月份一共有多少天                                let timestampstr = this.getTimeStamp(yearArr[i].year +"-"+  (j > 9 ? j : '0'+j) + "-" + monthsDays)                                let timestampstr1 = this.getTimeStamp(yearArr[i].year +"-"+  (j > 9 ? j : '0'+j) + "-01")                                yearArr[i].months.push({str:j+"月",num:j,endTimeStamp:timestampstr,beginTimeStamp:timestampstr1});// 记录最大最小的工夫戳                                // 如果显示月|天 才用记录天                                if(!this.IsShowyear){                                    yearArr[i].days[yearArr[i].days.length] = {year: "",month: "",daysArr: {}}                                    yearArr[i].days[yearArr[i].days.length - 1].year = yearArr[i].year    // 赋值年                                    yearArr[i].days[yearArr[i].days.length - 1].month = j;    // 赋值月                                    yearArr[i].days[yearArr[i].days.length - 1].daysArr = []                                    // 如果完结月,不是到本月最初一天,而是截止到最                                    if(j === maxMonth){                                        monthsDays = _maxDay                                    }                                    for(let k = 1; k <= monthsDays; k++){                                        timestampstr = this.getTimeStamp(yearArr[i].year +"-"+  (j > 9 ? j : '0'+j) + "-" + (k > 9 ? k : '0'+k))                                        yearArr[i].days[yearArr[i].days.length - 1].daysArr.push({day: k+"",timestamp:timestampstr});// 赋值天                                    }                                }                                j++                            }                        }else{                            if(i === 0){                                let j = minMonth                                let _minDay = new Date(this.minDay).getDate() // 最小日期 天数                                while(j <= 12){                                    let monthsDays = this.getLastDay(yearArr[i].year, j); // 获取月份一共有多少天                                    let timestampstr = this.getTimeStamp(yearArr[i].year +"-"+  (j > 9 ? j : '0'+j) + "-" + monthsDays)                                    let timestampstr1 = this.getTimeStamp(yearArr[i].year +"-"+  (j > 9 ? j : '0'+j) + "-01")                                    yearArr[i].months.push({str:j+"月",num:j,endTimeStamp:timestampstr,beginTimeStamp:timestampstr1});// 记录最大最小的工夫戳                                    // 如果显示月|天 才用记录天                                    if(!this.IsShowyear){                                        yearArr[i].days[yearArr[i].days.length] = {year: "",month: "",daysArr: {}}                                        yearArr[i].days[yearArr[i].days.length - 1].year = yearArr[i].year    // 赋值月                                        yearArr[i].days[yearArr[i].days.length - 1].month = j     // 赋值月                                        yearArr[i].days[yearArr[i].days.length - 1].daysArr = []                                        for(let k = 1; k <= monthsDays; k++){                                            // 如果开始月,就不从1日开始,而是从最开始的日期那天开始算起                                            if(k === 1 && j === minMonth){                                                k = _minDay                                            }                                            timestampstr = this.getTimeStamp(yearArr[i].year +"-"+  (j > 9 ? j : '0'+j) + "-" + (k > 9 ? k : '0'+k))                                            yearArr[i].days[yearArr[i].days.length - 1].daysArr.push({day: k+"",timestamp:timestampstr});// 赋值天                                        }                                    }                                    j++                                }                            }else{                                let j = 1                                while(j <= 12){                                    let monthsDays = this.getLastDay(yearArr[i].year, j); // 获取月份一共有多少天                                    let timestampstr = this.getTimeStamp(yearArr[i].year +"-"+  (j > 9 ? j : '0'+j) + "-" + monthsDays)                                    let timestampstr1 = this.getTimeStamp(yearArr[i].year +"-"+  (j > 9 ? j : '0'+j) + "-01")                                    yearArr[i].months.push({str:j+"月",num:j,endTimeStamp:timestampstr,beginTimeStamp:timestampstr1});// 记录最大最小的工夫戳                                    // 如果显示月|天 才用记录天                                    if(!this.IsShowyear){                                        yearArr[i].days[yearArr[i].days.length] = {year: "",month: "",daysArr: {}}                                        yearArr[i].days[yearArr[i].days.length - 1].year = yearArr[i].year    // 赋值年                                        yearArr[i].days[yearArr[i].days.length - 1].month = j // 赋值月                                        yearArr[i].days[yearArr[i].days.length - 1].daysArr = []                                        for(let k = 1; k <= monthsDays; k++){                                            timestampstr = this.getTimeStamp(yearArr[i].year +"-"+  (j > 9 ? j : '0'+j) + "-" + (k > 9 ? k : '0'+k))                                            yearArr[i].days[yearArr[i].days.length - 1].daysArr.push({day: k+"",timestamp:timestampstr});// 赋值天                                        }                                    }                                    j++                                }                            }                        }                    }else{                        // 如果只有一年那么没有必要判断是否记录天                        let maxMonth = new Date(this.maxDay).getMonth() + 1;                        let _minMonth = minMonth                        let _minDay = new Date(this.minDay).getDate() // 最小日期 天数                        let _maxDay = new Date(this.maxDay).getDate() // 最大日期 天数                        while(_minMonth <= maxMonth){                            let monthsDays = this.getLastDay(yearArr[i].year, _minMonth); // 获取月份一共有多少天                            let timestampstr = this.getTimeStamp(yearArr[i].year +"-"+  (_minMonth > 9 ? _minMonth : '0'+_minMonth) + "-" + monthsDays)                            let timestampstr1 = this.getTimeStamp(yearArr[i].year +"-"+  (_minMonth > 9 ? _minMonth : '0'+_minMonth) + "-01")                            yearArr[i].months.push({str:_minMonth+"月",num:_minMonth,endTimeStamp:timestampstr,beginTimeStamp:timestampstr1});// 记录最大最小的工夫戳                            yearArr[i].days[yearArr[i].days.length] = {year: "",month: "",daysArr: {}}                            yearArr[i].days[yearArr[i].days.length - 1].year = yearArr[i].year     // 赋值月                            yearArr[i].days[yearArr[i].days.length - 1].month = _minMonth    // 赋值月                            yearArr[i].days[yearArr[i].days.length - 1].daysArr = []                            // 如果完结月,不是到本月最初一天,而是截止到最                            if(_minMonth === maxMonth){                                monthsDays = _maxDay                            }                            for(let k = 1; k <= monthsDays; k++){                                // 如果开始月,就不从1日开始,而是从最开始的日期那天开始算起                                if(k === 1 && _minMonth === minMonth){                                    k = _minDay                                }                                timestampstr = this.getTimeStamp(yearArr[i].year +"-"+  (_minMonth > 9 ? _minMonth : '0'+_minMonth) + "-" + (k > 9 ? k : '0'+k))                                yearArr[i].days[yearArr[i].days.length - 1].daysArr.push({day: k+"",timestamp:timestampstr});// 赋值天                            }                            _minMonth++                        }                    }                }                this.showMonths = yearArr            },            // 获取月的最初一天            getLastDay(myyear, mymonth){                var new_date = new Date(myyear, mymonth, 0);                return new_date.getDate();            },            // 取得天数            GetNumberOfDays(date1,date2){                //date1:开始日期,date2完结日期                var a1 = Date.parse(new Date(date1));                var a2 = Date.parse(new Date(date2));                var day = parseInt((a2-a1)/ 86400000);//外围:工夫戳相减,而后除以天数                return day            },            // 工夫比拟 true 比大            compareDate(dateTime1,dateTime2,condition = true)            {                var formatDate1 = new Date(dateTime1)                var formatDate2 = new Date(dateTime2)                if(formatDate1 >= formatDate2)                {                    return condition ? dateTime1 : dateTime2                }                else                {                    return condition ? dateTime2 : dateTime1                }            },            getTimeStamp(val){                return new Date(val).getTime()            },        }    }</script>

CSS

<style>/* 边框宽度 */.barchart .el-table--border td,.barchart .el-table--border th {        border-width: 2px;    }  /* 单元格padding */  .barchart .el-table--border th:first-child .cell, .el-table--border td:first-child .cell{    padding: 0px;  }    .barchart .el-table th > .cell{        padding: 0px;    }    /* 单元格高度 */    .barchart .el-table--medium th,.barchart  .el-table--medium td {        padding: 0px 0px !important;            height: 25px !important;    }    .barchart .progressUpon{        background: rgb(38, 84, 124);        height: 1em;        /* width: calc(100% + 2px); */        z-index: 2;        position: absolute;        top: 25%;        left:0px    }    .barchart .progressDownon{        background: rgb(255,209,102);        height: 1em;        /* width: calc(100% + 1px); */        z-index: 2;        position: absolute;        top: 25%;        left:0px    }  /* 布局盒子 这样使得固定列与右侧图表离开 */ .barchart{    display: flex;    flex-direction: row;    flex-wrap: nowrap;    align-items: stretch;  }  .barchart .el-table  th {    background: #F5F7FA;  }  .barchart .left{    max-width: 20%;  }  .barchart .right{    min-width: 80%;  }</style>

发现:

当应用element 表格的fixed,会把表格绘制两份,导致有些计算方法反复执行。

测试

月|日
2016-05-15至2017-01-30工时为275天,大概渲染耗时:3s
2016-05-15至2017-10-30工时为183天,大概渲染耗时:2s
2016-05-15至2017-07-30工时为91天,大概渲染耗时:1.5s
2016-05-01至2016-07-30工时为16天,大概渲染耗时:1s

年|月
2016-05-01至2017-07-30工时为395天,大概渲染耗时:1s
2016-05-01至2017-12-30工时为609天,大概渲染耗时:1s
2016-05-01至2018-12-30工时为974天,大概渲染耗时:1s
2016-05-01至2019-12-30工时为1339天,大概渲染耗时:1.5s
2016-05-01至2020-12-30工时为1705天,大概渲染耗时:1.5s
2016-05-01至2021-12-30工时为2070天,大概渲染耗时:1.5s
2016-05-01至2022-12-30工时为2435天,大概渲染耗时:1.5s
2016-05-01至2025-12-30工时为2435天,大概渲染耗时:2s
2016-05-01至2026-12-30工时为2435天,大概渲染耗时:2.5s