vue3 封装组件透传 attrs listeners

封装el-table组件,在网上搜了些,都是要把事件重写一遍,发现vue3不支持listeners了合并到attrs内了,于是有了一个简单的思路
将attrs内的on开头的事件重新赋值给一个对象然后用v-on绑定到组件上

<script setup>
import { computed, ref, useAttrs } from 'vue'
import { ElTable } from 'element-plus'

const attrs = useAttrs()
// 取on开头的属性,给e-table添加v-on绑定事件,并在attrs删除 
let onMethods = {}
let removeMethods = {}
for (let key in attrs) {
  if (key.startsWith('on')) {
    onMethods[key.replace('on', '')] = attrs[key]
    removeMethods[key] = undefined
  }
}
const props = defineProps({
  tableData: Array,
  columns: Array,
  options: [Object, null]
})
const tableRef = ref()
// 设置option默认值,如果传入自定义的配置则合并option配置项
const _options = computed(() => {
  const option = {
    // size: "small",
    stripe: false,
    tooltipEffect: 'dark',
    showHeader: true,
    showPagination: false,
    rowStyle: () => 'cursor:pointer' // 行样式
  }
  return Object.assign(option, attrs, removeMethods)
})
// 合并分页配置
const _paginationConfig = computed(() => {
  const config = {
    total: 0,
    currentPage: 1,
    pageSize: 10,
    pageSizes: [10, 20, 30, 40, 50, 100],
    layout: 'total, sizes, prev, pager, next, jumper'
  }
  return Object.assign(config, props.options?.paginationConfig || {})
})
const emit = defineEmits([
  'size-change', // pageSize事件
  'current-change', // currentPage按钮组事件
  'pagination-change', // currentPage或者pageSize改变触发 
])
// 自定义索引
const indexMethod = (index) => {
  const tabIndex = index + (_paginationConfig.value.currentPage - 1) * _paginationConfig.value.pageSize + 1
  return tabIndex
}
// 切换pageSize
const pageSizeChange = (pageSize) => {
  emit('size-change', pageSize)
  emit('pagination-change', 1, pageSize)
}
// 切换currentPage
const currentPageChange = (currentPage) => {
  emit('current-change', currentPage)
  emit('pagination-change', currentPage, _paginationConfig.value.pageSize)
}
// 暴露给父组件参数和方法,如果外部需要更多的参数或者方法,都可以从这里暴露出去。
defineExpose({ element: tableRef })
</script>
<template>
  <div>
  	<!--v-on绑定事件 v-bind绑定参数-->
    <el-table ref="tableRef" :data="tableData" v-bind="_options" v-on="onMethods">
      <template v-for="(col, index) in columns" :key="index">
        <!---复选框, 序号 (START)-->
        <el-table-column v-if="col.type === 'index' || col.type === 'selection' || col.type === 'expand'" :index="indexMethod" v-bind="col">
          <!-- 当type等于expand时, 配置通过h函数渲染、txs语法或者插槽自定义内容 -->
          <template #default="{ row, $index }">
            <!-- render函数 (START) : 使用内置的component组件可以支持h函数渲染和txs语法 -->
            <component v-if="col.render" :is="col.render" :row="row" :index="$index" />
            <!-- render函数 (END) -->
            <!-- 自定义slot (START) -->
            <slot v-else-if="col.slot" name="expand" :row="row" :index="$index"></slot>
            <!-- 自定义slot (END) -->
          </template>
        </el-table-column>
        <!---复选框, 序号 (END)-->
        <!-- 渲染插槽 START -->
        <slot v-else-if="col.slot" :name="col.slot"></slot>
        <el-table-column v-else v-bind="col"></el-table-column>
        <!-- 渲染插槽 END -->
      </template>
    </el-table>
    <!-- 分页器 -->
    <div v-if="_options.showPagination" class="fx fx_ai_c fx_jc_e" style="width: 100%;margin-top: 5px;">
      <el-pagination v-bind="_paginationConfig" @size-change="pageSizeChange" @current-change="currentPageChange" />
    </div>
  </div>
</template>
<style lang="scss" scoped>
:deep(.el-image__inner) {
  transition: all 0.3s;
  cursor: pointer;
  &:hover {
    transform: scale(1.2);
  }
}
.mt20 {
  margin-top: 20px;
}
</style>


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值