【Vue.JS】纯 Vue.js 制作甘特图

效果图

img1

在线预览

GitHub链接(包含 knockoutJS 版本与 Vue 版本)

推荐组合效果

  • 推荐与双表头固定效果组合,实现如上例中横表头(日期)纵向固定,纵表头(类型)横向固定效果。
  • 参照连接 表头固定,表身滚动实例

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>
    /**
     * 日期格式化。
     * 小于 10 的数字在前面 + 0。如 01、06
     * */
    var fDate = function (value) {
        return value < 10 ? '0' + value : value;
    }
    /**
     * 日期格式化:yyyy-mm-dd
     * */
    Date.prototype.format = function () {
        return this.getFullYear() + '-' + fDate(this.getMonth() + 1) + '-' + fDate(this.getDate());
    };

    /**
     * 获取指定时间段内所有天。
     * 输入起止日期。格式:yyyy-mm-dd。
     * 返回格式:yyyy-mm-dd
     * */
    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]); //start
        var uDe = new Date().setUTCFullYear(b[0], b[1] - 1, b[2]); //end
        for (var i = uDb; i <= uDe; i = i + 24 * 60 * 60 * 1000) {
            allDays.push(new Date(parseInt(i)).format());
        }
        return allDays;
    };
    /**
     * 获取指定时间段内所有月。
     * 输入起止日期。格式:yyyy-mm-dd。
     * 返回格式:yyyy-mm
     * */
    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]); //start
        var uDe = new Date().setUTCFullYear(b[0], b[1] - 1, new Date(b[0], b[1], 0).getDate()); //结束月份设置为指定月最后一天
        while (uDb <= uDe) { // 等于号防止 31 号计算遗漏
            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>
    /**
     * 创建 Vue 实例
     * */
    var demo = new Vue({
        el: '#demo',
        data: {
            /**
             * 数据源 JSON 对象数组
             * 格式:
             * {
             *  startDate:'',        //开始日期(表头所用)
             *  endDate:''           //结束日期(表头所用)
             *  data:[{
             *      formType:'',        //数据类型1。可自动进行行合并
             *      type:'',            //数据类型2。如需行合并需参照类型1自行优化
             *      value:[{            //甘特图所需数据
             *              fromDate:'',    //开始时间
             *              toDate:'',      //截止时间
             *              spanClass:''    //该段时间内的样式
             *          },{
             *              //允许有多组时间段。
             *          }]
             *      }]
             *  }
             * 
             * */
            jsonData: sourceData.data,
            startDate: sourceData.startDate,
            endDate: sourceData.endDate,
            /*获取指定时间段内所有月,用作表头一*/
            AllMonths: getAllMonth(sourceData.startDate, sourceData.endDate),
            /*获取指定时间段内所有天,用作表头二*/
            Dateinterval: getAllDay(sourceData.startDate, sourceData.endDate),
        },
        methods: {
            /**
             * 甘特图显示状况
             * 传入参数:
             *      1、甘特图所需数据数组。即上述 JSON 对象的 value 数组
             *      2、当前日期,即此刻对应表头中的日期列。
             *  */
            spanShow: function (valArray, currentDate) {
                /*默认不显示*/
                var show = false;
                /*默认样式颜色为空*/
                var color = "";
                /*调用 Vue 过滤器*/
                var filter = this.$options.filters['strDateToTimeStamp'];
                /*循环 value 数据。判断当前对应日期是否位于该组 value 数据的 fromdate 与 todate 之间。*/
                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
                };
            },
            /**
             * 计算指定时间段内指定月份的总天数。
             * 这里需要根据指定月的总天数确定合并表头一时跨列的数量
             * 传入参数:指定月份。格式 yyyy-mm
             * */
            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;
                }
                //指定月份等于开始时间段的月份时,返回本月剩余天数 = 本月最后一天 - 开始日期 + 1
                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;
            }
        },
        /*Vue 过滤器用于格式化日期*/
        filters: {
            /*字符串格式的日期转为时间戳*/
            strDateToTimeStamp: function (strDate) {
                return Date.parse(strDate);
            },
            /*字符串格式的日期转为天。yyyy-mm-dd  -->  dd*/
            longDateToDay: function (longDate) {
                return fDate(new Date(Date.parse(longDate)).getDate());
            },
            /*字符串格式的日期转为月。yyyy-mm-dd  -->  mm*/
            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>
  • 5
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论
如果你想使用 Vue.js 来创建一个甘特图,并且希望代码整洁、注释全面,以及形成简单清爽的效果,我建议你按照以下步骤进行: 1. 创建一个新的 Vue.js 项目:首先,你需要创建一个新的 Vue.js 项目。你可以使用 Vue CLI 来方便地创建一个基础的 Vue 项目。运行以下命令来安装 Vue CLI 并创建新项目: ``` npm install -g @vue/cli vue create gantt-chart-project ``` 然后按照提示进行选择配置,选择你喜欢的特性和插件。 2. 安装甘特图库:接下来,你需要选择一个适合的甘特图库来实现你的需求。一些常见的甘特图库包括 `vue-gantt-chart`、`frappe-gantt` 等。你可以通过运行以下命令来安装其中一个库: ``` npm install vue-gantt-chart ``` 3. 创建甘特图组件:在 Vue 项目中,你可以创建一个单独的组件来显示甘特图。在你的项目中创建一个新的组件文件 `GanttChart.vue`,并在其中引入甘特图库。然后,根据甘特图库的文档,使用合适的 API 来渲染甘特图。 在编写代码时,确保你的代码整洁、模块化,并且添加适当的注释来解释你的代码逻辑和功能。 4. 调整样式:根据你的需求,调整甘特图的样式以达到简单清爽的效果。你可以使用 CSS 或者甘特图库提供的自定义选项来修改样式。 5. 测试和优化:完成甘特图的初始化后,进行测试并确保它能够按照预期工作。如有必要,进行性能优化或者添加额外的功能。 最后,记得在你的项目中保持良好的代码结构和注释习惯,这有助于代码的可维护性和可读性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

◣NSD◥

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值