layui中实现动态的cols表头字段

本文介绍了在layui中如何实现动态表头和处理后端返回的动态数据。通过在table.render之前先请求接口获取数据并处理,然后直接设置cols属性,实现了动态列展示。同时,利用反射工具类处理不确定属性数量的对象,以便前端能根据cols自动匹配数据。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

需求确定

最近再搞一个需求时,需要在layui中实现表头字段的动态更新,无奈转战前端阵营
来一波官方文档先,个人感觉还是挺简单易懂的
https://www.layui.com/doc/
再来个在线演示网站
https://www.layui.com/demo/table/height.html

修改前

layui.render中默认调用的接口的返回值是集合类型,所以根据一一匹配的原则可以快速的生成表头和表数据。但如果我们的表头是动态生成的,那就有些麻烦了,这里要涉及到表头的数据以及表格的数据。
原来是这样的

layui.use('table', function() {
    var table = layui.table;

    table.render({
        elem: '#tableList'
        , url: '/web/aliyunOSSMetric/query?day=' + day + '&company=' + company
        , toolbar: true
        , height: 'full-330'
        , cols: [
            [
                 {field: 'bucket', width: 420, title: 'bucket' }
                ,{ title:'操作', toolbar: '#tableListAction', width:120}
                , {field: 'companyName', width: 150, title: '厂商', sort: true}
                , {field: 'value', width: 200, title: '流量(TB)', sort: true}
                , {field: 'percent', width: 200, title: '比例', sort: true}
            ]
        ]
    });
});

修改后

parseData方法

在table中,我们可以关注到一个异步回调函数parseData,能够对回调的数据进行一些处理,例如将数据格式化。本来我也打算用这个来渲染cols的,但是这个是在数据返回之后的,cols已经在该方法之前便生效了,所以只能另辟蹊径
在这里插入图片描述

done函数

同理,done函数也能做一些事情,但是cols也已经在该函数前便已生效
在这里插入图片描述

解决方案

在render方法之前,先请求接口获取数据,并可以处理成想要的格式,在render中直接对cols直接赋值就可以了

layui.use('table', function() {
    let table = layui.table;
    let cols = []
    let col = []
    $.ajax({
        type: 'POST',
        url: '/web/aliyunOSSMetric/getCols?day=' + end + '&buckets=' + '&company=' + company,
        dataType: "JSON",
        sync: false,
        contentType: "application/json",
        success: function (res) {
            col.push({field: 'bucket', width: 420, title: 'bucket',merge: true});
            col.push({title:'操作', toolbar: '#tableListAction', width:120});
            col.push({field: 'companyName', width: 150, title: '厂商', sort: true, rowspan: 1});
            $.each(res.data, function (index, obj) {
                col.push({field: obj, width: 200, title: obj, sort: true, rowspan: 1});
            });
            col.push({field: 'percent', width: 200, title: '比例', sort: true, rowspan: 1});
            cols.push(col);

            table.render({
                elem: '#tableList'
                ,
                url: '/web/aliyunOSSMetric/query?day=' + end + '&company=' + company
                ,
                toolbar: true
                ,
                height: 'full-330'
                ,
                cols: cols
            });
        }
    });
});

那么我们会想到,cols是不固定的,那么后端返回的集合类型的每个元素的属性数量也是不固定的
针对后端的返回类型,我们可以抽象为Object集合
针对每个Object,我们可以通过动态的改变业务对象的属性数量,再将业务对象转成json对象,再向上转型成Object对象
具体如下:

先创建工具类
import com.google.common.collect.Maps;
import net.sf.cglib.beans.BeanGenerator;
import net.sf.cglib.beans.BeanMap;
import org.apache.commons.beanutils.PropertyUtilsBean;

import java.beans.PropertyDescriptor;
import java.util.Map;

/**
 * @author junfeng.lin
 * @date 2021/9/2
 */
public class ReflectUtil {
    public static Object getTarget(Object dest, Map<String, Object> addProperties) {
        PropertyUtilsBean propertyUtilsBean =new PropertyUtilsBean();
        PropertyDescriptor[] descriptors = propertyUtilsBean.getPropertyDescriptors(dest);
        Map<String, Class> propertyMap = Maps.newHashMap();
        for(PropertyDescriptor d : descriptors) {
            if(!"class".equalsIgnoreCase(d.getName())) {
                propertyMap.put(d.getName(), d.getPropertyType());
            }
        }
        // add extra properties
        addProperties.forEach((k, v) -> propertyMap.put(k, v.getClass()));
        // new dynamic bean
        DynamicBean dynamicBean =new DynamicBean(dest.getClass(), propertyMap);
        // add old value
        propertyMap.forEach((k, v) -> {
            try{
                // filter extra properties
                if(!addProperties.containsKey(k)) {
                    dynamicBean.setValue(k, propertyUtilsBean.getNestedProperty(dest, k));
                }
            }catch (Exception e) {
                e.printStackTrace();
            }
        });
        // add extra value
        addProperties.forEach((k, v) -> {
            try{
                dynamicBean.setValue(k, v);
            }catch (Exception e) {
                e.printStackTrace();
            }
        });
        Object target = dynamicBean.getTarget();
        return target;
    }

    public static class DynamicBean {
        /**
         * 目标对象
         */
        private Object target;

        /**
         * 属性集合
         */
        private BeanMap beanMap;

        public DynamicBean(Class superclass, Map<String, Class> propertyMap) {
            this.target = generateBean(superclass, propertyMap);
            this.beanMap = BeanMap.create(this.target);
        }


        /**
         * bean 添加属性和值
         *
         * @param property
         * @param value
         */
        public void setValue(String property, Object value) {
            beanMap.put(property, value);
        }

        /**
         * 获取属性值
         *
         * @param property
         * @return
         */
        public Object getValue(String property) {
            return beanMap.get(property);
        }

        /**
         * 获取对象
         *
         * @return
         */
        public Object getTarget() {
            return this.target;
        }


        /**
         * 根据属性生成对象
         *
         * @param superclass
         * @param propertyMap
         * @return
         */
        private Object generateBean(Class superclass, Map<String, Class> propertyMap) {
            BeanGenerator generator =new BeanGenerator();
            if(null != superclass) {
                generator.setSuperclass(superclass);
            }
            BeanGenerator.addProperties(generator, propertyMap);
            return generator.create();
        }
    }
}

处理逻辑

service层进行处理

	Map<String,Object> properties = Maps.newHashMap();
	//动态添加属性,其中第一个参数是属性名,第二个参数是属性值
   	properties.put(ossMetric.getName(), entity.getValue());
    ObjectMapper mapper = new ObjectMapper();
    //先转成JSON对象
    String json = mapper.writeValueAsString(ReflectUtil.getTarget(vo,properties));	//其中vo是具体的业务对象
    //再将JSON对象转成实体类,由于不知道具体的属性值是怎么样的,所以向上转型用Object接收
    Object ossMetricVo = JSONObject.parseObject(json, Object.class);

最后在controller中直接将Object数组返回给前端就可以了
controller中的伪代码

@RequestMapping("/aliyunOSSMetric/query")
    public Map<String,Object> queryByDay(@RequestParam(name = "day") String day,
                                         @RequestParam(name = "company") String company
    ) throws InvocationTargetException, JsonProcessingException {
        Map<String,Object> res = new HashMap<>();
        List<Object> data = service.query(day, company);
        res.put("code", 0);
        res.put("msg", "");
        res.put("count", data .size());
        res.put("data", data);
        return res;
    }

如此,前端就能根据cols中的属性名自动匹配到data中对象的属性名了,大功告成!

### layui 表格模块 `cols` 属性详解 在 LayUI 的表格组件中,`cols` 是用于定义表格列结构的核心属性之一。它接受一个二维数组作为其值,每一维代表一组表头配置项。以下是关于 `cols` 属性的具体说明以及如何结合其他功能使用的示例。 #### 基本语法 `cols` 属性的值是一个嵌套数组,外层数组可以包含多个子数组,每个子数组对应一栏或多栏的表头分组。如果只需要简单的单级表头,则只需提供一层子数组即可[^1]。 ```javascript table.render({ elem: '#test', height: 312, url: '/demo/table/user/', // 数据接口地址 page: true, // 开启分页 cols: [[ // 列字段设置 {field:'id', title:'ID', width:80}, {field:'username', title:'用户名', width:120} ]] }); ``` 上述代码片段展示了最基本的 `cols` 配置方式,其中每列表头由对象组成,常见的键有: - **field**: 对应数据源中的字段名。 - **title**: 显示在表头的文字描述。 - **width**: 定义该列宽度(单位像素或百分比)。 - **templet**: 自定义单元格内容渲染模板函数^。 #### 复杂场景下的应用实例 当遇到复杂情况比如展示关联数据或者格式化特定类型的数据时,可以通过自定义模板完成更灵活的内容呈现。例如处理学生选课信息并将其转换成易读形式: ```javascript table.render({ elem: '#studentInfoTable', data: studentDataList, cols: [[ { field: 'name', title: '姓名', width: 150 }, { field: 'courses', title: '已选课程', templet: function(d){ var courseNames = d.courses.map(function(courseId){ return getCourseNameById(courseId); }).join(", "); return "<span>" + (courseNames || '-') + "</span>"; }, width: 300 } ]], }); function getCourseNameById(id) { let coursesMap = {"C001":"高等数学","C002":"大学英语"}; return coursesMap[id]; } ``` 这里利用了 `templet` 来动态获取和拼接字符串从而达到美化输出的目的^。 另外,在某些情况下可能还需要加载外部资源如图片等媒体文件至表格内部节点位置处。此时同样依赖于 `templet` 方法配合 HTML 片段注入操作达成目标效果[^3]^: ```javascript { field: 'avatarUrl', title: '头像预览', templet: '<div><img src="{{d.avatarUrl}}" style="height:40px;"></div>', width: 100 } ``` #### 文件上传联动刷新表格视图 对于涉及文件管理类业务逻辑的应用程序而言,通常会涉及到文件上传之后重新拉取最新资料更新当前页面上的表格展现状态这一流程。这时就可以借助 JavaScript 函数封装统一调用机制简化重复动作执行过程[^4]^: ```javascript // 封装表格重载方法 function tableDoReload(){ table.reload('exampleTable'); } upload.render({ elem: '#uploadBtn' ,url: '/api/uploadFile' ,method: 'POST' ,done: function(res){ console.log(res); if(res.code === 0){ layer.msg('上传成功!'); tableDoReload(); }else{ layer.alert(res.message); } } }); ``` 以上即为有关 layUI framework 下 table 组件内 cols 参数较为详尽的功能解析及其实际应用场景举例演示部分。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值