vue3 手写表格甘特图公用组件

vue3 手写表格甘特图

最近前端开发中遇到一个需求,需要绘制一个甘特图,但是我找了很多组件,发现没有符合自己需求的,没办法,那就只有手写一个了

先来一张效果图如下
在这里插入图片描述
怎么样,这效果图看起来还不错吧,下面就给大家展示一下代码是如何实现的,其实实现起来很简单,主要还是要耐心慢慢调试

这是我使用我的组件时的代码

代码看起来多,其实就是一个data数据而已 ,这个data数据需要自己加工处理成这样

<template>
    <div style="padding:100px;width:80%;">
        <GanttChart :data="data"></GanttChart>
    </div>
</template>
  
<script lang="ts" setup>
import { reactive, ref } from 'vue'
import GanttChart from '@/components/ganttChart/index.vue'


let data = ref({
    data: [
    {
            title: '1级标题',
            children:
                [
                    {
                        subTitle: '',
                        children: [
                            [
                                {
                                    width: '50%', // 这是占一个列宽度的百分比
                                    left: '150%', // 这是从第一列起,向右移动第一列宽度的百分比
                                    name: '肿瘤、心脑血管疾病、遗传病等许多复杂疾病及慢性病仍缺乏有效治疗方法'  // 这个就是我们展示的文字了
                                },
                                {
                                    width: '100%',
                                    left: '200%',
                                    name: '肿瘤、心脑血管疾病、遗传病等许多复杂疾病及慢性病仍缺乏有效治疗方法'
                                },
                            ],
                            [
                                {
                                    width: '100%',
                                    left: '0%',
                                    name: '肿瘤、心脑血管疾病、遗传病等许多复杂疾病及慢...'
                                },
                                {
                                    width: '100%',
                                    left: '100%',
                                    name: '肿瘤、心脑血管疾病、遗传病等许多复杂疾病及慢性病仍缺乏rewqtr'
                                },
                                {
                                    width: '100%',
                                    left: '200%',
                                    name: '肿瘤、心脑血管疾病、遗传病等许多复杂疾病及慢性rweqrwqe'
                                },
                            ]

                        ]

                    },
                   
                ]
        },
        {
            title: '1级标题',
            children:
                [
                    {
                        subTitle: '二级标题',
                        children: [
                            [
                                {
                                    width: '50%',
                                    left: '150%',
                                    name: '肿瘤、心脑血管疾病、遗传病等许多复杂疾病及慢性病仍缺乏有效治疗方法'
                                },
                                {
                                    width: '100%',
                                    left: '0%',
                                    name: '肿瘤、心脑血管疾病、遗传病等许多复杂疾病及慢性病仍缺乏有效治疗方法'
                                },
                            ],
                            [
                                {
                                    width: '100%',
                                    left: '0%',
                                    name: '肿瘤、心脑血管疾病、遗传病等许多复杂疾病及慢...'
                                },
                                {
                                    width: '100%',
                                    left: '100%',
                                    name: '肿瘤、心脑血管疾病、遗传病等许多复杂疾病及慢性病仍缺乏rewqtr'
                                },
                                {
                                    width: '100%',
                                    left: '200%',
                                    name: '肿瘤、心脑血管疾病、遗传病等许多复杂疾病及慢性rweqrwqe'
                                },
                            ]

                        ]

                    },
                    {
                        subTitle: '222二级标题',
                        children: [
                            [
                                {
                                    width: '100%',
                                    left: '50%',
                                    name: '肿瘤、心脑血管疾病、遗传病等许多复杂疾病及慢性病仍缺乏有效治疗方法'
                                },
                                {
                                    width: '100%',
                                    left: '200%',
                                    name: '肿瘤、心脑血管疾病、遗传病等许多复杂疾病及慢性病...'
                                },
                                {
                                    width: '100%',
                                    left: '200%',
                                    name: '肿瘤、心脑血管疾病、遗传病等许多复杂疾病及慢性病仍缺乏有效治疗方法'
                                },
                            ],
                            [
                                {
                                    width: '100%',
                                    left: '50%',
                                    name: '肿瘤、心脑血管疾病、遗传病等许多复杂疾病及慢性病仍缺乏有效治疗方法'
                                },
                                {
                                    width: '100%',
                                    left: '200%',
                                    name: '肿瘤、心脑血管疾病、遗传病等许多复杂疾病及慢性病仍缺乏有效治疗方法'
                                },
                            ]

                        ]

                    },
                ]
        }
        ,
        {
            title: '11111级标题',
            children:
                [
                    {
                        subTitle: '二级标题',
                        children: [
                            [
                                {
                                    width: '50%',
                                    left: '0%',
                                    name: '肿瘤、心脑血管疾病、遗传病等许多复杂疾病及慢性病仍缺乏有效治疗方法'
                                },
                                {
                                    width: '50%',
                                    left: '50%',
                                    name: '肿瘤、心脑血管疾病、遗传病等许多复杂疾病及慢性病仍缺乏有效治疗方法'
                                },
                                {
                                    width: '50%',
                                    left: '100%',
                                    name: '肿瘤、心脑血管疾病、遗传病等许多复杂疾病及慢性病仍缺乏有效治疗方法'
                                },
                                {
                                    width: '50%',
                                    left: '150%',
                                    name: '肿瘤、心脑血管疾病、遗传病等许多复杂疾病及慢性病仍缺乏有效治疗方法'
                                },
                                {
                                    width: '50%',
                                    left: '200%',
                                    name: '肿瘤、心脑血管疾病、遗传病等许多复杂疾病及慢性病仍缺乏有效治疗方法'
                                },
                                {
                                    width: '50%',
                                    left: '250%',
                                    name: '肿瘤、心脑血管疾病、遗传病等许多复杂疾病及慢性病仍缺乏有效治疗方法'
                                },
                            ],
                            [
                                {
                                    width: '100%',
                                    left: '50%',
                                    name: '肿瘤、心脑血管疾病、遗传病等许多复杂疾病及慢性病仍缺乏有效治疗方法'
                                },
                                {
                                    width: '100%',
                                    left: '200%',
                                    name: '肿瘤、心脑血管疾病、遗传病等许多复杂疾病及慢性病仍缺乏有效治疗方法'
                                },
                            ]

                        ]

                    },
                    {
                        subTitle: '222二级标题',
                        children: [
                            [
                                {
                                    width: '100%',
                                    left: '50%',
                                    name: '肿瘤、心脑血管疾病、遗传病等许多复杂疾病及慢性病仍缺乏有效治疗方法'
                                },
                                {
                                    width: '60%',
                                    left: '200%',
                                    name: '肿瘤、心脑血管疾病、遗传病等...'
                                },
                            ],
                            [
                                {
                                    width: '20%',
                                    left: '30%',
                                    name: '肿瘤、心脑血管疾病、212312'
                                },
                                {
                                    width: '100%',
                                    left: '200%',
                                    name: '肿瘤、心脑血管疾病、遗传病等许多复杂4231'
                                },
                                {
                                    width: '60%',
                                    left: '100%',
                                    name: '肿瘤、心脑血管疾病、遗传病等许多复杂gerg'
                                },
                            ]

                        ]

                    },
                ]
        }

        ,

    ]
    ,
    title: [
        '2017-2020',
        '2021-2025',
        '2026-2030'
    ]
})

</script>
<style lang="less">

</style>
  

下面是封装的组件了

  • 这是封装的GanttChart.vue 文件的代码,此组件其实就是用css+html+javascript实现的,只要掌握了传参的数据格式就很容易理解
<template>
    <div class="ganttChartClass">
        <!-- 顶部标题 -->
        <div class="topTitle">
            <div style="position:relative" :style="{ width: leftTitleWidth + 'px' }">
                <div style="font-size: 12px;margin-left:58px;margin-top:-10px;">年份</div>
                <div class="diagonalLine"></div>
                <div style="font-size: 12px;margin-left:-54px;margin-top:-30px;">项目</div>
            </div>
            <div v-for="(item, i) in props.data.title" :key="i"
                :style="{ width: 'calc(' + '( 100% - ' + leftTitleWidth + 'px)' + ' * (1 / ' + props.data.title.length + ')' + ')' }">
                {{ item }}</div>
        </div>
        <div v-for="(item, i) in props.data.data" :key="i" class="content">
            <!-- 左侧标题 -->
            <div :style="{ width: leftTitleWidth + 'px' }" class="leftTitle">
                <!-- 只有一级题目 -->
                <!-- <div>
                    {{ item.title }}
                </div> -->
                <div style="display:flex;width:100%;height:100%;text-align: center;">
                    <!-- 一级题目 -->
                    <div style="display: flex;justify-content: center;align-items: center;font-size: 16px;"
                        :style="{ width: item.children[0].subTitle === '' ? '100%' : '40%', paddingRight: item.children[0].subTitle === '' ? '10px' : '0px' }"
                        class="firstTitleArea">
                        <div style="display:inline-block;text-align:left;">
                            {{ item.title }}
                        </div>
                    </div>

                </div>
            </div>
            <div
                :style="{ width: 'calc(' + '( 100% - ' + leftTitleWidth + 'px)' + ' * (1 / ' + props.data.title.length + ')' + ')' }">
                <!-- {{item}} -->
                <!-- <div style="height:100%;width:20px;background:red;position: relative;z-index:20;">
                </div> -->
                <div v-for="(item2, i2) in item.children" :key="i2"
                    style="width:100%;display: flex;justify-content: flex-start;">


                    <!-- 二级标题展示 -->
                    <div style="width:0px;">
                        <div style="width:84px;height:100%;position:relative;left:-84px;align-items: center;justify-content: center;padding:0 5px; color: #585D79;font-size: 14px;font-weight:600;"
                            :style="{ borderTop: (0 === i2) ? 'none' : '1px solid #FFE1C5',display:item2.subTitle===''?'none':'flex' }" >
                            {{ item2.subTitle }}
                        </div>
                    </div>

                    <div style="width:100%;">
                        <div v-for="(item3, i3) in  item2.children" :key="i3" class="lineRow"
                            style="display:flex;width:100%;">
                            <div v-for="(ele2, index2) in item3" :key="index2" style="width:100%;flex-shrink:0">

                                <!-- 这行是占位 -->
                                <div :style="{ width: 'calc(' + ele2.width + ' - 1px)', background: lineDrawArr[index2 % 4] }"
                                    style="height:100%;position: relative;visibility: hidden;" class="lineDraw">
                                    {{ ele2.name }}
                                </div>


                                <!-- 这行才是真正显示 -->
                                <div :style="{ width: 'calc(' + ele2.width + ' - 1px)', left: ele2.left, background: lineDrawArr[index2 % 4] }"
                                    style="display:flex;align-items:center;justify-content:center;" class="lineDraw">
                                    <div style="text-align:left;display: inline-block;">
                                        {{ ele2.name }}
                                    </div>
                                </div>

                            </div>

                            <div></div>

                        </div>
                    </div>

                    <div></div>

                </div>
                <div></div>
            </div>
            <div v-for="item5 in props.data.title.length - 1"
                :style="{ width: 'calc(' + '( 100% - ' + leftTitleWidth + 'px)' + ' * (1 / ' + props.data.title.length + ')' + ')' }">
            </div>
        </div>
    </div>
</template>
    
<script setup lang='ts'>
import { ref } from 'vue'
let props = defineProps<{ data: any }>()


let leftTitleWidth = ref(150)

let lineDrawArr = ['#E4EFFF', '#F3F37E', '#FFDED7', '#CBEEEA']
</script>
    
<style lang="less" scoped>
@bg: #FEF9F3;
@borderColor: #FFE1C5;

.ganttChartClass {
    box-sizing: border-box;
    overflow: hidden;
    border: 1px solid @borderColor;
    border-right: 0px;

    .content {
        display: flex;
        flex-wrap: wrap;

        border-top: 1px dashed @borderColor;

        &:nth-child(2) {
            border-top: 1px solid @borderColor;
        }


        .leftTitle {
            display: flex;
            align-items: center;
            justify-content: center;
            font-weight: 600;
            padding: 10px;
            padding-right: 0px;
            background: @bg;
            color: #252631;

            .firstTitleArea {
                position: relative;

                &:after {

                    display: block;
                    content: '';
                    height: calc(100% + 20px);
                    width: 1px;
                    background: @borderColor;
                    position: absolute;
                    right: 0;
                }
            }
        }


        &>div {
            position: relative;

            // border-right: 1px solid blue;
            &::after {
                display: block;
                content: '';
                position: absolute;
                height: 100%;
                width: 1px;
                background: @borderColor;
                right: 0;
                top: 0;
            }

            .lineRow {
                // height: 30px;
                margin-top: 10px;
                margin-bottom: 10px;
                position: relative;


                .lineDraw {
                    text-align: center;
                    // line-height: 30px;
                    z-index: 5;
                    position: absolute;
                    padding: 5px 20px;
                    top: 0;
                    height: 100%;



                    .lineDrawText {
                        text-overflow: ellipsis;
                        overflow: hidden;
                        white-space: nowrap;

                        color: #585D79;
                        font-size: 14px;

                        &:hover {
                            cursor: pointer;
                        }
                    }
                }
            }

        }
    }

    .topTitle {
        display: flex;
        flex-wrap: wrap;
        background: @bg;
        color: #CE8D51;


        &>div {
            display: inline-block;
            text-align: center;
            border-right: 1px solid @borderColor;
            height: 50px;
            line-height: 50px;
            overflow: hidden;


            .diagonalLine {
                width: 200px;
                border-bottom: 1px solid @borderColor;
                transform: rotate(17.9deg);
                transform-origin: 0 0;
                position: absolute;
                z-index: 5;
                top: 0;
                left: 0;
            }
        }
    }

    div {
        box-sizing: border-box;
    }
}
</style>

好了,代码就是这样了,是不是看起来也很简单呢

创作分享不易,如果对你有帮助,点赞收藏鼓励一下吧!

  • 5
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值