背景:
在vue3项目中,常用的三种插槽。
关于插槽的理论知识如下:
插槽是指可以在父组件内自定义模板片段,在子组件中可以将定义的模板片段插入到子组件的特定位置。常用:匿名插槽、具名插槽
作用域插槽:子组件向父组件传递数据,并在父组件定义的模板中渲染。常用:作用域插槽
匿名插槽和具名插槽:
插槽是指可以在父组件内自定义模板片段,在子组件中可以将定义的模板片段插入到子组件的特定位置。常用:匿名插槽、具名插槽
代码截图:
父组件:
子组件:
作用域插槽:
作用域插槽:子组件向父组件传递数据,并在父组件定义的模板中渲染。
代码截图:
实际代码如下:
父组件:
<div class="container">
<Table :columns="columns" :current-page="currentPage" :data="tableData" :page-size="pageSize" :total="total"
@update:currentPage="val => currentPage = val">
<template #operation="{ row, $index }">
<el-button text @click="ClickDetail(row, $index)">
<template #icon>
<img :src="detailIcon" alt="">
</template>
详情
</el-button>
<el-button text @click="ClickEdit(row, $index)">
<template #icon>
<img :src="editIcon" alt="">
</template>
编辑
</el-button>
<el-button text @click="ClickForward(row, $index)">
<template #icon>
<img :src="forwardIcon" alt="">
</template>
预/决算
</el-button>
<el-button text @click="ClickDelete(row, $index)">
<template #icon>
<img :src="deleteIcon" alt="">
</template>
删除
</el-button>
</template>
</Table>
</div>
子组件:
<template>
<div class="table-container">
<el-table :data="data"
:style="`width: 100%; flex: 1 1 auto;opacity: ${!enableLoading || !isloading || isempty ? 1 : 0};`"
:height="tableBodyHeight" :header-cell-style="{ background: '#F5F9FF', color: '#333333', fontWeight: '550' }"
:cell-style="cellStyle" max-height="100%" :border="showBorder" empty-text="">
<el-table-column type="index" label="序号" width="60" align="center" :index="indexMethod" fixed="left"
v-if="showIndex" />
<!-- 操作列插槽 -->
<el-table-column label="操作" align="center" fixed="right" v-if="$slots.operation" :width="400">
<template #default="scope">
<slot name="operation" :row="scope.row" :$index="scope.$index"></slot>
</template>
</el-table-column>
</el-table>
<div class="custom-pagination-wrapper">
<span class="custom-pagination-total">共 {{ total }} 个</span>
<el-pagination background layout="prev, pager, next" :total="total" :page-size="pageSize"
:current-page="currentPage" @current-change="handlePageChange" class="custom-pagination" />
</div>
</div>
</template>
<script setup>
import { defineProps, defineEmits, onMounted, ref, nextTick, reactive, watch, computed } from 'vue'
const props = defineProps({
columns: {
type: Array,
required: true
},
data: {
type: Array,
required: true
},
total: {
type: Number,
default: 0
},
pageSize: {
type: Number,
default: 10
},
currentPage: {
type: Number,
default: 1
},
// 是否默认显示序号列
showIndex: {
type: Boolean,
default: true
},
// 是否默认显示表格边框
showBorder: {
type: Boolean,
default: false
},
// 是否默认开启加载动画
enableLoading: {
type: Boolean,
default: false
}
});
const isloading = ref(true), isempty = ref(false);
watch(() => props.data, (newValue, oldValue) => {
nextTick(() => {
// console.log('table');
isempty.value = props.data.length == 0;
isloading.value = false;
})
});
const emit = defineEmits(['update:currentPage', 'customCellStyle'])
function handlePageChange(page) {
// if (props.data && props.data.length !== 0) {
// state.tableData = props.data.slice((page - 1) * 10, 10 * page);
// emit('update:currentPage', page)
// }
emit('update:currentPage', page)
}
// 自动序号方法,分页自增
const indexMethod = (index) => {
return (props.currentPage - 1) * props.pageSize + index + 1
}
// 计算表格可视区高度,减去分页区高度
const tableBodyHeight = ref('100%')
// 自定义每个单元格的样式
const cellStyle = (target) => {
let style = { color: '#363636' };
// 子组件可自己实现自定义样式
emit('customCellStyle', target, data => {
style = data;
});
return style;
}
onMounted(() => {
nextTick(() => {
const container = document.querySelector('.table-container')
const pagination = document.querySelector('.custom-pagination-wrapper')
if (container && pagination) {
const containerHeight = container.clientHeight
const paginationHeight = pagination.clientHeight
tableBodyHeight.value = `${containerHeight - paginationHeight}px`
}
// handlePageChange(props.currentPage)
})
})
</script>
<style scoped>
.table-container {
position: relative;
display: flex;
flex-direction: column;
height: 100%;
min-height: 0;
.loading {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
z-index: 9;
span {
color: #3A5269;
text-align: center;
font-family: "Alibaba PuHuiTi";
font-size: 18px;
font-style: normal;
line-height: 22px;
/* 122.222% */
font-weight: 400;
/* margin-top: 10px; */
margin-left: 20px;
}
}
.isempty {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
z-index: 9;
img {
width: 140px;
height: 140px;
}
span {
color: #3A5269;
text-align: center;
font-family: "Alibaba PuHuiTi";
font-size: 18px;
font-style: normal;
line-height: 22px;
/* 122.222% */
/* margin-top: 16px; */
margin-left: 20px;
}
}
}
.el-table {
flex: 1 1 auto;
min-height: 0;
}
.el-table__body-wrapper {
overflow-y: auto !important;
}
:deep(.el-table__row) {
height: 40px;
}
.custom-pagination-wrapper {
display: flex;
align-items: center;
justify-content: space-between;
height: 30px;
}
.custom-pagination-total {
color: #86909C;
font-size: 14px;
margin-right: 16px;
}
.custom-pagination {
margin-left: auto;
}
.custom-pagination .el-pager li {
border-radius: 4px;
min-width: 32px;
height: 32px;
line-height: 32px;
margin: 0 2px;
color: #4E5A6A;
font-size: 14px;
background: transparent;
border: none;
transition: background 0.2s, color 0.2s, border 0.2s;
}
.custom-pagination .el-pager li.active {
background: transparent;
color: #28ABF5;
border: 1px solid #28ABF5;
border-radius: 4px;
}
.custom-pagination .el-pager li:hover {
background: #eaf4ff;
color: #28ABF5;
}
.custom-pagination .el-pagination__prev,
.custom-pagination .el-pagination__next {
min-width: 32px;
height: 32px;
line-height: 32px;
border-radius: 4px;
color: #4E5A6A;
background: transparent;
border: none;
margin: 0 2px;
}
.custom-pagination .el-pagination__prev.is-active,
.custom-pagination .el-pagination__next.is-active {
background: transparent;
color: #28ABF5;
border: 1px solid #28ABF5;
border-radius: 4px;
}
.custom-pagination .el-pagination__prev:hover,
.custom-pagination .el-pagination__next:hover {
background: #eaf4ff;
color: #28ABF5;
}
:deep(.el-pagination.is-background .btn-next),
:deep(.el-pagination.is-background .el-pager li),
:deep(.el-pagination.is-background .btn-prev:disabled),
:deep(.el-pagination.is-background .btn-prev) {
background: transparent;
color: #606266;
}
:deep(.el-pagination.is-background .el-pager li.is-active) {
min-width: 25px;
height: 25px;
color: #28ABF5;
border-radius: 4px;
border: 1px solid #28ABF5;
}
</style>
为什么这么封装,需要了解el-table组件,点击跳转