vue-table-demo

43 阅读1分钟
<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>

// 状态管理器
class TableStore {
    constructor(){
        this.states = {
            data: null, //table的数据
            columns: [] //table的列定义
        }
    }
    commit(name, ...args){
        this.mutations[name].apply(this, [this.states].concat(args))
    }
}
TableStore.prototype.mutations = {
    setData(states, data) {
        states.data = data
    },
    insertColumn(states, column) {
        states.columns.push(column)
    }
}
// el-table组件
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'],
    data(){
        return {
            store: new TableStore() //状态管理器
        }
    },
    watch: {
        data: {
            immediate: true,
            handler(value) {
                // 将data添加到状态管理器中,供 table-body 使用
                this.store.commit('setData', value)
            }
        }
    }
})
// table-header组件
Vue.component('table-header',{
    props: ['store'],
    computed: {
        columns() { //获取状态管理器中的列定义
            return this.store.states.columns;
        }
    },
    render(createElement) { //通过createElement创建vNode
        return createElement('table',{class: {'el-table__header': true}}, [
            createElement('thead', 
                this.columns.map(column=>{
                    return createElement('th',[createElement('div',column.label)])
                })
            )
        ])
    }
})
// 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
        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})])
                }))
            })
        )
    },
})
//el-table-column
Vue.component('el-table-column',{
    template: `<div class="ttt"></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;
        console.log(_self);
        // 生成列的渲染方法
        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>*/
            }
            return createElement('div', {
                'class': {
                    cell: true
                }
            },renderCell())
        }
        this.columnConfig = column
    },
    mounted(){
        // 将列定义添加到状态管理器中,供 table-body table-header 使用
        this.owner.store.commit('insertColumn', this.columnConfig)
    }
})
var vm = new Vue({
    el: '#app',
    data: {
        tableData: [{
            name: '张三',
            address: '成都市青羊区清源路1号'
        }, {
            name: '李四',
            address: '成都市青羊区清源路2号'
        }]
    }
})
</script>