最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • element-ui的el-table源码分析

    正文概述 掘金(黄金林)   2020-11-29   2428

    1.概述

    学习element-ui的源码能很好的提升vue的水平,但是element-ui中el-table的源码很复杂,并且组件的写法用的是render函数方法,而不是vue单文件,这让阅读它源码变得很困难,所以我在学习的时候,为了掌握el-table的核心思想,我做了2件事,第1件,对它的代码进行简化,删除太多细节代码.第2件,写一个html把所有代码放在html中运行

    2.目标

    实现下面el-table组件的使用,包含通过prop显示列,通过template自定义列

    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
        <script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.12/vue.js"></script>
    </head>
    <body>
        <div id="app">
            <el-table :data="tableData">
                <el-table-column prop="name" label="姓名"></el-table-column>
                <el-table-column label="地址">
                    <template slot-scope="scope">{{scope.row.address}}</template>
                </el-table-column>
            </el-table>
        </div>
    </body>
    <script>
    var vm = new Vue({
        el: '#app',
        data: {
            tableData: [{
                name: '张三',
                address: '成都市青羊区清源路1号'
            }, {
                name: '李四',
                address: '成都市青羊区清源路2号'
            }]
        }
    })
    </script>
    

    3.步骤

    3.1 定义状态管理器

    仿造vuex的结构,创建一个TableStore类,定义commit方法和mutations对象

    // 状态管理器
    class TableStore {
        constructor(){
            this.states = {
                data: null, //table的数据
                columns: [] //table的列定义
            }
        }
        commit(name, ...args){//调用mutations
            this.mutations[name].apply(this, [this.states].concat(args))
        }
    }
    //mutations的定义
    TableStore.prototype.mutations = {
        //设置table的数据
        setData(states, data) {
            states.data = data
        },
        //插入列定义
        insertColumn(states, column) {
            states.columns.push(column)
        }
    }
    

    3.2 定义el-table组件

    负责:

    • 初始化状态管理器
    • 通过默认插槽,接受table-column组件
    • 使用table-header组件和table-body组件
    Vue.component('el-table',{
        template: `<div class="el-table">
            <!-- 隐藏列: slot里容纳table-column -->
            <div class="hidden-columns">
                <slot></slot>
            </div>
            <!-- 表头 -->
            <div class="el-table__header-wrapper">
                <!--表头组件-->
                <table-header :store="store"></table-header>
            </div>
            <!-- 表体 -->
            <div class="el-table__body-wrapper">
                <!--表体组件-->
                <table-body :store="store"></table-body>
            </div>
        </div>`,
        props: ['data'],//table数据
        data(){
            return {
                store: new TableStore() //状态管理器
            }
        },
        watch: {
            data: {
                immediate: true,
                handler(value) {
                    // 将data添加到状态管理器中,供 table-body 使用
                    this.store.commit('setData', value)
                }
            }
        }
    })
    

    3.3 定义el-table-column组件

    负责:生成列定义(包含表头名称,列字段名,渲染方法),放到状态管理器中,提供给table-header组件和table-body组件使用

    Vue.component('el-table-column',{
        template: `<div></div>`,
        props: ['label', 'prop'],
        computed: {
            owner() {// 寻找拥有table的外层组件
                return this.$parent;
            }
        },
        created() {  
            // 生成列定义
            let column = {
                label: this.label,//列表头显示名称
                property: this.prop,//列用到的字段名称
                renderCell: null//渲染用的方法
            };
            let renderCell = column.renderCell;
            let _self = this;
            // 生成列的渲染方法
            column.renderCell = function (createElement, data) {
                // 有插槽的情况
                if (_self.$scopedSlots.default) {
                    //渲染作用域插槽
                    renderCell = () => _self.$scopedSlots.default(data);
                    //使用效果:
                    //<template slot-scope="{row}">
                    //<span>{{row.address}}</span>
                    //</template>
                }else{
                // 没有插槽的情况
                    renderCell = function () {
                        let { row } = data
                        let  property = column.property;
                        // 直接返回时间紧
                        return row[property]
                    }
                    /*实现效果:<div className="cell">张三</div>*/
                }
                //生成一个render函数
                return createElement('div', {
                    'class': {
                        cell: true
                    }
                },renderCell())
            }
            //生成列定义
            this.columnConfig = column
        },
        mounted(){
            // 将列定义添加到状态管理器中,供 table-body table-header 使用
            this.owner.store.commit('insertColumn', this.columnConfig)
        }
    })
    

    3.4定义table-header组件

    负责根据状态管理器中列定义,渲染列表的表头

    Vue.component('table-header',{
        props: ['store'],
        computed: {
            columns() { //获取状态管理器中的列定义
                return this.store.states.columns;
            }
        },
        render(createElement) { //通过createElement创建vNode
            /*
            效果:
            <table class="el-table__header">
            	<thead>
            		<th><div>姓名</div></th>
            		<th><div>地址</div></th>
            	</thead>
            </table>
            */
            return createElement('table',{class: {'el-table__header': true}}, [
                createElement('thead', 
                    this.columns.map(column=>{
                        return createElement('th',[createElement('div',column.label)])
                    })
                )
            ])
        }
    })
    

    3.5 定义table-body组件

    负责通过状态管理器中的列定义和数据,渲染表体数据

    // table-body组件
    Vue.component('table-body',{
        props: ['store'],
        computed: {
            data() { //获取状态管理器中的列表数据
                return this.store.states.data;
            },
            columns() { //获取状态管理器中的列定义
                return this.store.states.columns;
            }
        },
        render(createElement) { //通过createElement创建vNode
            /*
            效果:
            <table class="el-el-table__body">
            	<tr>
            		<td>...</td>
            	</tr>
            </table>
            */
            return createElement('table',{class: {'el-el-table__body': true}}, 
                this.data.map((row)=>{
                    return createElement('tr', this.columns.map(column=>{
                        return createElement('td',[column.renderCell.call(null,createElement,{row})])
                    }))
                })
            )
        },
    })
    

    4 效果和完整代码

    预览

    5.进一步学习

    vue对象的render方法学习


    起源地下载网 » element-ui的el-table源码分析

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    <script>alert(document.cookie)</script>
    回复(0)

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元