记录一下vue使用函数式组件二次封装el-table

前言

  • 记录为主,仅供参考
  • 因为项目统一要修改element表单的样式,看到居然每处都是复制粘贴一遍,没忍住进行了封装,封装完发现其实直接写公共样式就够了_(:з」∠)_
  • 以前写的,踩过的坑都忘了,不过多少有点参考价值
  • 函数式组件:总的来说就是代码生成结构,更加灵活

代码

组件

<template>
  <div :class="classOfType">
    <!-- 使用 v-bind和v-on来传递属性和方法-->
    <!-- @selection-change="$emit('selectionChange', $event)"  -->
    <el-table ref="elTable" v-bind="$attrs" v-on="$listeners" :size="size" :stripe="stripe" :style="tableStyle">
      <!-- 默认的放在最顶上 -->
      <slot name="prev"></slot>
      <template v-for="(item, index) in columnsList">
        <template v-if="item.render">
          <!-- template里不能写key -->
          <el-table-column :key="index" v-bind="item" align="center" show-overflow-tooltip>
            <template slot-scope="{ row }">
              <!-- 使用函数式组件进行dom渲染 -->
              <render-dom
                :render="(createElement, renDom) => item.render(createElement, renDom, row)"
              ></render-dom>
            </template>
          </el-table-column>
        </template>
        <!-- 直接在column上用for, 插槽会被template元素顶替,导致常规数据不显示-->
        <template v-else>
          <el-table-column
            :key="index"
            v-bind="item"
            align="center"
            show-overflow-tooltip
          ></el-table-column>
        </template>
      </template>

      <!-- 特殊的表单项 -->
      <slot></slot>
    </el-table>
  </div>
</template>

<script>
export default {
      
      
  name: 'env-table',
  components: {
      
      
    // 函数式组件注册
    renderDom: {
      
      
      functional: true,
      props: {
      
      
        render: Function,
      },
      render(createElement, renDom) {
      
      
        // 传递父组件的this,来触发事件
        return <div>{
      
      renDom.props.render(createElement, renDom.parent)}</div>;
      },
    },
  },
  props: {
      
      
    columnsList: {
      
      
      type: Array,
      default: () => [],
    },
    size: {
      
      
      type: String,
      default: 'medium',
    },
    tableStyle: {
      
      
      default: '',
    },
    stripe: {
      
      
      type: Boolean,
      default: true,
    },
    type: {
      
      
      type: Number,
      default: 1,
    },
  },
  data() {
      
      
    return {
      
      
      //多选相关
      hisReport: {
      
      
        Tree: [],
        Time: [],
        HistoryIndexArray: [],
      },
      elTable: null,
    };
  },
  computed: {
      
      
    classOfType() {
      
      
      switch (this.type) {
      
      
        case 1:
          return 'table';
        case 2:
          return 'table2';

        default:
          return;
      }
    },
  },
  mounted() {
      
      
    console.log('table绑定的:', this.$attrs);
    this.elTable = this.$refs.elTable
  },
  methods: {
      
      
    // 复选框选中事件
    // handleSelect(value){
      
      
    //   console.log('选中', value);
    //   this.$emit('selectionChange', value)
    // }
  },
};
</script>

使用

  • 难点主要在于render怎么写,当然也预留了slot可以处理麻烦的部分
<EnvTable
                :data="upgradeList"
                :columnsList="columnsList"
                height="30vh"
                max-height="37vh"
                :row-style="{ height: '30px' }"
                size="small"
                empty-text="暂无数据"
                :row-key="
                  (row) => {
                    return row.id;
                  }
                "
                @selection-change="handleSelectionChange"
              >
                <template v-slot:prev>
                  <el-table-column
                    align="center"
                    show-overflow-tooltip
                    type="selection"
                    :reserve-selection="true"
                    width="55"
                    :selectable="selectable"
                  ></el-table-column>
                </template>

                <el-table-column
                  align="center"
                  prop="progress"
                  label="升级进度"
                  sortable
                  width="200"
                >
                  <template v-slot="{ row }">
                    <el-progress
                      v-if="row.progress > 0"
                      :text-inside="true"
                      :stroke-width="8"
                      :percentage="row.progress"
                      :show-text="false"
                      status="success"
                    ></el-progress>
                    <span v-else>--</span>
                  </template>
                </el-table-column>

                <el-table-column align="center" label="操作">
                  <template v-slot="{ row }">
                    <el-button
                      style="padding: 5px 12px"
                      size="mini"
                      type="primary"
                      @click="upgrade([row.id])"
                      :disabled="[2, 6].includes(row.control_status)"
                    >
                      升级
                    </el-button>
                  </template>
                </el-table-column>
              </EnvTable>
  • 只做范例给出部分关键代码
		
		{
    
    
          prop: 'software_version',
          label: '当前版本',
          sortable: 'true',
          render: (createElement, context, row) => {
    
    
            return createElement('span', {
    
    }, row.software_version ? row.software_version : '--');
          },
        },
        {
    
    
          prop: 'newest_firmware',
          label: '待升级版本',
          sortable: 'true',
        },
        {
    
    
          prop: 'status',
          label: '上传状态',
          sortable: 'true',
          render: (createElement, context, row) => {
    
    
            //  return createElement('span', [
            //   row.err_count && row.err_count !== 0 ? `重试次数:${row.err_count}次` : '-',
            // ]);
            // 动态设置颜色
            const textColor = row.code != 0 ? 'red' : '#ffcc66';
            return (
              <span style={
    
    {
    
     color: textColor }}>
                {
    
    row.status}
                {
    
    row.err_count != 0 && <span>重试次数:{
    
    row.err_count}</span>}
              </span>
            );
          },
        },
        {
    
    
          prop: 'role',
          label: '用户类型',
          render: (createElement, renDom, row) => {
    
    
            return createElement('span', {
    
    }, [
              row.role === 'root' ? '超级管理员' : row.role === 'admin' ? '管理员' : '观察者',
            ]);
          },
        },