vue.js Table 组件自定义列宽实现核心方法

目录
  • 前言
  • colgroup 和 col
  • 核心实现
    • 一些常量/变量定义
  • 初始化表头列表 initColumns
    • 处理含有固定宽度和最小宽的列
    • 获取各列宽度,并组成一个数组 getWidthList
    • 计算需要自适应的列宽度 getAdaptWidth
  • 监听屏幕变化和属性更新

前言

如果你使用过类似于 ElementUI 的组件库,一定对如下的 API 属性不眼生,例如:

<!-- Element UI -->
<el-table-column prop="date" label="日期" min-width="150"></el-table-column>
<el-table-column prop="name" label="姓名" width="200"></el-table-column>
<el-table-column prop="province" label="省份" width="200"></el-table-column>

<!-- and-design for vue -->
 cols: [
    { title: '日期',dataIndex: 'date',key: 'date', minWidth: 150 },
    { title: '姓名',dataIndex: 'name',key: 'name', width: 200 },
    { title: '省份',dataIndex: 'province',key: 'province', width: 200 },
],

上面的例子中,Table 组件支持自定义最小宽度min-width和固定宽度width,如果不设置,则默认填充剩余宽度。

如果你打算自己手动实现一个 Table 组件,并且对支持定义列宽属性的实现毫无头绪,那这篇文章大概率可以帮你梳理一些逻辑和核心方法的实现(Vue3)

注:这也许不是最佳的实现方案。

准备工作:

这里假定使用的是类似于and-design for vue的属性传值方式,即列的属性配置是通过额外的数组对象传入的。

除了title-列表头名,key-列值对应的键外,还有这篇文章涉及到的最小宽度minWidth和固定宽度width,并通过组件属性cols传入。

colgroup 和 col

这里需要用到<colgroup><col>标签,以便更好的去控制每列的属性信息,两个标签均支持传入width属性控制列宽度,不同的是,<col>控制的是单列的宽度,而<colgroup>可以控制所包含在内的。

除此之外,这两个标签还有如下注意事项:

  • colgroup需在 table 标签中
  • col需在 colgroup 标签中,且只能包含 标签
  • 两者均无法为表格创建列,仅控制列的展现形式
  • 在 xhtml 中,col必须含有结束标签

根据我们的需求,我们需要单独控制每一列的宽度展示,并在浏览器宽度变化时实时的重新计算并且重新渲染列。

大致的功能如下:

  • 含有width的列,宽度固定,不随浏览器宽度变化而变化
  • 含有minWidth的列,在大于设定值时,自动填充 table 剩余宽度,小于设定值时,固定该宽度
  • 不包含widthminWidth的列,自动填充 table 剩余宽度

最终实现如下渲染效果:

<template>
    <colgroup>
        <col
         v-for="(item, index) in columns"
         :key="`table-tr-${index}`"
         :name="`table_tr_${index}`"
         :width="`${item.width}px`"
         />
    </colgroup>
</template>

核心实现

一些常量/变量定义

在 Table 组件初始化的时候,需要定义一些变量以供后续方法中使用,具体如下:

/** Table 实例 */
const bpTable = ref(null);

/** 最终用于渲染的 columns 表头列表 */
const columns = ref([]);

/** 表格所占的实际宽度 px */
const _table_width = ref("");

/** 在没有设定宽度时,可用于撑开剩余宽度的列数 */
let _remainder_col = 0;

/** 固定宽度(包含自定义的宽和最小宽的总和) */
let _fixed_width = 0;

/** 各列最小宽度数组 */
let _min_width_list = [];

/** 表格各列宽度数组 */
let _col_width_list = [];

/** 单列最小宽度 */
const _min_column_width = 80;

初始化表头列表 initColumns

在表格整体渲染结束,能获取 table 实际宽度后,需要执行表头列表初始化,对传入的props中的cols进行处理,计算实际每一列需要width值。

/**
 * 初始化表头列表
 * @returns Array
 */
const initColumns = () => {
    const el = bpTable.value;
    const { cols } = props;

    /** 每次需要初始化的一些值 */
    _fixed_width = 0;
    _remainder_col = cols.length;
    _min_width_list = [];

    // 1. 处理含有固定宽度和最小宽的列

    // 2. 获取各列宽度,并组成一个数组

        // 计算需要自适应的列宽度

    // 3. 输出 columns
}

处理含有固定宽度和最小宽的列

如果含有自定义的宽和最小宽,则需要单独处理这些列,使其不参与剩余宽度自适应当中,同时对应的自适应列的数量也要相应的减去,处理逻辑如下:

for (let i = 0; i < cols.length; i++) {
    const { width, minWidth } = cols[i];

    if (width) {
            _fixed_width += Number(width);
            _remainder_col--;
    }
    minWidth && _min_width_list.push(minWidth)
}

获取各列宽度,并组成一个数组 getWidthList

这个方法目的返回一个数组,包含各列的宽度值,最后匹配到columns中。 为了不出现列宽过于太小而把内容挤掉的情况,需要判断最小值不能小于设定的80px

/**
 * 获取各列宽度,并组成一个数组
 * @returns Array width_list
 */
function getWidthList() {
    const { cols } = props;
    /** 各列宽度数组 */
    let width_list = [];
    /** 自适应列宽 */
    let adapt_width = getAdaptWidth();
    /**
    * 当表格中含有设置最小宽度的列时,需要挨个比较自适应宽是否小于最小宽度
    * 如果小于,则重新设置各个值并重新计算自适应宽度
    */
    if (_min_width_list.length) {
        _min_width_list.map((item, index) => {
            if (adapt_width > item) {
                _fixed_width += item;
                _remainder_col--;
                _min_width_list.splice(index, 1);
                adapt_width = getAdaptWidth();
            }
        });
    }

    for (let i = 0; i < cols.length; i++) {
        const { width, minWidth } = cols[i];

        // 设置成固定宽度
        if (width) { width_list.push(width); continue; }

        // 是否设置成最小宽度:当含有最小宽度属性并且最小宽度大于计算得出的最大列宽
        const hasMinWidth = minWidth && minWidth > adapt_width;
        if (hasMinWidth) { width_list.push(minWidth); continue; }

        // 如果没有定义宽度和最小宽,则设置成自适应宽度或者最小预设宽度
        width_list.push(adapt_width < _min_column_width ? _min_column_width : adapt_width);
    }
    return width_list;
}

计算需要自适应的列宽度 getAdaptWidth

在表格整体渲染结束,能获取 table 实际宽度后,需要计算允许列自适应的宽度有多少,如果所有列都没有设置宽度值,这时候自适应的列宽即为 table 的实际宽度,列宽平均分布就行了。

/**
    * 根据表格实际宽度、已固定的列宽、以及剩余自适应列数,计算得出自适应列宽
    * @returns Number width
    */
    function getAdaptWidth() {
    let width = (_table_width.value - _fixed_width) / _remainder_col;
    return Number(width).toFixed(2);
    }
    ```
    #### 完整代码
    ```javascript
    /**
    * 获取各列宽度,并组成一个数组
    * @returns Array width_list
    */
    function getWidthList() {
    const { cols } = props;

    /** 各列宽度数组 */
    let width_list = [];

    /** 自适应列宽 */
    let adapt_width = getAdaptWidth();

    /**
     * 当表格中含有设置最小宽度的列时,需要挨个比较自适应宽是否小于最小宽度
     * 如果小于,则重新设置各个值并重新计算自适应宽度
     */
    if (_min_width_list.length) {
      _min_width_list.map((item, index) => {
        if (adapt_width > item) {
          _fixed_width += item;
          _remainder_col--;
          _min_width_list.splice(index, 1);
          adapt_width = getAdaptWidth();
        }
      });
    }

    for (let i = 0; i < cols.length; i++) {
      const { width, minWidth } = cols[i];

      // 设置成固定宽度
      if (width) { width_list.push(width); continue; }

      // 是否设置成最小宽度:当含有最小宽度属性并且最小宽度大于计算得出的最大列宽
      const hasMinWidth = minWidth && minWidth > adapt_width;
      if (hasMinWidth) { width_list.push(minWidth); continue; }

      // 如果没有定义宽度和最小宽,则设置成自适应宽度或者最小预设宽度
      width_list.push(adapt_width < _min_column_width ? _min_column_width : adapt_width);
    }
    return width_list;
    }

监听屏幕变化和属性更新

触发initColumns的时机有三个

  • 初次加载表格组件
  • 列属性有更新时
  • 屏幕宽度变化时
  watch(() => props.cols, () => { initColumns() });

  onMounted(() => {
    nextTick(() => {
      initColumns();
      on(window, 'resize', throttle(() => initColumns(), 400));
    });
  });
  onBeforeUnmount(() => off(window, 'resize', () => initColumns()));

到此这篇关于vue.js Table 组件自定义列宽实现核心方法的文章就介绍到这了,更多相关vue.js Table 组件自定义内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 利用vue.js把静态json绑定bootstrap的table方法

    直接上代码 嘻嘻,发现bootstrap+vue.js拿来做原型效率挺高,以后就这样做原型 <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Document</title> <link rel="stylesheet" type="text/css" href="https://cdn.b

  • vue.js中proxyTable 转发请求的实现方法

    找到config/index.js 配置文件 proxyTable: { '/api': { target: 'http://your_website', changeOrigin: true, pathRewrite: { //需要rewrite重写的, 如果在服务器端做了处理则可以不要这段 '^/api': '' } } } 以上这篇vue.js中proxyTable 转发请求的实现方法就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持我们.

  • vue.js管理后台table组件封装的方法

    目录 问题分析 为什么封装 封装的内容都有哪些 封装table组件 确认数据格式 封装组件 封装全局组件 table组件封装 分页组件封装 数据定义 封装 总结 最近开了新的项目,简单说了自己的table封装. 问题分析 为什么封装 首先为什么封装,是因为追求技术吗,不,是因为懒,不想一直的去粘贴复制代码,所以就想把table封装下,可以在创建新的table的时候,只需要填充数据就行了. 封装的内容都有哪些 主要有两个,一个是table组件,一个是分页组件 搞清楚这个些,就可以开始封装组件了.

  • vue.js Table 组件自定义列宽实现核心方法

    目录 前言 colgroup 和 col 核心实现 一些常量/变量定义 初始化表头列表 initColumns 处理含有固定宽度和最小宽的列 获取各列宽度,并组成一个数组 getWidthList 计算需要自适应的列宽度 getAdaptWidth 监听屏幕变化和属性更新 前言 如果你使用过类似于 ElementUI 的组件库,一定对如下的 API 属性不眼生,例如: <!-- Element UI --> <el-table-column prop="date" l

  • Vue中Table组件行内右键菜单实现方法(基于 vue + AntDesign)

    最近做的一个项目是基于 vue + AntDesign 的.由于项目要求,需要在 Table 组件的行内点右键的时候弹出菜单.在线演示地址及最终效果图如下: 在线演示地址>> 首先新建一个Table组件的实例: <a-table :columns="columns" :rowKey="record => { return record.INDEX;}" :dataSource="tableData" /> ... c

  • Vue.js桌面端自定义滚动条组件之美化滚动条VScroll

    前言 前段时间有给大家分享一个vue桌面端弹框组件,今天再分享最近开发的一个vue pc端自定义滚动条组件. vscroll 一款基于vue2.x开发的网页端轻量级超小巧自定义美化滚动条组件.支持是否原生滚动条.鼠标移出是否自动隐藏.自定义滚动条尺寸及颜色等功能. 组件在设计开发之初借鉴了 el-scrollbar 及 vuebar 等组件设计思想. 通过简单的标签写法<v-scroll>...</v-scroll> 即可快速生成一个漂亮的替换原生滚动条. 参数配置 props:

  • Vue.js 中制作自定义选择组件的代码附演示demo

    定制 select 标签的设计非常困难.有时候,如果不使用样式化的 div 和自定义 JavaScript 的结合来构建自己的脚本,那是不可能的.在本文中,你将学习如何构建使用完全自定义 CSS 设置样式的 Vue.js 组件. Demo: https://codesandbox.io/s/custom-vuejs-select-component-8nqgd HTML <template> <div class="custom-select" :tabindex=&

  • 基于Vue.js+Nuxt开发自定义弹出层组件

    今天给大家分享VPopup 基于Vue.js构建的轻量级移动端弹出框组件,详情如下所示: 一款融合了Vant.NutUI等热门Vue组件库中的Popup弹层.Dialog对话框.Toast提示框.ActionSheet动作面板框.Notify通知框等功能. 快速使用 在main.js中引入组件 // 引入弹窗Popup import Popup from './components/popup' Vue.use(Popup) 支持如下两种 组件式 及 函数式 调用插件. 组件式 <templat

  • Vue.js实现一个自定义分页组件vue-paginaiton

    vue实现一个分页组件vue-paginaiton vue使用了一段时间的感触就是,我再也不想直接操作DOM了.数据绑定式的编程体验真是好.实现的一个分页组件. 这里的css就不放出来了,可以看直接去github上下载:vue-pagination 先上一张实例图吧 模版 <div class="page-bar"> <ul> <li v-if="showFirstText"><a v-on:click="cur-

  • Vue.js函数式组件的全面了解

    目录 前言 React 函数式组件 Vue(2.x) 中的函数式组件

  • Vue.js动态组件解析

    本篇资料来于官方文档:http://cn.vuejs.org/guide/components.html#u52A8_u6001_u7EC4_u4EF6 本文是在官方文档的基础上,更加细致的说明,代码更多更全. 简单来说,更适合新手阅读 ①简单来说: 就是几个组件放在一个挂载点下,然后根据父组件的某个变量来决定显示哪个,或者都不显示. ②动态切换: 在挂载点使用component标签,然后使用v-bind:is="组件名",会自动去找匹配的组件名,如果没有,则不显示: 改变挂载的组件,

  • Vue.js分页组件实现:diVuePagination的使用详解

    一.介绍 Vue.js 是什么 Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式框架.与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用.Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合.另一方面,当与现代化的工具链以及各种支持类库结合使用时,Vue 也完全能够为复杂的单页应用提供驱动. 二.创建初始化项目 这里不在详细说明,我们的分页演示只需要vue和vue-router就可以了,我们直接构建项目和设置配置. main.js:

  • vue element-ui table组件动态生成表头和数据并修改单元格格式 父子组件通信

    父组件 定义表头和表内容 data(){ return{ // 表格数据 tableColumns: [], // 表头数据 titleData:[], } } 引入并注册子组件 import TableComponents from "../../components/table/table"; //注册子组件table components: { tableC: TableComponents }, 获取表头和表内容数据.(真实数据应该是从接口获取的,由于是测试数据这里我先写死)

随机推荐