Layui表格树、表格合并+表格折叠树

一、表格树:

1、先将插件源码进行下载,新建 tableTree.js 文件,将源码放进去

2、将 tableTree.js 文件 配置之后,在需要使用的页面进行引入:

layui.define(["tableTree"],function (exports) {
   
   
    var tableTree = layui.tableTree;

   // 获取树图的数据
	var handleList = function() {
   
   
		// 假数据
		let tableData = [{
   
   
		    "pid": "0", 
		    "title": "1",
		    "parentTitle": null,
		    "sid": "1111111111",
		    "children": null
		  },
		  {
   
   
		    "pid": "1111111111",
		    "title": "1-1",
		    "parentTitle": "1",
		    "sid": "2"
		},
		  {
   
   
		    "pid": "1111111111",
		    "title": "1-2",
		    "parentTitle": "1",
		    "sid": "3"
		},
		  {
   
   
		    "pid": "0",
		    "title": "2",
		    "parentTitle": null,
		    "sid": "2222222"
		},{
   
   
		    "pid": "0",
		    "title": "3",
		    "parentTitle": null,
		    "sid": "3333333"
		},{
   
   
		    "pid": "0",
		    "title": "4",
		    "parentTitle": null,
		    "sid": "44444"
		},{
   
   
		    "pid": "0",
		    "title": "5",
		    "parentTitle": null,
		    "sid": "5555"
		},{
   
   
		    "pid": "5555",
		    "title": "5",
		    "parentTitle": "5",
		    "sid": "6"
		}]
		renderTable(tableData)
	}
	
	// 表格渲染
    var  renderTable = function (tableData) {
   
   
		tableTree.render({
   
   
			id: 'test',       //做刷新的时候需要用ID
			tree: {
   
   
                 iconIndex: 3, // 展开图标显示再第几列
                 isPidData: true, // // pid形式数据转children形式
                 idName: 'sid', // 子id
                 pidName: 'pid', // 父id
                 openName: 'open',// 是否默认展开的字段名
             },
			elem: '#test',	//表格id
			skin: 'line' //表格风格
			, page: false//是否显示分页
			, limit: 100
			,cols: [[ //标题栏
				{
   
    field: 'id', hide: true },
				{
   
    type: 'radio'}
				, {
   
    field: 'title', title: '名称', align: 'left', width: 200 }
				, {
   
   
					field: 'opt', title: '操作', templet:
						return '<a class="layui-btn layui-btn-normal layui-btn-xs" lay-event="edit"><i class="layui-icon layui-icon-edit"></i> </a><a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="del"><i class="layui-icon layui-icon-delete"></i></a>'
				}
			]],
			data: tableData,
			//数据渲染完的回调
			done: function () {
   
   
			}
			, event: true
		})
	};

    // 单选框点击事件
	tableTree.on('checkbox(test)', function (obj) {
   
   
		var data = obj.data;
		console.log('拿到的当前行的数据', data)
	});

	// 表格操作事件
	tableTree.on("tool(test)", function (obj) {
   
   
		var data = obj.data;
		var layEvent = obj.event;
		var tr = obj.tr;
		if ("del" === layEvent) {
   
   
			console.log(删除的数据', data)
		} else if ("edit" === layEvent) {
   
   
			console.log(操作的数据', data)
		}
	});
		
	var Class = {
   
   
		init: function () {
   
   
			// 先请求数据
			handleList()
			return this;
		},
	};
  }
);

效果图:

在这里插入图片描述

插件源码如下:

/** 树形表格3.x Created by wangfan on 2020-05-12 https://gitee.com/whvse/treetable-lay */
 
layui.define(['laytpl', 'form', 'util'], function (exports) {
   
   
    var $ = layui.jquery;
    var laytpl = layui.laytpl;
    var form = layui.form;
    var util = layui.util;
    var device = layui.device();
    var MOD_NAME = 'treeTable';  // 模块名
    var _instances = {
   
   };  // 记录所有实例
 
    /* 表格默认参数 */
    var defaultOption = {
   
   
        elem: undefined,                                 // 容器
        cols: undefined,                                 // 列参数
        url: undefined,                                  // url模式请求
        method: undefined,                               // url模式请求方式
        where: undefined,                                // url模式请求条件
        contentType: undefined,                          // url模式请求类型
        headers: undefined,                              // url模式请求headers
        parseData: undefined,                            // url模式处理请求数据
        request: {
   
   pidName: 'pid'},                       // url模式请求字段自定义
        toolbar: undefined,                              // 表头工具栏
        defaultToolbar: undefined,                       // 表头工具栏右侧按钮
        width: undefined,                                // 容器宽度
        height: undefined,                               // 容器高度
        cellMinWidth: 90,                                // 单元格最小宽度
        done: undefined,                                 // 数据处理完回调
        data: undefined,                                 // 直接赋值数据
        title: undefined,                                // 定义table大标题,文件导出会用到
        skin: undefined,                                 // 表格风格
        even: undefined,                                 // 是否开启隔行变色
        size: undefined,                                 // 表格尺寸
        text: {
   
   
            none: '无数据'                               // 空数据提示
        },
        reqData: undefined,                              // 自定义加载数据方法
        useAdmin: false,                                  // 是否使用admin.ajax
        tree: {
   
   
            idName: 'id',                                // id的字段名
            pidName: 'pid',                              // pid的字段名
            childName: 'children',                       // children的字段名
            haveChildName: 'haveChild',                  // 是否有children标识的字段名
            openName: 'open',                            // 是否默认展开的字段名
            iconIndex: 0,                                // 图标列的索引
            arrowType: undefined,                        // 折叠箭头类型
            onlyIconControl: undefined,                  // 仅点击图标控制展开折叠
            getIcon: function (d) {
   
                         // 自定义图标
                var haveChild = d[this.haveChildName];
                if (haveChild !== undefined) haveChild = haveChild === true || haveChild === 'true';
                else if (d[this.childName]) haveChild = d[this.childName].length > 0;
                if (haveChild) return '<i class="ew-tree-icon layui-icon layui-icon-layer"></i>';
                else return '<i class="ew-tree-icon layui-icon layui-icon-file"></i>';
            }
        }
    };
    /* 列默认参数 */
    var colDefaultOption = {
   
   
        field: undefined,     // 字段名
        title: undefined,     // 标题
        width: undefined,     // 宽度
        minWidth: undefined,  // 最小宽度
        type: 'normal',       // 列类型
        fixed: undefined,     // 固定列
        hide: undefined,      // 是否初始隐藏列
        unresize: undefined,  // 禁用拖拽列宽
        style: undefined,     // 单元格样式
        align: undefined,     // 对齐方式
        colspan: undefined,   // 单元格所占的列数
        rowspan: undefined,   // 单元格所占的行数
        templet: undefined,   // 自定义模板
        toolbar: undefined,   // 工具列
        'class': undefined,   // 单元格class
        singleLine: undefined // 是否一行显示
    };
 
    /** TreeTable类构造方法 */
    var TreeTable = function (options) {
   
   
        _instances[options.elem.substring(1)] = this;
        this.reload(options);
    };
 
    /** 参数设置 */
    TreeTable.prototype.initOptions = function (opt) {
   
   
        var that = this;
 
        // 处理特殊列
        function initCol(item) {
   
   
            if (!item.INIT_OK) item = $.extend({
   
   INIT_OK: true}, colDefaultOption, item);
            // 特殊列处理
            if (item.type === 'space') {
   
     // 空列
                if (!item.width) item.width = 15;
                item.minWidth = item.width;
            } else if (item.type === 'numbers') {
   
     // 序号列
                if (!item.width) item.width = 40;
                item.minWidth = item.width;
                if (!item.singleLine) item.singleLine = false;
                if (!item.unresize) item.unresize = true;
                if (!item.align) item.align = 'center';
            } else if (item.type === 'checkbox' || item.type === 'radio') {
   
     // 复/单选框列
                if (!item.width) item.width = 48;
                item.minWidth = item.width;
                if (!item.singleLine) item.singleLine = false;
                if (!item.unresize) item.unresize = true;
                if (!item.align) item.align = 'center';
            }
            if (item.toolbar) item.type = 'tool';
            return item;
        }
 
        // 初始化列参数
        if ('Array' !== isClass(opt.cols[0])) opt.cols = [opt.cols];
 
        // 恢复cols参数初始状态
        for (var m = 0; m < opt.cols.length; m++) {
   
   
            for (var n = 0; n < opt.cols[m].length; n++) {
   
   
                opt.cols[m][n].INIT_OK = undefined;
                opt.cols[m][n].key = undefined;
                opt.cols[m][n].colGroup = undefined;
                opt.cols[m][n].HAS_PARENT = undefined;
                opt.cols[m][n].parentKey = undefined;
                opt.cols[m][n].PARENT_COL_INDEX = undefined;
            }
        }
 
        // cols参数处理
        var colArrays = [], colIndex = 0;
        for (var i1 = 0; i1 < opt.cols.length; i1++) {
   
   
            var item1 = opt.cols[i1];
            for (var i2 = 0; i2 < item1.length; i2++) {
   
   
                var item2 = item1[i2];
                if (!item2) {
   
   
                    item1.splice(i2, 1);
                    continue;
                }
                item2 = initCol(item2);
                // 合并单元格处理
                item2.key = i1 + '-' + i2;
                var CHILD_COLS = undefined;
                if (item2.colGroup || item2.colspan > 1) {
   
   
                    item2.colGroup = true;
                    item2.type = 'group';
                    CHILD_COLS = [];
                    colIndex++;
                    var childIndex = 0;
                    for (var i22 = 0; i22 < opt.cols[i1 + 1].length; i22++) {
   
   
                        var item22 = $.extend({
   
   INIT_OK: true}, colDefaultOption, opt.cols[i1 + 1][i22]);
                        if (item22.HAS_PARENT || (childIndex > 1 && childIndex == item2.colspan)) {
   
   
                            opt.cols[i1 + 1][i22] = item22;
                            continue;
                        }
                        item22.HAS_PARENT = true;
                        item22.parentKey = i1 + '-' + i2;
                        item22.key = (i1 + 1) + '-' + i22;
                        item22.PARENT_COL_INDEX = colIndex;
                        item22 = initCol(item22);
                        CHILD_COLS.push(item22);
                        childIndex = childIndex + parseInt(item22.colspan > 1 ? item22.colspan : 1);
                        opt.cols[i1 + 1][i22] = item22;
                    }
                }
                item2.CHILD_COLS = CHILD_COLS;
                if (!item2.PARENT_COL_INDEX) colArrays.push(item2);
                opt.cols[i1][i2] = item2;
            }
        }
        this.options = $.extend(true, {
   
   }, defaultOption, opt);
        this.options.colArrays = colArrays;
 
        // url加载模式转为reqData模式
        if (this.options.url) {
   
   
            this.options.reqData = function (data, callback) {
   
   
                if (!that.options.where) that.options.where = {
   
   };
                if (data) that.options.where[that.options.request.pidName] = data[that.options.tree.idName];
                (that.options.useAdmin ? layui.admin : $).ajax({
   
   
                    url: that.options.url,
                    data: that.options.contentType && that.options.contentType.indexOf('application/json') === 0 ? JSON.stringify(that.options.where) : that.options.where,
                    headers: that.options.headers,
                    type: that.options.method,
                    dataType: 'json',
                    contentType: that.options.contentType,
                    success: function (res) {
   
   
                        if (that.options.parseData) res = that.options.parseData(res);
                        if (res.code == 0) callback(res.data);
                        else callback(res.msg || '加载失败');
                    },
                    error: function (xhr) {
   
   
                        callback(xhr.status + ' - ' + xhr.statusText);
                    }
                });
            };
        } else if (this.options.data && this.options.data.length > 0 && this.options.tree.isPidData) {
   
     // pid形式数据转children形式
            this.options.data = tt.pidToChildren(this.options.data, this.options.tree.idName, this.options.tree.pidName, this.options.tree.childName);
        }
 
        // toolbar参数处理
        if ('default' === this.options.toolbar) {
   
   
            this.options.toolbar = [
                '<div>',
                '   <div class="ew-tree-table-tool-item" title="添加" lay-event="add">',
                '      <i class="layui-icon layui-icon-add-1"></i>',
                '   </div>',
                '   <div class="ew-tree-table-tool-item" title="修改" lay-event="update">',
                '      <i class="layui-icon layui-icon-edit"></i>',
                '   </div>',
                '   <div class="ew-tree-table-tool-item" title="删除" lay-event="delete">',
                '      <i class="layui-icon layui-icon-delete"></i>',
                '   </div>',
                '</div>'
            ].join('');
        }
        if (this.options.defaultToolbar === undefined) this.options.defaultToolbar = ['filter', 'exports', 'print'];
 
        // 自定义图标参数处理
        if (typeof this.options.tree.getIcon === 'string') {
   
   
            var icon = this.options.tree.getIcon;
            this.options.tree.getIcon = function (d) {
   
   
                if (icon !== 'ew-tree-icon-style2') return icon;
                var haveChild = d[this.haveChildName];
                if (haveChild !== undefined) haveChild = haveChild === true || haveChild === 'true';
                else if (d[this.childName]) haveChild = d[this.childName].length > 0;
                if (haveChild) return '<i class="ew-tree-icon ew-tree-icon-folder"></i>';
                else return '<i class="ew-tree-icon ew-tree-icon-file"></i>';
            }
        }
    };
    /** 初始化表格 */
    TreeTable.prototype.init = function () {
   
   
        var options = this.options;
        var $elem = $(options.elem);  // 原始表格
        var tbFilter = options.elem.substring(1);  // 表格的filter
        // 第一次生成树表格dom
        $elem.removeAttr('lay-filter');
        if ($elem.next('.ew-tree-table').length === 0) {
   
   
            $elem.css('display', 'none');
            $elem.after([
                '<div class="layui-form ew-tree-table" lay-filter="', tbFilter, '" style="', options.style || '', '">',
                '   <div class="ew-tree-table-tool" style="display: none;"></div>',
                '   <div class="ew-tree-table-head">',
                '      <table class="layui-table"></table>',
                '   </div>',
                '   <div class="ew-tree-table-box">',
                '      <table class="layui-table"></table>',
                '      <div class="ew-tree-table-loading">',
                '         <i class="layui-icon layui-icon-loading layui-anim layui-anim-rotate layui-anim-loop"></i>',
                '      </div>',
                '      <div class="ew-tree-table-empty">', options.text.none || '', '</div>',
                '   </div>',
                '</div>'
            ].join(''));
        }
        // 获取各个组件
        var components = this.getComponents();
 
        // 基础参数设置
        if (options.skin) components.$table.attr('lay-skin', options.skin);
        if (options.size) components.$table.attr('lay-size', options.size);
        if (options.even) components.$table.attr('lay-even', options.even);
 
        // 头部工具栏
        components.$toolbar.empty();
        if (options.toolbar === false || options.toolbar === undefined) {
   
   
            components.$toolbar.hide();
        } else {
   
   
            components.$toolbar.show();
            if (typeof options.toolbar === 'string') {
   
   
                laytpl($(options.toolbar).html()).render({
   
   }, function (html) {
   
   
                    components.$toolbar.html('<div style="display: inline-block;">' + html + '</div>');
                });
            }
            var tbRights = ['<div class="ew-tree-table-tool-right">'];
            for (var i = 0; i < options.defaultToolbar.length; i++) {
   
   
                var tbItem;
                if ('filter' === options.defaultToolbar[i]) {
   
   
                    tbItem = {
   
   title: '筛选', layEvent: 'LAYTABLE_COLS', icon: 'layui-icon-cols'};
                } else if ('exports' === options.defaultToolbar[i]) {
   
   
                    tbItem = {
   
   title: '导出', layEvent: 'LAYTABLE_EXPORT', icon: 'layui-icon-export'};
                } else if ('print' === options.defaultToolbar[i]) {
   
   
                    tbItem = {
   
   title: '打印', layEvent: 'LAYTABLE_PRINT', icon: 'layui-icon-print'};
                } else {
   
   
                    tbItem = options.defaultToolbar[i];
                }
                if (tbItem) {
   
   
                    tbRights.push('<div class="ew-tree-table-tool-item"');
                    tbRights.push(' title="' + tbItem.title + '"');
                    tbRights.push(' lay-event="' + tbItem.layEvent + '">');
                    tbRights.push('<i class="layui-icon ' + tbItem.icon + '"></i></div>');
                }
            }
            components.$toolbar.append(tbRights.join('') + '</div>');
        }
 
        // 固定宽度
        if (options.width) {
   
   
            components.$view.css('width', options.width);
            components.$tHeadGroup.css('width', options.width);
            components.$tBodyGroup.css('width', options.width);
        }
        // 表格尺寸设置
        var colgroupHtml = this.resize(true);
        // 生成thead
        var headHtml = '<thead>' + this.renderBodyTh() + '</thead>';
 
        // 渲染表头及空的表主体的结构
        components.$tBodyGroup.children('style').remove();
        if (options.height) {
   
     // 固定表头
            components.$tHead.html(colgroupHtml + headHtml);
            components.$tBody.html(colgroupHtml + '<tbody></tbody>');
            if (options.height.indexOf('full-') === 0) {
   
     // 差值高度
                var h = parseFloat(options.height.substring(5)) + components.$toolbar.outerHeight()
                    + components.$tHeadGroup.outerHeight() + 1;
                components.$tBodyGroup.append([
                    '<style>[lay-filter="', tbFilter, '"] .ew-tree-table-box {',
                    '   height: ', getPageHeight() - h, 'px;',
                    '   height: -moz-calc(100vh - ', h, 'px);',
                    '   height: -webkit-calc(100vh - ', h, 'px);',
                    '   height: calc(100vh - ', h, 'px);',
                    '}</style>'
                ].join(''));
                components.$tBodyGroup.data('full', h);
                components.$tBodyGroup.css('height', '');
            } else {
   
     // 固定高度
                components.$tBodyGroup.css('height', options.height);
                components.$tBodyGroup.data('full', '');
            }
            components.$tHeadGroup.show();
        } else {
   
   
            components.$tHeadGroup.hide();
            var trH = {
   
   lg: 50, sm: 30, md: 38};
            components.$tBodyGroup.append([
                '<style>[lay-filter="', tbFilter, '"] .ew-tree-table-box:before {',
                '   content: "";',
                '   position: absolute;',
                '   top: 0; left: 0; right: 0;',
                '   height: ' + (trH[options.size || 'md'] * options.cols.length) + 'px;',
                '   background-color: #f2f2f2;',
                '   border-bottom: 1px solid #e6e6e6;',
                '}</style>'
            ].join(''));
            components.$tBody.html(colgroupHtml + headHtml + '<tbody></tbody>');
        }
        form.render('checkbox', tbFilter);  // 渲染表头的表单元素
 
        // 默认隐藏列修正colspan
        function patchHide($tr) {
   
   
            var parentKey = $tr.data('parent'), pCol;
            if (!parentKey) return;
            var $parent = components.$table.children('thead').children('tr').children('[data-key="' + parentKey + '"]');
            var colspan = $parent.attr('colspan') - 1;
            $parent.attr('colspan', colspan);
            if (colspan === 0) $parent.addClass('layui-hide');
            patchHide($parent);
        }
 
        components.$table.children('thead').children('tr').children('th.layui-hide').each(function () {
   
   
            patchHide($(this));
        });
 
        // 渲染数据
        if (options.reqData) {
   
     // 异步加载
            this.options.data = undefined;
            this.renderBodyAsync();
        } else if (options.data && options.data.length > 0) {
   
   
            this.renderBodyData(options.data);
        } else {
   
   
            components.$loading.hide();
            components.$empty.show();
        }
    };
 
    /** 绑定各项事件 */
    TreeTable.prototype.bindEvents = function () {
   
   
        var that = this;
        var options = this.options;
        var components = this.getComponents();
        var $allBody = components.$table.children('tbody');
 
        /* 行事件公共返回对象 */
        var member = function (ext) {
   
   
            // 获取行dom
            var $tr = $(this);
            if (!$tr.is('tr')) {
   
   
                var $temp = $tr.parent('tr');
                if ($temp.length > 0) $tr = $temp;
                else $tr = $tr.parentsUntil('tr').last().parent();
            }
            var data = that.getDataByTr($tr);  // 行对应数据
            var obj = {
   
   
                tr: $tr,
                data: data,
                del: function () {
   
    // 删除行
                    var index = $tr.data('index');
                    var indent = parseInt($tr.data('indent'));
                    // 删除子级
                    $tr.nextAll('tr').each(function () {
   
   
                        if (parseInt($(this).data('indent')) <= indent) return false;
                        $(this).remove();
                    });
                    // 更新后面同辈的index
                    var indexLength = (typeof index === 'number' ? 1 : index.split('-').length);
                    $tr.nextAll('tr').each(function () {
   
   
                        var $this = $(this);
                        if (parseInt($this.data('indent')) < indent) return false;
                        var _index = $this.data('index').toString
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

ᥬ 小月亮

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

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

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

打赏作者

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

抵扣说明:

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

余额充值