基于antd-vue Table组件的二次封装

  • 封装缘由:
    1.减少重复工作量
    2.统一风格
    3.方便一键式更改(如果样式变更,减少工作量)

  • 封装方式:
    本次封装没有封装接口联调部分,只是基于日常使用的规范,进行常用功能的封装。

  • 封装后支持的功能或方便之处:
    1.新增了斑马线的功能。
    2.新增了省略时鼠标移入的ToolTip组件提示。
    3.通过配置可以选择隐藏某些列。
    4.数据为空时,官网的滚动条在表头下面,改为表的最下面。
    5.通过自定义列配置,实现是/否的判断。

  • 封装时遇到的问题及解决方式
    1.问题:插槽的二次封装,如果想要正常使用,必须在封装组件的时候重新定义一遍
    解决方式:封装时通过遍历传入的column,去动态生成外层的插槽。
    2.问题:封装省略时鼠标移入的ToolTip组件提示时,判断是否省略
    解决方式:给容器一个最大宽度,然后判断容器的scrollWidth是否大于设置好的最大宽度。
    3.问题:如果需要判断是否溢出的是一个插槽,该怎么去判断
    解决方式:通过columns自定义一个变量代表渲染方式,判断是插槽类型还是文字类型。如果是插槽类型,那么就外包裹;如果是文件类型,那么就内包裹。具体请详看代码。
    4.问题:初版斑马线使用计算设置的,但是使用fixed时,出现错位情况
    解决方式:使用css方式添加斑马线。
    5.问题:scroll绑定的时,如果没有赋值会报错
    解决方式:动态判断是否有没有传入scroll属性,如果没有传入,不会绑定此属性。
    6.问题:因为antd-vue层级结构已定,该如果更改滚动条位置
    解决方式:隐藏之前的dom,通过定位和更改样式,去实现一个类似的效果。

  • 完整代码


<template>
  <div :class="`my-table ${dataSource.length ? '' : 'no-data'}`">
    <a-table
      :class="hideStripe ? '' : 'stripe'"
      :rowKey="rowKey || 'id'"
      :columns="newColumns"
      :data-source="dataSource"
      :loading="loading"
      :pagination="newPagination"
      :showHeader="showHeader"
      :row-selection="rowSelection"
      :childrenColumnName="childrenColumnName"
      :expandIcon="null"
      v-on="$listeners"
      v-bind="
        $props.scroll
          ? {
              scroll: {
                ...scroll,
                x:
                  scroll.x <= 1500
                    ? dataSource.length
                      ? scroll.x
                      : null
                    : scroll.x,
              },
            }
          : {}
      "
      @expand="expand"
      :rowClassName="rowClassName"
    >

      <template slot="customTitle">
        <slot name="customTitle"></slot>
      </template>

      <template
        v-for="(column, columnIndex) in columns"
        :slot="column.scopedSlots ? column.scopedSlots.customRender : ''"
        slot-scope="text, record, index"
      >
        <div :key="columnIndex">
          <!-- 支持传入插槽的tooltip格式 -->
          <EllipsisContent
            v-if="
              column.scopedSlots
                ? column.scopedSlots.ellipsisSlot
                  ? true
                  : false
                : false
            "
            :width="getEllipsisContentWidth(column)"
            :title="
              record[column.scopedSlots ? column.scopedSlots.customRender : '']
            "
          >
            <slot
              :name="column.scopedSlots ? column.scopedSlots.customRender : ''"
              v-bind="record"
              v-bind:index="index"
            >
            </slot>
          </EllipsisContent>

          <!-- 支持传入插槽的普通渲染格式 -->
          <!-- 不支持传入插槽的tooltip格式 -->
          <!-- 通用xxxx判断(0:否,1:是) -->
          <slot
            v-else
            :name="column.scopedSlots ? column.scopedSlots.customRender : ''"
            v-bind="record"
            v-bind:index="index"
          >

            <!-- 支持传入插槽的普通渲染格式 -->
            <div
              v-if="
                column.scopedSlots
                  ? column.scopedSlots.ellipsisName
                    ? true
                    : false
                  : false
              "
              :slot="column.scopedSlots.ellipsisName"
              :key="index"
            >
              <EllipsisContent
                :width="getEllipsisContentWidth(column)"
                :title="record[column.scopedSlots.ellipsisName]"
              >
                {{ record[column.scopedSlots.ellipsisName] }}
              </EllipsisContent>
            </div>

            <!-- 通用xxxx判断(0:否,1:是) -->
            <div
              v-if="
                column.scopedSlots
                  ? column.scopedSlots.customRender === 'is'
                    ? true
                    : false
                  : false
              "
              slot="is"
            >
              {{ record[column.dataIndex] == 1 ? "是" : record[column.dataIndex] == 0 ? "否" : "" }}
            </div>
          </slot>
        </div>
      </template>
      <template
        :slot="expandedRowRender ? 'expandedRowRender' : 'undefind'"
        slot-scope="record"
      >
        <slot name="expandedRowRender" v-bind="record"></slot>
      </template>
    </a-table>

    <!-- 数据为空时显示自定义 empty -->
    <a-empty v-show="!dataSource.length" class="empty">
      <img slot="image" src="@/assets/svg/empty.svg" />
    </a-empty>
  </div>
</template>

<script>
const defaultPagination = {
  pageSize: 10,
  current: 1,
  pageSizeOptions: ["10", "20", "30", "50", "100"],
  "show-size-changer": true,
  "show-quick-jumper": true,
  showTotal(total) {
    return `共${total}条`;
  },
};

// antd 表格默认的左右padding,会影响省略时父容器的计算
const ANT_TABLE_LR_PADDING = 32;

import { Table } from "ant-design-vue";
export default {
  name: "my-table",
  data() {
    return {
      paginationData: defaultPagination,
      variableColumns: [],
      isload: true,
    };
  },
  props: {
    ...Table.props,
    expandedRowRender: {
      type: Boolean,
      default: false,
    },
    pagination: {
      default() {
        return defaultPagination;
      },
    },
    // 隐藏斑马线
    hideStripe: {
      type: Boolean,
      default: false,
    },
    // 隐藏配置过hidden为true的列
    hideConfigColumns: {
      type: Boolean,
      default: false,
    },
  },
  methods: {
    expand(expanded, record) {
      this.$emit("expand", expanded, record);
    },

    // 获取省略容器真实宽度
    getEllipsisContentWidth(column) {
      let columnWidth = parseInt(column.width || 200 + ANT_TABLE_LR_PADDING);
      return columnWidth - ANT_TABLE_LR_PADDING;
    },
  },
  computed: {
    newPagination() {
      if (!this.pagination) {
        return false;
      }

      return {
        ...defaultPagination,
        ...this.pagination,
      };
    },

    // 通过hideConfigColumns控制columns中配置过hidden为true的列隐藏
    newColumns() {
      let columns = this.columns;
      let newColumns = [];
      if (this.hideConfigColumns) {
        columns.map((column) => {
          if (!column.hidden) {
            newColumns.push(column);
          }
        });
      }
      return newColumns?.length ? newColumns : columns;
    },
  },
};
</script>

<style lang="less" scoped>
@import "@/style/antd.less";
.my-table {
  position: relative;

  // 斑马线css版样式
  .stripe {
    /deep/ .ant-table-tbody > tr:nth-child(even) > td {
      background: #f5f7fa;
    }

    /deep/ .ant-table-tbody > tr:nth-child(even) {
      &:hover td {
        background: #e6f7ff;
      }
    }
  }

  // 修改每列的样式
  /deep/ .ant-table-thead > tr > th,
  /deep/ .ant-table-tbody > tr > td {
    padding: 12px 16px;
  }

  /deep/ tr.ant-table-expanded-row,
  tr.ant-table-expanded-row:hover {
    background-color: transparent;
  }

  // 删除拓展表格无用的样式
  /deep/ tr.ant-table-expanded-row.ant-table-expanded-row-level-1 > td {
    padding: 0;
  }
  /deep/ tr.ant-table-expanded-row.ant-table-expanded-row-level-1 {
    .ant-table-tbody > tr:last-child > td {
      border-bottom: 0;
    }
  }

  /deep/ .ant-table-scroll {
    .ant-table-body {
      overflow-x: auto !important;
    }
  }
}

.no-data {
  /deep/ .ant-table-placeholder {
    display: none;
  }
  /deep/ .ant-table-body {
    height: 168px;
  }
}

.empty {
  top: 46px;
  width: 100%;
  height: 100px;
  position: absolute;
  padding-right: 14px;

  /deep/ .ant-empty-image {
    height: 40px;
    margin-top: 20px;
    margin-bottom: 8px;
  }
  /deep/ .ant-empty-description {
    color: rgba(0, 0, 0, 0.2);
  }
}
</style>

省略组件相关代码:

<template>
  <div class="">
    <a-tooltip v-if="visible" :title="title">
      <div :style="`max-width: ${width}px;`"  class="ellipsis-content" ref="content">
        <slot></slot>
      </div>
    </a-tooltip>
    <div :style="`max-width: ${width}px;`" v-else class="ellipsis-content" ref="content">
      <slot></slot>
    </div>
  </div>
</template>
<script>
export default {
  name: "ellipsis-content",
  data() {
    return {
      visible: false,
    };
  },
  props: {
    width: {
      default: 200,
    },
    title: {
      default: "",
    },
  },
  mounted() {
    this.$nextTick(() => {
      let scrollWidth = this.$refs.content.scrollWidth;
      if (scrollWidth > this.width) {
        this.visible = true;
      }
    });
  },
};
</script>

<style lang="less" scoped>
.ellipsis-content {
  max-width: 200px;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}
</style>

使用代码:

<Table
      rowKey="id"
      :columns="columns"
      :data-source="dataSource"
      :pagination="pagination"
      :loading="loading"
      :row-selection="{
        selectedRowKeys: selectedRowKeys,
        onChange: handleSelectChange,
      }"
      :scroll="{ x: 3180 }"
      @change="change"
   / >

使用起来和antd官网基本相似,可能存在部分属性的差异。

在这里插入图片描述
如图,如果要配置省略时有tooltip的效果,ellipsisName代表渲染对应的字段,ellipsisSlot代表采用插槽类型。定义插槽类型时,需要写好插槽,并且插槽中渲染的内容必须是文字且不能被标签包裹。如下:

<template slot="name" slot-scope="record">
 {{ record.name }}
</template>

看到这里,可能会有童鞋说,为什么不将所需的属性存在一个变量中传入,然后动态赋值,这样做能解开上述的很多问题。我也想过,也试验过,最终的感觉就是不好用。封装起来可能比较简单,但是对于使用者来说,体验是最重要的,如果采用类似的官网的方式就行使用,对于开发着来说是最优的。

  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 9
    评论
### 回答1: antd-mobile-vue是一个基于Vue.js框架的移动端组件库,它提供了一系列UI组件,用于开发高质量的移动端应用。 与其它UI组件库相比,antd-mobile-vue具有以下优势和特点: 1. 高质量的组件antd-mobile-vue提供了丰富的移动端UI组件,如按钮、表单、弹窗、导航等,这些组件都经过了精心设计和开发,具有统一的风格和良好的用户体验。 2. 灵活的布局:antd-mobile-vue提供了灵活的布局组件,如栅格布局、Flex布局,可帮助开发者快速搭建页面结构,并自适应不同的屏幕尺寸。 3. 易于使用和扩展:antd-mobile-vue组件使用简单,开发者可以通过简单的配置和参数就可以实现复杂的交互效果。而且,antd-mobile-vue组件提供了丰富的扩展能力,可以根据项目需求进行个性化的定制。 4. 生态丰富:antd-mobile-vue拥有庞大的开发者社区和活跃的维护团队,开发者可以通过官方文档和社区资源获取帮助和支持。此外,antd-mobile-vue还与其它Vue.js生态工具和库良好地兼容,如Vue Router、Vue CLI等。 5. 支持国际化:antd-mobile-vue提供了多语言支持,开发者可以根据项目需求灵活地切换多种语言环境。 总之,antd-mobile-vue是一个功能强大、易于使用和扩展的移动端组件库,它可以帮助开发者快速构建高质量的移动端应用,提高开发效率和用户体验。 ### 回答2: antd-mobile-vue是一种基于Vue.js框架的移动端UI库。它是对Ant Design Mobile的Vue组件实现的封装和扩展,旨在为开发者提供高质量、易用性的移动端组件库,帮助快速开发移动应用程序。 antd-mobile-vue提供了丰富的移动端UI组件,如按钮、导航栏、标签栏、列表、表单等,可以满足日常开发中绝大部分的界面需求。这些组件都经过精心设计和优化,在视觉和交互上都符合当前移动端的设计原则和用户体验。而且,它还提供了灵活的定制和扩展能力,允许开发者根据具体需求进行个性化定制,提高开发效率和用户体验。 除了UI组件外,antd-mobile-vue还提供了一些实用的工具和功能,如样式工具库、语言国际化、路由管理等。这些工具和功能都是为了让开发者更方便地进行移动应用开发,减少重复性的工作,提高开发效率。 antd-mobile-vue拥有广泛的社区支持和文档资料,开发者可以从社区中获取帮助和解决问题,学习和掌握使用该库的技巧和最佳实践。同时,antd-mobile-vue还提供了详细的官方文档和示例代码,方便开发者快速入手和上手该库。 总之,antd-mobile-vue是一款功能强大、易用性强的移动端UI库,适用于各种移动应用的开发。无论是个人开发者还是团队开发,都可以通过使用antd-mobile-vue来快速构建高质量的移动应用程序。 ### 回答3: antd-mobile-vue 是一个基于 Vue.js 的移动端 UI 组件库,它提供了丰富的移动端组件和样式风格,可以帮助开发者快速构建优雅的移动端应用。 antd-mobile-vue 的特点有以下几个方面: 1. 高度可定制:antd-mobile-vue 提供了大量的组件,涵盖了移动端常见的UI元素,如按钮、导航栏、表单等,这些组件的样式和交互行为都可以通过配置进行定制,满足不同项目的需求。 2. 兼容性强:antd-mobile-vue 提供了对不同移动端浏览器和操作系统的支持,保证组件在不同环境下的正常运行和展示,同时也保证了用户的使用体验。 3. 特色设计:antd-mobile-vue 的设计风格简洁、现代,符合移动端用户的审美要求,同时也遵循了 Material Design 和 iOS Human Interface Guidelines 等设计准则,保证了用户的熟悉感和易用性。 4. 文档丰富:antd-mobile-vue 提供了详细的文档和示例代码,开发者可以根据文档了解组件的使用方法和配置参数,快速上手使用。 5. 生态丰富:antd-mobile-vue 是基于 Ant Design Mobile(antd-mobile)的 Vue 实现,可以与其它 Vue 生态工具和插件无缝集成,如 Vue Router、Vuex 等,方便开发者构建复杂的移动应用。 总之,antd-mobile-vue 是一个强大而灵活的移动端 UI 组件库,它可以帮助开发者节省时间和精力,快速开发出高质量的移动应用。无论是个人项目还是企业应用,都可以考虑使用这个库来提升开发效率和用户体验。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值