基于Ant Design of Vue的粗糙组件封装-左右分栏

原型

原型图

注意:上面原型图中缺少缩放按钮的设计

要求

  1. 左右分栏统一使用间距16px进行分割。
  2. 左侧栏目是否可以收缩由项目自行决定。
  3. 左侧栏目默认宽度280px,右侧栏宽度自适应。
  4. 左侧分栏的缩放按钮可使用纯图标按钮。

分析

1、由于当前组件是一个布局组件,而且是左右横向布局的组件,所以选用antd组件中的Grid 栅格布局组件

2、左右部分的内容都是有head和body部分,所以可以选用antd组件中最常用的Card 卡片组件,这样组件内的间距也可以默认使用,不用在自定义样式

代码实现

<!--
 * @description GHorizontalColumns.vue 横向左右分栏布局
 * @author JUN - 2023/8/10 10:06
-->
<template>
    <a-row type="flex" justify="space-between" align="top" :gutter="gutter" class="h-full">
        <!--左边部分-->
        <a-col :flex="isShrinkSwitch?'0px':'280px'"
               class="h-full"
               :style="{left:isShrinkSwitch?`-${this.paddingLeft}`:0}">
            <a-card v-show="!isShrinkSwitch"
                    :bordered="bordered"
                    :head-style="getLeftHeadStyle"
                    :style="{backgroundColor: this.bgColor}"
                    :body-style="getLeftBodyStyle"
                    class="h-full shadow-md shadow-black">
                <div slot="title">
                    <slot name="leftTitle">{{ leftTitle }}</slot>
                </div>

                <div slot="extra">
                    <slot name="leftExtra">{{ leftExtra }}</slot>
                </div>

                <div>
                    <slot name="leftContent"></slot>
                </div>
            </a-card>

            <!--伸缩操纵杆-->
            <div v-if="isVisibleSwitchHandler"
                 @click.prevent="onTriggerSwitchHandler()"
                 class="z-10 absolute top-20 -right-10">
                <slot name="switchHandler" v-bind="{isShrinkSwitch}">
                    <img :src="activeSwitchHandlerIcon" width="48px" height="136px">
                </slot>
            </div>
        </a-col>

        <!--右边部分-->
        <a-col flex="auto" class="h-full w-0">
            <a-card :bordered="bordered"
                    :head-style="getRightHeadStyle"
                    :style="{backgroundColor: this.bgColor}"
                    :body-style="getRightBodyStyle"
                    class="h-full shadow-md">
                <div slot="title">
                    <slot name="rightTitle">{{ rightTitle }}</slot>
                </div>

                <div slot="extra">
                    <slot name="rightExtra">{{ rightExtra }}</slot>
                </div>

                <div>
                    <slot name="rightContent"></slot>
                </div>
            </a-card>
        </a-col>
    </a-row>
</template>
<script lang="ts">
import { Vue, Component, Prop } from 'vue-property-decorator';

@Component({ name: 'GHorizontalColumns' })
export default class GHorizontalColumns extends Vue {
    /* 左边部分的title */
    @Prop({
        type: String,
        default: '左边栏标题slot'
    }) leftTitle: string | undefined;

    /* 左边部分的extra */
    @Prop({
        type: String,
        default: '左边栏extra的slot'
    }) leftExtra: string | undefined;

    /* 右边部分的title */
    @Prop({
        type: String,
        default: '右边栏标题slot'
    }) rightTitle: string | undefined;

    /* 右边部分的extra */
    @Prop({
        type: String,
        default: '右边栏extra的slot'
    }) rightExtra: string | undefined;

    /* 左右分栏的间隔 */
    @Prop({
        type: Number,
        default: 16
    }) gutter: number | undefined;

    /* 是否显示border */
    @Prop({
        type: Boolean,
        default: true
    }) bordered: boolean | undefined;

    /* 是否显示左边的head */
    @Prop({
        type: Boolean,
        default: true
    }) isVisibleLeftHead: boolean | undefined;

    /* 是否显示右边的head */
    @Prop({
        type: Boolean,
        default: true
    }) isVisibleRightHead: boolean | undefined;

    /* 是否显示border */
    @Prop({
        type: String,
        default: '#ffff'
    }) bgColor: string | undefined;

    /* 是否显示伸缩操纵杆 */
    @Prop({
        type: Boolean,
        default: true
    }) isVisibleSwitchHandler: boolean | undefined;

    /* 是否显示伸缩操纵杆 */
    @Prop({
        type: Object,
        default: {
            extend: '/images/switch/extend_icon.png',
            shrink: '/images/switch/shrink_icon.png'
        }
    }) switchHandlerIcons: { extend: string; shrink: string };

    /* 是否收起操纵杆 */
    isShrinkSwitch = false;

    paddingLeft = '0px';

    /**
     * @description 动态设置headStyle (左)
     * @return void
     * @author JUN - 2023/8/10 10:52
     */
    get getLeftHeadStyle() {
        const bordered = this.bordered ? {} : { border: 0 };
        const visible = this.isVisibleLeftHead ? {} : { display: 'none' };
        return { ...bordered, ...visible };
    }

    /**
     * @description 动态设置headStyle (右)
     * @return void
     * @author JUN - 2023/8/10 10:52
     */
    get getRightHeadStyle() {
        const bordered = this.bordered ? {} : { border: 0 };
        const visible = this.isVisibleRightHead ? {} : { display: 'none' };
        return { ...bordered, ...visible };
    }

    /**
     * @description 动态设置bodyStyle (左)
     * @return void
     * @author JUN - 2023/8/10 10:52
     */
    get getLeftBodyStyle() {
        const bordered = this.bordered ? {} : { border: 0 };
        const height = this.isVisibleLeftHead ? { height: 'calc(100% - 55px)' } : { height: '100%' };
        return {
            ...bordered,
            ...height,
            overflow: 'auto',
        };
    }

    /**
     * @description 动态设置bodyStyle (右)
     * @return void
     * @author JUN - 2023/8/10 10:52
     */
    get getRightBodyStyle() {
        const bordered = this.bordered ? {} : { border: 0 };
        const height = this.isVisibleRightHead ? { height: 'calc(100% - 55px)' } : { height: '100%' };
        return {
            ...bordered,
            ...height,
            overflow: 'auto',
        };
    }

    /**
     * @description 返回当前操作杆的icon
     * @return void
     * @author JUN - 2023/8/10 13:45
     */
    get activeSwitchHandlerIcon() {
        const icon = this.isShrinkSwitch ? 'extend' : 'shrink';
        return this.switchHandlerIcons[icon];
    }

    /**
     * @description 触发操纵杆事件处理
     * @return void
     * @author JUN - 2023/8/10 13:41
     */
    onTriggerSwitchHandler() {
        this.isShrinkSwitch = !this.isShrinkSwitch;
    }

    mounted() {
        const parentElement = this?.$el?.parentElement;
        const { paddingLeft } = getComputedStyle(parentElement);
        this.paddingLeft = paddingLeft;
    }
}
</script>

<style scoped lang="less">
/deep/ .ant-card-body {
  /*定义滚动条高宽及背景 高宽分别对应横竖滚动条的尺寸*/

  &::-webkit-scrollbar {
    width: 8px;
    height: 8px;
    border-radius: 0px;
  }

  /*定义滚动条轨道 内阴影+圆角*/

  &::-webkit-scrollbar-track {
    //-webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3);
    border-radius: 3px;
    background: rgba(0, 0, 0, 0.05);
  }

  /*定义滑块 内阴影+圆角*/

  &::-webkit-scrollbar-thumb {
    border-radius: 4px;
    //-webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, .3);
    background: rgba(0, 0, 0, 0.10);
  }
}
</style>

由于默认的滚动条颜值太低了,所以我还自定义了滚动条的样式(less),代码如下:

/deep/ .ant-card-body {
  /*定义滚动条高宽及背景 高宽分别对应横竖滚动条的尺寸*/
  &::-webkit-scrollbar {
    width: 8px;
    height: 8px;
    border-radius: 0px;
  }

  /*定义滚动条轨道 内阴影+圆角*/
  &::-webkit-scrollbar-track {
    //-webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3);
    border-radius: 3px;
    background: rgba(0, 0, 0, 0.05);
  }

  /*定义滑块 内阴影+圆角*/
  &::-webkit-scrollbar-thumb {
    border-radius: 4px;
    //-webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, .3);
    background: rgba(0, 0, 0, 0.10);
  }
}

使用

<!--
 * @description GHorizontalColumnsDemo.vue 横向左右分栏布局的demo
 * @author JUN - 2023/8/10 14:54
-->
<template>
    <g-horizontal-columns :bordered="false" :is-visible-left-head="false" style="height: 85vh;">
        <div class="border" style="height: 800px" slot="leftContent">
            测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试
        </div>
        <div class="border" style="height: 800px" slot="rightContent">
            测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试
        </div>

        <div slot="switchHandler" slot-scope="{isShrinkSwitch}">
            <img v-if="isShrinkSwitch" src="/images/switch/extend_icon.png" width="48px" height="136px">
            <img v-else src="/images/switch/shrink_icon.png" width="48px" height="136px">
        </div>
    </g-horizontal-columns>
</template>
<script lang="ts">
import { Vue, Component } from 'vue-property-decorator';
import GHorizontalColumns from '@/components/common/layouts/GHorizontalColumns.vue';

@Component({
    name: 'GHorizontalColumnsDemo',
    components: { GHorizontalColumns }
})
export default class GHorizontalColumnsDemo extends Vue {

}
</script>

<style scoped lang="less">

</style>

效果

在这里插入图片描述

技术不行,还有很多可以优化的地方,希望大家留言指教

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

花姐夫Jun

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

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

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

打赏作者

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

抵扣说明:

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

余额充值