Vue3 + Element 自定义数据表格组件 el-table

目录

1.0

创建组件

使用组件

ts

html

效果:

2.0--------优化多个操作项显示,优化删除确认框

优化:

 弊端:

2.1       ----------------支持插槽操作

ts

vue

 模型


1.0

创建组件

<script lang="ts">
export default {
  name: "ReElTable"
};
</script>
<script setup lang="ts">
import { getCurrentInstance, watch } from "vue";
import { useI18n } from "vue-i18n";

const { proxy } = getCurrentInstance();
const { locale } = useI18n();

//监听国际化切换变化 用于国际化响应
watch(
  () => locale.value,
  () => {
    //防止 进行国际化操作时 固定列出现 样式异常问题
    proxy.$nextTick(() => {
      proxy.$refs["filterTableRef"].doLayout();
    });
  }
);

//获取 父级传进的参数
const props = defineProps({
  tableModule: {
    type: Object,
    default: null
  }
});
</script>

<template>
  <div>
    <h1>使用组件</h1>
    <el-table
      ref="filterTableRef"
      class="table-list"
      row-key="date"
      stripe
      :data="props.tableModule.table.data"
      v-loading="props.tableModule.table.loading"
      @sort-change="props.tableModule.table.sortChangeFunc"
      height="650"
      :header-cell-style="{ background: '#f5f7fa' }"
    >
      <template v-for="(item, index) in props.tableModule.columns" :key="index">
        <el-table-column
          :prop="item.prop"
          :width="item.width"
          :min-width="item.minWidth"
          :fixed="item.fixed"
          :sortable="item.sortable"
          :label="item.label"
          :align="item.align"
          :formatter="item.formatter"
          :show-overflow-tooltip="item.showOverflowTooltip"
        >
        </el-table-column>
      </template>
      <template v-if="props.tableModule.operation">
<!--        操作列-->
        <el-table-column
          align="center"
          fixed="right"
          :label="$t('table.operation')"
          width="200"
        >
          <template #default="scope">
            <template v-for="(item, index) in props.tableModule.operation" :key="index">
              <template v-if="!item.popConfirm">
<!--                普通按钮-->
                <el-button
                  type="text"
                  size="small"
                  @click="item.clickFunc(scope.$index, scope.row)"
                  >{{ item.button }}</el-button
                >
              </template>
              <template v-else>
<!--                带有确认框的按钮-->
                <el-popconfirm
                  :confirm-button-text="
                    !item.popConfirm.confirm
                      ? $t('button.confirm')
                      : item.popConfirm.confirm
                  "
                  :cancel-button-text="
                    !item.popConfirm.cancel
                      ? $t('button.cancel')
                      : item.popConfirm.cancel
                  "
                  :title="
                    !item.popConfirm.title
                      ? $t('else.isDelete')
                      : item.popConfirm.title
                  "
                  @confirm="item.clickFunc(scope.row.id)"
                >
                  <template #reference>
                    <el-button type="text" size="small">
                      {{ item.button }}
                    </el-button>
                  </template>
                </el-popconfirm>
              </template>
            </template>
          </template>
        </el-table-column>
      </template>
    </el-table>
    <!--分页-->
    <el-pagination
      :hide-on-single-page="false"
      :current-page="props.tableModule.paging.currentPage"
      :page-sizes="[5, 10, 15, 20, 25]"
      :page-size="props.tableModule.paging.pageSize"
      layout="total, sizes, prev, pager, next, jumper"
      :total="props.tableModule.paging.total"
      @size-change="props.tableModule.paging.sizeChangeFunc"
      @current-change="props.tableModule.paging.currentChangeFunc"
      align="right"
    ></el-pagination>
  </div>
</template>

<style scoped></style>

使用组件

ts

//引入组件 我的因为用的比较多所以 在main.js中引入了
import { ReElTable } from "/@/components/csms/re-el-table";

const tableModule = () => {
  return {
    table: {
      data: state.tableData,
      loading: state.tableLoading,
      sortChangeFunc: onSortChange
    },
    columns: [
      { prop: "id", sortable: true, width: 120, label: t("table.id") },
      { prop: "stationName", label: t("table.name") },
      { prop: "state", label: t("table.state") }
    ],
    operation: [
      { button: t("button.details"), clickFunc: onInfo },
      { button: t("button.delete"), popConfirm: true, clickFunc: onDel }
    ],
    paging: {
      currentPage: state.currentPage,
      pageSize: state.pageSize,
      total: state.total,
      sizeChangeFunc: pageSizeChange,
      currentChangeFunc: pageIndexChange
    }
  };
};

html

<ReElTable
   :tableModule="tableModule"
>
</ReElTable>

效果:

这里修改了 删除按钮 只是为了做一个 示例 

2.0--------优化多个操作项显示,优化删除确认框

优化

<script lang="ts">
export default {
  name: "ReElTable"
};
</script>
<script setup lang="ts">
import { getCurrentInstance, watch, reactive } from "vue";
import { useI18n } from "vue-i18n";

const { proxy } = getCurrentInstance();
const { locale } = useI18n();

//监听国际化切换变化 用于国际化响应
watch(
  () => locale.value,
  () => {
    //防止 进行国际化操作时 固定列出现 样式异常问题
    proxy.$nextTick(() => {
      proxy.$refs["filterTableRef"].doLayout();
    });
  }
);

//获取 父级传进的参数
const props = defineProps({
  tableModule: {
    type: Object,
    default: null
  }
});

//监听父级参数变化
watch(
  () => props.tableModule,
  () => {
    handleOperation();
  }
);

const operationArr = reactive([]);
const operationDropdownArr = reactive([]);

//用于对操作项显示处理
function handleOperation() {
  if (!props.tableModule.operation) return;
  operationArr.length = 0;
  operationDropdownArr.length = 0;
  let x = props.tableModule.operation.length > 3 ? 1 : 0;
  props.tableModule.operation.forEach(arr => {
    //判断是否显示
    if (arr.permission != false) {
      if (x < 3) {
        operationArr.push(arr);
      } else {
        operationDropdownArr.push(arr);
      }
      x++;
    }
  });
}

handleOperation();
</script>

<template>
  <div>
    <el-table
      ref="filterTableRef"
      class="table-list"
      size="large"
      :row-key="props.tableModule.table.data?.id"
      stripe
      :data="props.tableModule.table.data"
      v-loading="props.tableModule.table.loading"
      @sort-change="props.tableModule.table.sortChangeFunc"
      :max-height="
        props.tableModule.table.height ? props.tableModule.table.height : 650
      "
      :header-cell-style="{ background: '#f5f7fa' }"
      @selection-change="props.tableModule.table.selectionChange"
    >
      <template v-if="props.tableModule.table.selectionChange">
        <el-table-column type="selection" width="55" />
      </template>
      <slot />
      <template v-for="(item, index) in props.tableModule.columns" :key="index">
        <el-table-column
          :prop="item.prop"
          :width="item.width"
          :min-width="item.minWidth"
          :fixed="item.fixed"
          :sortable="item.sortable"
          :label="item.label"
          :align="item.align"
          :formatter="item.formatter"
          :show-overflow-tooltip="true"
        />
      </template>
      <template v-if="operationArr.length > 0">
        <!--        操作列-->
        <el-table-column
          align="center"
          :fixed="props.tableModule.operationAttr?.fixed ?? 'right'"
          :label="$t('title.operations')"
          :width="props.tableModule.operationAttr?.width ?? 200"
        >
          <template #default="scope">
            <template v-for="(item, index) in operationArr" :key="index">
              <!--                普通按钮-->
              <el-button
                type="primary"
                link
                size="small"
                @click="item.clickFunc(scope.$index, scope.row)"
                >{{ item.button }}</el-button
              >
            </template>
            &nbsp;
            <el-dropdown
              :hide-on-click="false"
              v-if="operationDropdownArr.length > 0"
            >
              <el-button type="primary" size="small" link>
                {{ $t("title.more") }}
                <el-icon class="el-icon--right">
                  <IconifyIconOffline icon="arrow-down" />
                </el-icon>
              </el-button>
              <template #dropdown>
                <el-dropdown-menu>
                  <template
                    v-for="(item, index) in operationDropdownArr"
                    :key="index"
                  >
                    <el-dropdown-item
                      :command="item.button"
                      @click="item.clickFunc(scope.$index, scope.row)"
                    >
                      {{ item.button }}
                    </el-dropdown-item>
                  </template>
                </el-dropdown-menu>
              </template>
            </el-dropdown>
          </template>
        </el-table-column>
      </template>
    </el-table>
    <!--分页-->
    <template v-if="props.tableModule.paging">
      <el-pagination
        :hide-on-single-page="false"
        :current-page="props.tableModule.paging.currentPage"
        :page-sizes="[5, 10, 20, 50, 100]"
        :page-size="props.tableModule.paging.pageSize"
        layout="->, total, sizes, prev,  pager, next, jumper"
        :total="props.tableModule.paging.total"
        @size-change="props.tableModule.paging.sizeChangeFunc"
        @current-change="props.tableModule.paging.currentChangeFunc"
      />
    </template>
  </div>
</template>

<style lang="scss" scoped>
//.el-button + .el-button {
//  margin-left: 0 !important;
//}
</style>

优化:

1.不再使用弹出在按钮旁的询问框(没做防抖的话,快速点击会出现重复发送请求问题)

2.低于或包含三个操作项直接显示,超出则提供一个更多按钮,点击后显示其他操作项

 弊端:

  使用插槽不方便

2.1       ----------------支持插槽操作

支持插槽

ts

<script lang="ts">
export default {
  name: "ReElTable"
};
</script>
<script setup lang="ts">
import { getCurrentInstance, watch, reactive } from "vue";
import { useI18n } from "vue-i18n";

const { proxy } = getCurrentInstance();
const { locale } = useI18n();

//监听国际化切换变化 用于国际化响应
watch(
  () => locale.value,
  () => {
    //防止 进行国际化操作时 固定列出现 样式异常问题
    proxy.$nextTick(() => {
      proxy.$refs["filterTableRef"].doLayout();
    });
  }
);

//获取 父级传进的参数
const props = defineProps({
  tableModule: {
    type: Object,
    default: null
  }
});

//监听父级参数变化
watch(
  () => props.tableModule,
  () => {
    handleOperation();
  }
);

const operationArr = reactive([]);
const operationDropdownArr = reactive([]);

//用于对操作项显示处理
function handleOperation() {
  if (!props.tableModule.operation) return;
  operationArr.length = 0;
  operationDropdownArr.length = 0;
  let x = props.tableModule.operation.length > 3 ? 1 : 0;
  props.tableModule.operation.forEach(arr => {
    //判断是否显示
    if (arr.permission != false) {
      if (x < 3) {
        operationArr.push(arr);
      } else {
        operationDropdownArr.push(arr);
      }
      x++;
    }
  });
}

handleOperation();
</script>

<template>
  <div>
    <el-table
      ref="filterTableRef"
      class="table-list"
      size="large"
      :row-key="props.tableModule.table.data?.id"
      stripe
      :data="props.tableModule.table.data"
      v-loading="props.tableModule.table.loading"
      @sort-change="props.tableModule.table.sortChangeFunc"
      :max-height="
        props.tableModule.table.height ? props.tableModule.table.height : 650
      "
      :header-cell-style="{ background: '#f5f7fa' }"
      @selection-change="props.tableModule.table.selectionChange"
    >
      <!--多选框-->
      <template v-if="props.tableModule.table.selectionChange">
        <el-table-column type="selection" width="55" />
      </template>
      <template v-for="(item, index) in props.tableModule.columns" :key="index">
        <!--是否为插槽-->
        <template v-if="item.slotName">
          <slot :name="item.slotName" />
        </template>
        <template v-else>
          <!--列-->
          <el-table-column
            :prop="item.prop"
            :width="item.width"
            :min-width="item.minWidth"
            :fixed="item.fixed"
            :sortable="item.sortable"
            :label="item.label"
            :align="item.align"
            :formatter="item.formatter"
            :show-overflow-tooltip="true"
          />
        </template>
      </template>
      <template v-if="operationArr.length > 0">
        <!--操作列-->
        <el-table-column
          align="center"
          :fixed="props.tableModule.operationAttr?.fixed ?? 'right'"
          :label="$t('title.operations')"
          :width="props.tableModule.operationAttr?.width ?? 200"
        >
          <template #default="scope">
            <template v-for="(item, index) in operationArr" :key="index">
              <!--普通按钮-->
              <el-button
                type="primary"
                link
                size="small"
                @click="item.clickFunc(scope.$index, scope.row)"
                >{{ item.button }}</el-button
              >
            </template>
            &nbsp;
            <!--超出显示更多按钮-->
            <el-dropdown
              :hide-on-click="false"
              v-if="operationDropdownArr.length > 0"
            >
              <el-button type="primary" size="small" link>
                {{ $t("title.more") }}
                <el-icon class="el-icon--right">
                  <IconifyIconOffline icon="arrow-down" />
                </el-icon>
              </el-button>
              <template #dropdown>
                <el-dropdown-menu>
                  <template
                    v-for="(item, index) in operationDropdownArr"
                    :key="index"
                  >
                    <el-dropdown-item
                      :command="item.button"
                      @click="item.clickFunc(scope.$index, scope.row)"
                    >
                      {{ item.button }}
                    </el-dropdown-item>
                  </template>
                </el-dropdown-menu>
              </template>
            </el-dropdown>
          </template>
        </el-table-column>
      </template>
    </el-table>
    <!--分页-->
    <template v-if="props.tableModule.table.data">
      <el-pagination
        :hide-on-single-page="false"
        :current-page="props.tableModule.paging.currentPage"
        :page-sizes="[5, 10, 20, 50, 100]"
        :page-size="props.tableModule.paging.pageSize"
        layout="->, total, sizes, prev,  pager, next, jumper"
        :total="props.tableModule.paging.total"
        @size-change="props.tableModule.paging.sizeChangeFunc"
        @current-change="props.tableModule.paging.currentChangeFunc"
      />
    </template>
  </div>
</template>

<style lang="scss" scoped>
//.el-button + .el-button {
//  margin-left: 0 !important;
//}
</style>

vue

 模型

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值