相关文章推荐
淡定的茶壶  ·  Python经纬度-阿里云·  7 月前    · 
单身的人字拖  ·  fatal: Cannot get ...·  1 年前    · 
文武双全的刺猬  ·  ASP.NET ...·  1 年前    · 
对elementui表格组件进行二次封装

对elementui表格组件进行二次封装

elementui是我们在做vue项目时常用的组件库,但是这些组件库并不能满足我们的需求,因此我在我需要的情况下对表格组件进行了二次封装

父组件使用:

<cu-table 
 ref="videoTable"
            :columns="columns"
            :buttons="buttons"
            :searchItem="searchItem"
            @add-row="handlerAdd" // 表格头部按钮事件
            @del-row="handlerDel"
            @menuClick="menuClick"
            :requireUrl="requireUrl">
 <!-- <template slot="button">
                <el-button class="group-btn" type="primary" size="mini">xxx</el-button>
                <el-button class="group-btn" type="primary" size="mini">xxx</el-button>
            </template> -->
            <template v-slot:title=" { row }">
                <a href="#">{{row.title}}</a>
            </template>
            <template v-slot:opt="row">
                <el-dropdown trigger="click">
                    <span class="el-dropdown-link">
                        操作<i class="el-icon-arrow-down el-icon--right"></i>
                    </span>
                    <el-dropdown-menu slot="dropdown">
                        <el-dropdown-item @click.native="handlerEdit(row)">编辑</el-dropdown-item>
                        <el-dropdown-item @click.native="handlerDelete(row)">删除</el-dropdown-item>
                    </el-dropdown-menu>
                </el-dropdown>
            </template>
        </cu-table>
data() {
  return {
   requireUrl: 'back/videoList', //表格数据调用的接口
   columns: [
                    code: 'title',
                    label: '标题',
                    slot: 'title'  //是否排序
                    code: 'createTime',
                    label: '创建时间',
                    sort: true,
                    width: 200
                    code: 'auth',
                    label: '创建人'
                    code: 'updateTime',
                    label: '修改时间',
                    width: 200
                    code: 'url',
                    label: '播放地址',
                    width: 300
                    code: 'likeNum',
                    label: '点赞数',
                    sort: true
                    code: 'commentNum',
                    label: '评论数',
                    sort: true
                    code: 'shareNum',
                    label: '分享数',
                    sort: true
                    code: 'playNums',
                    label: '播放量',
                    sort: true
                    code: 'status',
                    label: '状态',
                    code: 'operation',
                    label: '操作',
                    fixed: 'right', // 固定栏
                    slot: 'opt' // 操作栏插槽
   buttons: ['add', 'del', 'frozen', 'thaw', 'export'], // 表格头部按钮,可利用插槽自定义
}


表格子组件:

<template>
    <div class="curstom-vue">
        <div style="display:flex;justify-content: space-between;align-items: center;">
            <div class="btn-group-box">
                <div v-if="buttons.length">
                    <span class="btn-span" v-for="btn in buttons" :key="btn" >
                        <el-button @click="add1" v-if="btn === 'add'" class="group-btn" type="primary" size="mini">增加</el-button>
                        <el-button @click="del1" v-if="btn === 'del'" class="group-btn" type="primary" size="mini">删除</el-button>
                        <el-button @click="frozen1" v-if="btn === 'frozen'" class="group-btn" type="primary" size="mini">冻结</el-button>
                        <el-button @click="thaw1" v-if="btn === 'thaw'" class="group-btn" type="primary" size="mini">解冻</el-button>
                        <el-button @click="export1" v-if="btn === 'export'" class="group-btn" type="primary" size="mini">导出</el-button>
                    </span>
                <div class="solt-btn">
                    <slot name="button"></slot>
            <header-search @search="search" :options="searchItem"></header-search>
        <el-table 
 class="vue-table"
            :data="tableData"
            :border="border"
            :stripe="stripe"
            @row-contextmenu="rightClick"
            @selection-change="selectChange">
            <el-table-column
 v-if="select"
 type="selection"
 width="55"
 fixed="left">
            </el-table-column>
            <el-table-column
 v-if="index"
 type="index"
 label="序号"
 width="55"
                :index="index">
            </el-table-column>
            <template v-for="(column, index) in columns">
 <!-- <slot  v-if="column.slot"  :name="column.slot"></slot> -->
                <el-table-column v-if="column.slot"
                    :key="'index-'+index"
                    :label="column.label"
                    :width="column.width"
                    :sortable="column.sort"
                    :fixed="column.fixed">
                    <template slot-scope="scope">
                        <slot :row="scope.row" :name="column.slot">{{scope.row.title}}</slot>
                    </template>
                </el-table-column>
                <el-table-column v-else-if="column.code !== 'operation'"
                    :key=index
                    :prop="column.code"
                    :label="column.label"
                    :width="column.width"
                    :sortable="column.sort"
                    :fixed="column.fixed">
                </el-table-column>
                <el-table-column v-else-if="column.code === 'operation'"
                    :key=index
                    :prop="column.code"
                    :label="column.label"
                    :width="column.width"
                    :fixed="column.fixed">
                    <template slot-scope="scope">
                        <template slot-scope="scope" v-if="column.slot">
                            <slot :row="scope" :name="column.slot">{{scope}}</slot>
                        </template>
                        <el-dropdown trigger="click">
                            <span class="el-dropdown-link">
                                操作<i class="el-icon-arrow-down el-icon--right"></i>
                            </span>
                            <el-dropdown-menu slot="dropdown">
                                <el-dropdown-item @click.native="handlerEdit(scope)">编辑</el-dropdown-item>
                                <el-dropdown-item @click.native="handlerDelete(scope)">删除</el-dropdown-item>
                            </el-dropdown-menu>
                        </el-dropdown>
                    </template>
                </el-table-column>
            </template>
            <template slot="empty">
                    <img src="./../assets/images/noData.png" alt="" srcset="">
            </template>
        </el-table>
        <div id="menu" ref="rightMenu">
            <div class="menu" v-for="item in menus" :key="item" @click.stop="infoClick(item)">{{item.label}}</div>
        <el-pagination
            @size-change="handleSizeChange"
            @current-change="handleCurrentChange"
            :page-sizes="[2, 10, 20, 50]"
 layout="total, sizes, prev, pager, next"
            :total="total">
        </el-pagination>
</template>
<script>
import HearderSearch from './headerSearch'
import * as API from './../api/index'
export default {
 name: 'Table',
 props: {
 columns: { 
 type: Array,
 default: () => {
 return []
 border: {
 type: Boolean,
 default: true
 tableData: {
 type: Array,
 default: () => {
 return []
 buttons: {
 type: Array,
 default: () => {
 return []
 select: {
 type: Boolean,
 default: true
 index: {
 type: Boolean,
 default: true
 stripe: {
 type: Boolean,
 default: true
 menus: {
 type: Array,
 default: () => {
 return [{
 code: 'edit',
 label: '编辑'
 code: 'del',
 label: '删除'
 searchItem: {
 type: Array
 requireUrl: {
 type: String,
 default: ''
 data() {
 return {
 currentRowIndex : 0,
 showMenu: false,
 rowData: {},
 activeName: '1',
 tableParams: {
 limit: 1,
 offset: 10
 total: 0,
 selectData: []
 created() {
 components: {
 'header-search': HearderSearch
 mounted() {
        document.addEventListener('click', () => {
 const menu = document.querySelector("#menu");
            menu.style.display = 'none';
 this.getData();
 methods: {
 // 查询数据
 getData() {
 API.GET(this.requireUrl, this.tableParams).then(res => {
 this.tableData = res.data;
 this.total = res.total;
 selectChange(val) {
 this.selectData = val;
 search(item) {
 alert(22);
            console.log(item)
 handlerEdit(item) {
            console.log(item);
            console.log('edit');
 handlerDelete(item) {
            console.log(item);
            console.log('delete');
 add1() {
 this.$emit('add-row');
 del1() {
 this.$emit('del-row', this.selectData);
 frozen1() {
 this.$emit('frozen-row');
 thaw1() {
 this.$emit('thaw-row');
 export1() {
 this.$emit('export-row');
 // 自定义菜单的点击事件
 infoClick(item) {
 this.$emit('menuClick', {item, row: this.rowData});
 // table的右键点击当前行事件
 rightClick(row, column, event) {
 const menu = document.querySelector("#menu");
            event.preventDefault();
 //获取我们自定义的右键菜单
 // 根据事件对象中鼠标点击的位置,进行定位
            menu.style.left = event.clientX + 'px';
            menu.style.top = event.clientY + 'px';
 // 改变自定义菜单的隐藏与显示
            menu.style.display = 'block';
 this.rowData = row;
 handleSizeChange(val) {
 // console.log(`每页 ${val} 条`);
 this.tableParams.offset = val;
 this.getData();
 handleCurrentChange(val) {
 // console.log(`当前页: ${val}`);
 this.tableParams.limit = val;
 this.getData();
</script>
<style lang='scss'>
.curstom-vue {
    height: 100%;
    display: flex;
    flex-direction: column;
 .btn-group-box {
        display: flex;
 .solt-btn .el-button:nth-child(n+2){
            margin-left: 0.1rem;
 .btn-span:nth-child(n+2) {
        margin-left: 0.1rem;
 .btn-span:last-child {
        margin-right: 0.1rem;
 .vue-table {
        margin-top: 0.1rem;
 .el-dropdown-link {
 cursor: pointer;
        color: #409EFF;
 .el-icon-arrow-down {
        font-size: 12px;
 #menu { 
        border-radius: 5px;
        overflow: hidden; /*隐藏溢出的元素*/
        box-shadow: 0 1px 1px #888, 1px 0 1px #ccc;
        position: absolute; 
        display: none;
        background: #ffffff;
        z-index: 10;
        padding-bottom: 10px;
        background: #ccc;
 .menu {
        width: 125px;
        height: 25px;
        line-height: 25px;
        text-indent: 10px;
 cursor: pointer;
 .menu:hover {
        color: deeppink;
        text-decoration: underline;
 .is-scrolling-none {
        height: 100%;
</style>

搜索栏子组件:

<template>
    <div class="hearder-search">
        <el-select style="width:100px" v-model="value" clearable placeholder="请选择" size="mini" @change="changeItem">
            <el-option
 v-for="item in options"
            :key="item.value"
            :label="item.label"
            :value="item.value"
 size="mini">
            </el-option>
        </el-select>
        <div class="input" v-if="!type">
            <el-input size="mini" style="width:200px" v-model="searchValue" placeholder="请输入内容"></el-input>
        <div class="dateTime" v-else-if="type === 'dateTime'">
            <el-date-picker
 size="mini"
 v-model="dateTime"
 type="datetimerange"
 range-separator="至"
 start-placeholder="开始日期"
 end-placeholder="结束日期"
 value-format="yyyy-MM-dd HH:mm:ss"
 align="right"
                @change="changeDateTime">
            </el-date-picker>
        <div class="num" v-else-if="type === 'range'">
            <div class="range-num">
                <el-input size="mini" style="width:100px" v-model="range1" placeholder="请输入内容"></el-input> 至
                <el-input size="mini" style="width:100px" v-model="range2" placeholder="请输入内容"></el-input>
        <el-button @click="search" style="margin-left:10px" type="primary" icon="el-icon-search" size="mini">搜索</el-button>
</template>
<script>
export default {
 name: 'HeaderSearch',
 props: {
 options: {
 type: Array
 data() {
 return {
 searchValue: '',
 value: '',
 dateTime: '',
 type: '',
 range1: '',
 range2: ''
 computed: {
 methods: {
 changeItem(item) {
 const type = this.options.find(val => val.value === item);
 this.type = type.type;
 changeDateTime(item) {
            console.log(item)
 search() {
 if (!this.value) {
 this.$message({
 message: '请输入搜索类型',
 type: 'warning'
            } else {
 this.$emit('search', {
 type: this.value,
 value: this.searchValue
</script>
<style lang='scss'>
.hearder-search {
    display: flex;
 .el-select {
 .el-input__inner {
 // border-right: none;
            border-top-left-radius: 4px;
            border-bottom-left-radius: 4px;
            border-top-right-radius: 0;
            border-bottom-right-radius: 0;
 .input {
 .el-input__inner {
            border-left: none;
            border-top-left-radius: 0;
            border-bottom-left-radius: 0;
            border-top-right-radius: 4px;
            border-bottom-right-radius: 4px;
 .dateTime {
 .el-input__inner {
            border-left: none;
            border-top-left-radius: 0;
            border-bottom-left-radius: 0;
            border-top-right-radius: 4px;
            border-bottom-right-radius: 4px;
 .num {
 .range-num {
            box-sizing: content-box;
            border: 1px solid #DCDFE6;
            border-left: none;
            border-top-left-radius: 0;
            border-bottom-left-radius: 0;
            border-top-right-radius: 4px;
            border-bottom-right-radius: 4px;
            background: #fff;
 .el-input__inner {
                border: none;