众所周知,vue中自带的select组件是单列并且没有分页的组件,但是在实际项目中,经常用到需要分页的select组件,甚至是select下拉选项是表格分页的组件。
以下是我简单的封装select的组件,使其变成了带有表格分页的组件,最终如下图所示:
废话不多说,直接上代码吧,先说明上面图片的颜色是项目的样式统一封装了,这里不贴出样式代码了。
第一:先封装一个分页组件
<template>
<div :class="{ hidden: hidden }" class="pagination-container">
<el-pagination
:small="small"
style="float: right"
:background="background"
:current-page="currentPage"
:page-sizes="[10, 30, 50]"
:page-size="currentLimit"
:layout="layout"
:total="total || 0"
:disabled="loading"
@current-change="handleCurrentChange"
@size-change="handleSizeChange"
/>
<el-button
v-show="refreshBtn"
:loading="loading"
plain
type="primary"
:small="small"
style="margin-left: 20px"
:class="{ marginA: !small, marginB: small }"
@click="handleRefresh"
>
<i-ic:outline-loop />
</el-button>
</div>
</template>
<script lang="ts" setup name="Pagination">
// name: 'Pagination',
const props = defineProps({
disabled: {
type: Boolean,
default: false,
},
small: {
type: Boolean,
default: true,
},
refreshBtn: {
type: Boolean,
default: false,
},
loading: {
type: Boolean,
default: false,
},
total: {
required: true,
type: Number,
},
page: {
type: Number,
default: 1,
},
limit: {
type: Number,
default: 50,
},
layout: {
type: String,
default: 'total, sizes, prev, pager, next,jumper',
},
background: {
type: Boolean,
default: true,
},
hidden: {
type: Boolean,
default: false,
},
pagesizes: {
type: Array,
default: function () {
return [10, 30, 50]
},
},
pagerCount: {
type: Number,
default: function () {
return 11
},
},
})
// 'page', 'limit',
const emit = defineEmits(['update:page', 'update:limit', 'pagination'])
// computed
const currentPage = computed(() => {
return props.page
})
const currentLimit = computed(() => {
return props.limit
})
// function
function handleRefresh() {
emit('pagination', {
refresh: true,
toPage: true,
page: props.page,
limit: props.limit,
isPrev: false,
isNext: false,
})
}
function handleCurrentChange(val) {
emit('update:page', val)
emit('pagination', {
toPage: true,
page: val,
limit: props.limit,
isPrev: false,
isNext: false,
})
}
function handleSizeChange(val) {
emit('update:limit', val)
emit('pagination', {
toPage: true,
page: 1,
limit: val,
isPrev: false,
isNext: false,
})
}
</script>
<style rel="stylesheet/scss" lang="scss" scoped>
.marginA {
margin-top: 6px;
}
.marginB {
margin-top: 0px;
}
.pagination-container {
/* padding: 32px 16px; */
margin: 0px;
padding: 0px;
padding-top: 10px;
// padding-left: 10px;
// height: 47px;
/* border: 1px solid #ebeef5; */
}
.pagination-container.hidden {
display: none;
}
</style>
第二封装select组件
<template>
<el-container>
<el-select
v-model="modelValueName"
placeholder="请选择"
style="width: 180px"
@change="selectChange"
>
<el-table
ref="plSelectTableRef"
row-key="id"
:data="dataList"
show-overflow-tooltip
@row-click="handleRowClick"
>
<template v-for="(item, index) in elTableOptions.columns" :key="index">
<el-table-column
:label="item.label"
:prop="item.props"
:width="item.width"
show-overflow-tooltip
>
<template #default="scope">
<el-option :key="item.props" :value="scope.row">
{{ scope.row[item.props] }}
</el-option>
</template>
</el-table-column>
</template>
</el-table>
<template #footer>
<div style="margin-bottom: 8px">
<Pagination
v-model:page="pageInfo.page"
v-model:limit="pageInfo.limit"
:total="pageInfo.total"
@pagination="pageChange"
/>
</div>
</template>
</el-select>
</el-container>
</template>
<script setup lang="ts">
import { getUUID } from '@/utils/util'
import { onMounted, ref } from 'vue'
export type Colcumn = {
props: string
label: string
width: number
}
export type Pagination = {
page: number
limit: number
total: number
}
export type TableOptions = {
colcumns: Colcumn[]
pagination: Pagination
}
export type PLSelectProps = {
tableOptions: TableOptions
}
const emit = defineEmits(['onPageChange', 'onSelectChange'])
const props = defineProps({
// 表格配置参数
tableOptions: {
type: Object,
default() {
return {}
},
},
dataSource: {
type: Array,
default() {
return []
},
},
// 绑定值对应显示的名称
modelValueName: {
type: String,
default: '',
},
})
const dataList = ref([])
const pageInfo = reactive<Pagination>({
page: 1,
limit: 10,
total: 0,
})
const modelValueName = ref()
const elTableOptions = ref<any>({})
const plSelectTableRef = ref()
const pageChange = (pageValue: Pagination) => {
// console.log('pageChange', pageValue)
pageInfo.page = pageValue.page
emit('onPageChange', pageValue)
}
const handleRowClick = (row) => {
// console.log('handleRowClick', row)
}
const selectChange = (data) => {
// console.log('selectChange', data)
emit('onSelectChange', data)
}
onMounted(() => {})
watch(
() => props.tableOptions,
(newVal, oldVal) => {
const options = {
...props.tableOptions,
}
const columns = []
if (props.tableOptions?.columns?.length) {
for (let index = 0; index < props.tableOptions?.columns.length; index++) {
const element = props.tableOptions?.columns[index]
columns.push({ ...element })
}
}
options.columns = columns
// console.log('tableOptions change', options)
elTableOptions.value = options
},
{
deep: true,
immediate: true,
}
)
watch(
() => props.dataSource,
(newVal, oldVal) => {
// console.log('dataSource change', props.dataSource)
dataList.value = props.dataSource
},
{
deep: true,
immediate: true,
}
)
watch(
() => props.tableOptions.pagination,
(newVal, oldVal) => {
// console.log('tableOptions.pageInfo change', props.tableOptions.pagination)
if (props.tableOptions?.pagination) {
pageInfo.limit = props.tableOptions.pagination.limit
pageInfo.page = props.tableOptions.pagination.page
pageInfo.total = props.tableOptions.pagination.total
}
},
{
deep: true,
immediate: true,
}
)
watch(
() => props.modelValueName,
(val, oldVal) => {
modelValueName.value = val
},
{
deep: true,
immediate: true,
}
)
</script>
<style lang="scss" scoped>
</style>
最后就是使用
<template>
<el-container class="test_data_container">
<el-row style="margin-top: 20px">
<el-col :span="8"></el-col>
<el-col :span="8">
<pl-select
:data-source="plSelectDataSource"
:table-options="tableOptions"
:model-value-name="plSelectValueName"
@on-select-change="plSelectChange"
@on-page-change="plSelectPageChange"
/>
</el-col>
</el-row>
</el-container>
</template>
<script setup lang="ts">
import { onMounted, ref } from 'vue'
import dayjs from 'dayjs'
import { get32UUID, getUUID } from '@/utils/util'
const plSelectDataSource = ref([])
const plSelectItem = ref()
const plSelectValueName = ref()
// 定义表格结构
const tableOptions = ref({
pagination: {
page: 1,
limit: 10,
total: 0,
},
columns: [
{
props: 'label1',
label: '列1',
width: 150,
},
{
props: 'label2',
label: '列2',
width: 150,
},
{
props: 'label3',
label: '列3',
width: 150,
},
{
props: 'label4',
label: '列4',
width: 150,
},
{
props: 'label5',
label: '列5',
width: 150,
},
],
})
const searchData = (pageIndex = 1) => {
const list = []
// 请求数据后,这里为模拟数据
const dataTotalCount = 35
for (let index = 0; index < tableOptions.value.pagination.limit; index++) {
const row = {
id: getUUID(),
label1: '页' + pageIndex + '行' + (index + 1) + '值' + '-1',
label2: '页' + pageIndex + '行' + (index + 1) + '值' + '-2',
label3: '页' + pageIndex + '行' + (index + 1) + '值' + '-3',
label4: '页' + pageIndex + '行' + (index + 1) + '值' + '-4',
label5: '页' + pageIndex + '行' + (index + 1) + '值' + '-5',
value: index + '' + pageIndex + '' + 1,
}
list.push(row)
}
plSelectDataSource.value = list
tableOptions.value.pagination.total = dataTotalCount
}
const plSelectPageChange = (pageValue) => {
searchData(pageValue.page)
}
const plSelectChange = (data) => {
plSelectItem.value = data
plSelectValueName.value = data.label1
}
onMounted(() => {
searchData()
})
</script>
<style lang="scss" scoped>
.test_data_container {
display: flex;
flex-direction: column;
}
</style>
上面代码的pl-select就是第二步中封装的select组件,可以根据自己项目使用相对引用路径也可以的。