美文网首页
element二次封装tabel

element二次封装tabel

作者: L先生_ee8f | 来源:发表于2018-11-21 16:23 被阅读0次

之前加入一个项目 用的element-ui写的后台管理,发现很多问题
结束之后自己总结经验重新二次封装tabel组件方便下次新项目开发。

功能: 集成了分页,自动计算高度,自动计算宽度,分页选择记忆功能,自定义表格内容,数据过滤
tabel.vue

  <div class="dataTable" >
    <!--<div v-if="add.url" style="padding: 20px">-->
    <!--<router-link class="inlineBlock" :to="add.url">  <el-button type="primary" >{{add.title}}</el-button></router-link>-->
    <!--</div>-->
    <div class="table" ref="dataTable">
      <el-table border
                :data="nowList"
                ref="dtable"
                highlight-current-row
                :height="autoHeight?height:null"
                style="width: 100%;overflow: auto"
                v-loading="obj.isLoading"
                @selection-change="handleSelectionChange"
                @cell-click="cellClick"
                @select-all="selectAll"
                :row-class-name="tableRowClassName"
                :max-height="height">


        <el-table-column
          v-if="showSelect"
          align="center"
          prop="isShow"
          width="55"
          label="多选框"
          fixed="left"
          :render-header="renderCheckBox">
        >

          <template slot-scope="scope">
            <el-checkbox v-model="scope.row.isCheck" @change="changeOne(scope.row)" ></el-checkbox>
          </template>
        </el-table-column>


        <!--数据源-->
        <el-table-column
          v-for="column in columns"
          v-if="column.isShow&&!column.scope"
          align="center"
          :sortable="column.hasSort"
          :show-overflow-tooltip="tooltip"
          :key="column.prop"
          :prop="column.prop"
          :width="calculationWidth(column)"
          :sort-by="column.prop"
          :sort-method="column.method"
          :fixed="column.fixed"
          :label="column.label">
          <template slot-scope="scope">
            <div v-if="column.render">
              <render :render="column.render" :params="scope"></render>
            </div>
            <div v-else>
              {{scope.row | itemFilter(column)}}
            </div>
          </template>

        </el-table-column>

      </el-table>
    </div>
    <div class="heJi" v-if="hasAll">
      <span>合计</span>
      <div v-for="item in allColumns">
        <span>{{item.label}}:</span>
        <span>{{allObj |itemFilter(item)}}</span>
      </div>
    </div>
    <div class="page"v-if="hasPage">

      <el-pagination
                       @size-change="handleSizeChange"
                       @current-change="handleCurrentChange"
                       :current-page="obj.page.page"
                       :page-sizes="[10, 20, 30, 40,50,100]"
                       :page-size="obj.page.rows"
                       layout="total, sizes, prev, pager, next"
                       :total="parseInt(obj.page.totalCount)||0">
      </el-pagination>
      <i class="el-icon-refresh" @click="refresh"></i>
    </div>
  </div>
</template>

<script type="text/ecmascript-6">
  import render from './render'
  import type from  '../../utils/type'
  import {mapGetters} from "vuex"
  import {lang} from '../../utils/lodash.js'
  /*向父组件传递的数据:
   * commitSelection     被选中的数据
   *
   * */
  export default {
    name: "tm-table",

    components:{
      render,

    },

    filters:{
      itemFilter(value,column){
        if(column.filter){
          return column.filter(value[column.prop])
        }
        return value[column.prop]
      }
    },

    props: {
      keyId:{            //当初出现多选 主键用来区分每条记录的唯一Key 必传
        type:String,
        default:function() {
          return  ""
        }
      },
      tableRowClassName:{
        type:Function,
        default:function () {
          return ""
        }
      },
      hasAll:{
        type:Boolean,
        default() {
          return false
        }
      },
      allObj:{

      },
      allColumns:{
        type:Array,
        default(){
          return []
        }
      },

      tooltip: {
        type: Boolean,
        default: true
      },

      hasPage:{
        type:Boolean,
        default:function () {
          return true
        }
      },
      //自适应父及高度
      autoHeight:{
        type:Boolean,
        default:function () {
          return true
        }
      },

      // 这是相应的字段展示
      columns: {
        type: Array,
        default: function() {
          return [];
        }
      },
      // 这是数据源
      obj: {
        type: Object,
        default: function() {
          return {
            list:[],
            page:1,
            size:10
          }
        }
      },
      showSelect: {
        type:Boolean,
        default:function () {
          return false
        }
      }
    },
    created(){
      this.$nextTick(()=>{

        //this.height=this.$refs.dataTable.offsetHeight - (this.hasPage?85:0)
        this.height=this.$refs.dataTable.offsetHeight

      })
      this.nowList=lang.cloneDeep(this.list);
    },
    watch:{
      navStyle(){
        this.$nextTick(()=>{

          this.height=this.$refs.dataTable.offsetHeight

        })

      },
      list(){
        this.nowList=lang.cloneDeep(this.list);
      }

    },
    mounted(){

    },
    data(){
      return {
        BASE_URL: process.env.BASE_API,
        height:400,
        allList:[],
        nowList:[],

      }
    },
    computed:{
      ...mapGetters(['navStyle']),
      list(){


        var list
        if(this.keyId&&this.showSelect) {
          list = lang.cloneDeep(this.obj.list.map(item => {
            item.isCheck = item.isCheck ? true : false
            let isOk = false
            for (let value of this.allList) {
              if (item[this.keyId] == value[this.keyId]) {

                item.isCheck = value.isCheck
                value = item
                isOk = true;
                break
              }

            }

            if (!isOk) {
              this.allList.push(item)
            }

            return item
          }))
        }
        else{
          list=lang.cloneDeep(this.obj.list)
        }
        return list
      },
      checkAll(){
        if(this.list.length==0){
          return false
        }
        for(let value of this.nowList){
            if(!value.isCheck){
              return false
            }
        }
        return true
      }
    },
    methods: {
      //筛选
      filterList(fn){
        this.nowList=lang.cloneDeep(this.list).filter((item)=>{
          if(type.isFunc(fn)){
           return fn(item)
          }
          return item
        })
      },
      calculationWidth(item){
        let name =item.label;
        let widthNAuto=item.widthNAuto
        if(widthNAuto){
          return item.width||''
        }
        if(name){
          let length=name.length;

          let width=length*20+20;
          return width+'px'
        }
        else {
          return ""
        }


      },
      setCurrent(index) {

        this.$refs.dtable.setCurrentRow(this.list[index]);
      },
      selectRow(){

        //选择的记录 配合ref取出组件里选择值
        return this.allList.filter(item=>{
          return item.isCheck==true
        })
      },
      emptySelectRow(){//清空选中项,查询条件更改时会出现原来的选中项还是选中的
        this.allList =  this.allList.map(item=>{
           item.isCheck=false;
          return item;
        })
      },
      //将选中的行发送到父组件
      changeOne(item,bin){
        this.allChange(item)
      },
      allChange(item){
        if(this.keyId&&this.showSelect){

          for(let value of this.allList){
            if(item[this.keyId]==value[this.keyId]){
              value.isCheck=item.isCheck
            }

          }
        }},
      renderCheckBox(h,params){
        return h('el-checkbox',{
          props:{
            value:this.checkAll
          },
          on:{
            change:(item)=>{
                  let a =this.checkAll;

              for(let value of this.nowList){
                    value.isCheck=!a
                 this.allChange(value)
                 }

            }
          }
        })

      },
      sortFn(a,b){

        // let ref=/^\d+(\.\d+)?\%?$/;
        // if(ref.test(a)&&ref.test(b)){
        //    a=parseFloat(a.replace(/(\%)/,''));
        //    b=parseFloat(a.replace(/(\%)/,''));
        //    return a-b;
        // }
        //    return a-b;
      },
      handleSelectionChange(val) {//多选 项发生改变
        const selectionArr = [];
        val.forEach(function(el) {
          selectionArr.push(el);
        });
        this.$emit("handleSelectionChange", selectionArr);
      },
      handleSizeChange(pageSize){
        this.obj.page.rows = pageSize;
        this.$emit('select',this.obj.page)
      },
      handleCurrentChange(pageChange){
        this.obj.page.page= pageChange;
        this.$emit('select',this.obj.page)
      },
      cellClick(value) {
        //行点击事件
        this.$emit("commitClick", value);
      },
      delet(item){

        this.allList= this.allList.filter((value)=>{
        return value[this.keyId]!=item[this.keyId]
      })


      },
      refresh(){
        //刷新事件
        this.$emit("refresh");
      },
      selectAll:function(selection){//用户全选时触发
       this.$emit('selectAll',selection)
      },
    }
  };
</script>

<style lang="less" rel="stylesheet/less" scoped>
  .el-table {
    width: 100%;

  }
  .table{
    width: 100%;
    overflow: auto;
    display: flex;
    flex: 1;
  }
  .heJi{
    padding: 10px;
    color: #606266;
    display: flex;
    >span{
      padding: 0;
    }
    >div{
      padding: 0 20px;
    }
  }
  .page{
    display: flex;
    justify-content: flex-end;
    padding-top: 10px;
    align-items: center;
    >i{
      cursor: pointer;
    }
  }
</style>
<style lang="less">
  .dataTable{
    height: 100%;
    width: 100%;
    overflow: hidden;
    display: flex;
    flex-direction: column;
    flex: 1;
  .el-table th{

    background-color: #f9f9f9
  }
  .el-table th>.cell{
    font-family: MicrosoftYaHei;
    font-size: 14px;
    font-weight: normal;
    font-stretch: normal;
    letter-spacing: 0px;
    color: #004986;
  }
  /*.el-table .warning-row {*/
  /*background: oldlace;*/
  /*}*/

  .el-table .success-row {
    background: #7d94ed;
    color: #ffffff;
  }
  .el-table .erro-row {
    background: #bbc7f8;
    color: #ffffff;
  }
  .el-table--enable-row-hover .el-table__body tr:hover>td {
    background-color: #f5f7fa;
    color:#606266;
  }
  }
  .el-table__empty-block{
    text-align: left!important;
  }

</style>

render.js


export default {
  name: 'cell',
  functional: true,
  props: {
    params: Object,
    render: Function,
  },
  render: (h, ctx) => {
    const params = ctx.props.params

    return ctx.props.render(h, params);
  }
};

  • 传入参数
参数 参数类型 参数说明 默认值
obj <mark>Object,必传</mark> isLoading:Boolean遮罩层开关;list:Array数据源;page{page:1,rows:10,totalCount:总条数}分页参数
hasAll Boolean 非必传 是否显示合计 默认false
allcolumns Array 非必传 合计显示内容
allObj Array 源 合计数据 默认false
showSelect Boolean 非必传 选择框打开 默认false
keyId String 非必传 需要记忆选择内容分页时候每条记录的主键
columns Array 必传 表格设置和element-ui columns类似新增加一些字段
columns 介绍 参数类型 参数说明 默认值
prop String 必传 数据的key
label String 必传 显示的名字
isShow Boolean 是否显示 true
filter Function(item) 过滤的方法 返回值为显示的内容
widthNAuto Boolean 是否自动计算表格宽度 true
width String '80px' 宽度 widthNAuto=false 生效 true
render Function(h,prams) vue render自定义组件
回调 作用 返回参数
refresh 表格刷新
select 分页发生变化 返回page参考传入的page
内部方法 传入值 作用 返回值
filterList (Function(item) ) 过滤数据(前端筛选)
selectRow 返回选择数据列
dele item 某条记录 删除表格记忆的数据

具体项目地址gihub

相关文章