Lógica de paginación e implementación en ElementPlus

Lógica de paginación e implementación en ElementPlus

La paginación es un componente esencial en el desarrollo web. El equipo de elementos proporciona componentes de paginación simples y hermosos, que se pueden usar con datos de tablas para lograr efectos de paginación plug-and-play. La implementación de la paginación se puede dividir en dos tipos, una es la paginación de front-end y la otra es la paginación de back-end. Estos dos tipos de paginación son adecuados para diferentes escenarios comerciales, respectivamente. He escrito sobre la paginación innumerables veces, pero nunca he podido recordarlo, por lo que registraré la lógica y la implementación de estos dos efectos de paginación.

1. Paginación frontal

La paginación front-end es adecuada para situaciones donde la cantidad de datos es pequeña: se inicia una solicitud de datos al back-end y el front-end maneja la paginación. La ventaja es que hay pocas solicitudes de interfaz y la lógica es muy simple, pero la desventaja es obvia: cuando se procesan grandes cantidades de datos, la eficiencia es extremadamente baja.

La paginación front-end es un modo de paginación que me gusta mucho, la razón principal es que el código es simple.

Ahora veamos cómo se logra esto.

Primero, echemos un vistazo a la implementación final:

imagen-20231214083706881

Veámoslo con el código:

<template>
    <div class="outer">
        <el-table :data="currentTableData" height="480" stripe border class="table">
            <el-table-column v-for="(item, index) in tableForm" :key="index" :prop="item.prop" :label="item.label"
                :width="100" show-overflow-tooltip></el-table-column>
            <el-table-column fixed="right" label="详细" width="100">
                <template #default="scope">
                    <el-button link type="primary" size="small" @click="handleClick(scope.$index, scope.row)">查看</el-button>
                </template>
            </el-table-column>
        </el-table>
        <el-pagination class="pagination" small background layout="prev, pager, next" :total="totalItems"
            v-model:current-page="currentPage" @current-change="handelCurrentChange" :hide-on-single-page="paginationShow"
            style="margin-top: 20px;" />
    </div>
</template>

<script setup>
import {
      
       ref, onMounted, watch } from 'vue'
import {
      
       getAnalisisNolocalTableApi } from '@/apis/analysisNolocal'
import {
      
       ElMessage } from 'element-plus';
const tableData = ref([])
const tableForm = [
   // 表头数据
]

// 点击每行的查看,展示详细事故信息
import mitt from '@/utils/mitt'
const emitter = mitt
const handleClick = (index, row) => {
      
      
    emitter.emit('showDrawer', row)
    // console.log(index, row)
}

// 分页
const currentTableData = ref([])
const currentPage = ref(1)
const pageSize = 10
const totalItems = ref(0)
const paginationShow = ref(true)

watch(tableData, (newVal, oldVal) => {
      
      
    currentPage.value = 1
    totalItems.value = tableData.value.length
    currentTableData.value = tableData.value.filter((item, index) => index < pageSize)
    // paginationShow.value = tableData.value.length > 10 ? true : false
})

const handelCurrentChange = page => {
      
      
    currentPage.value = page
    // currentPage.value = 1
    const index = pageSize * (page - 1)
    const nums = pageSize * page
    const tables = []
    for (let i = index; i < nums; i++) {
      
      
        if (tableData.value[i]) tables.push(tableData.value[i])
    }
    currentTableData.value = tables
}

const getData = async () => {
      
      
    try {
      
      
        const {
      
       data } = await getAnalisisNolocalTableApi()
        // console.log(data)
        tableData.value = data
    } catch (error) {
      
      
        ElMessage.error('请求接口报错')
        console.log(error)
    }
}
onMounted(async () => {
      
      
    getData()
})
</script>

<style lang="scss" scoped>

</style>

Primero explique el código:

  1. Todos los datos de la tabla están vinculados a tableData. El método para obtener tableData es getData, que se llama antes de montar el componente.
  2. Los datos de la tabla de la página actual son currentTableData
  3. El encabezado de la tabla es tableForm, escríbalo aquí de acuerdo con su situación real.

A continuación mire la paginación:

<el-pagination class="pagination" small background layout="prev, pager, next" :total="totalItems"
   v-model:current-page="currentPage" @current-change="handelCurrentChange" :hide-on-single-page="paginationShow"
   style="margin-top: 20px;" />

Hay muchos parámetros, veamos directamente la API proporcionada por elementplus:

Nombre del Atributo ilustrar tipo valor por defecto
pequeño Si se debe utilizar un estilo de paginación pequeño boolean FALSO
fondo Si se debe agregar un color de fondo al botón de paginación boolean FALSO
tamaño de página / modelo v: tamaño de página Número de elementos mostrados por página number
tamaño de página predeterminado El número predeterminado de entradas por página; si no se establece, el valor predeterminado es 10 number
total Número total de entradas number
recuento de páginas El número total de páginas, total y page-count se pueden configurar en cualquiera para lograr la función de mostrar números de página; si desea admitir page-sizes, necesitas usar el atributo total number
recuento de buscapersonas Establezca el número máximo de botones de página. El número de botones de número de página, que se colapsarán cuando el número total de páginas supere este valor. number 7
página-actual/modelo-v:página-actual número de página actual number
página-actual-predeterminada El valor inicial predeterminado del número de página actual, el valor predeterminado es 1 si no se establece number
disposición Diseño de componentes, nombres de subcomponentes separados por comas string anterior, buscapersonas, siguiente, puente, ->, total
tamaños de página Mostrar la configuración de opciones del selector de números por página object [10, 20, 30, 40, 50, 100]
clase popper El nombre de clase del cuadro desplegable del selector de números que se muestra en cada página. string ''
texto anterior Texto de la página anterior mostrado por el icono de reemplazo string ''
icono anterior El icono de la página anterior tiene mayor prioridad que prev-text string/Component FlechaIzquierda
texto siguiente Texto de la página siguiente mostrado por el icono de reemplazo string ''
icono siguiente El icono de la página siguiente tiene una prioridad menor que next-text string/Component FlechaDerecha
desactivado Ya sea para deshabilitar la paginación boolean FALSO
teletransportado 2.3.13 Ya sea para teletransportar el menú desplegable al cuerpo boolean verdadero
ocultar en una sola página Si se debe ocultar cuando solo hay una página boolean FALSO

Hay varios parámetros que son muy importantes:

  • const currentPage = ref(1), el atributo vinculado es página actual / modelo v: página actual, que es el número de página actual y el valor predeterminado es 1
  • const totalItems = ref(0), el atributo vinculado es total, que es el número total de datos, determinado según la longitud de tableData

Hay otro evento muy importante, a sabercurrent-change, que es el evento que se ejecuta cuando cambia el número de página actual. El método de enlace es handleCurrentChange. Veamos qué hace este método.

const handelCurrentChange = page => {
    
    
    currentPage.value = page
    // currentPage.value = 1
    const index = pageSize * (page - 1)
    const nums = pageSize * page
    const tables = []
    for (let i = index; i < nums; i++) {
    
    
        if (tableData.value[i]) tables.push(tableData.value[i])
    }
    currentTableData.value = tables
}
  1. Primero, este método recibe una página de parámetros predeterminada, que en realidad es el número de página actual, y asigna el parámetro predeterminado a página actual.
  2. Obtenga el índice inicial de los datos de la página actual, es decir, índice = tamaño de página * (página - 1). Debido a que el número de página comienza desde 1 y los datos de la primera página comienzan desde el elemento 0, el índice en realidad debería ser tamaño de página * ( página - 1), tamaño de página aquí es el número de elementos de datos que se mostrarán en cada página.
  3. Obtenga el índice del último dato en la página actual, es decir, nums = pageSize * page
  4. Obtenga los datos de la página actual según el índice y los números

Tenga en cuenta que también escribí un evento de escucha:

watch(tableData, (newVal, oldVal) => {
    
    
    currentPage.value = 1
    totalItems.value = tableData.value.length
    currentTableData.value = tableData.value.filter((item, index) => index < pageSize)
    // paginationShow.value = tableData.value.length > 10 ? true : false
})

Este código está escrito aquí porque también he filtrado los datos. Después de filtrar los datos, tableData cambia, por lo que el número total de paginaciones y la página actual deben cambiar. Esto tiene poco que ver con la paginación frontal de la que estoy hablando. aquí.

Hasta ahora se han logrado todos los efectos de la paginación front-end, lo cual es bastante simple, en resumen, el núcleo radica en:

  1. Definir parámetros de paginación
  2. Obtener datos totales del backend
  3. Escribe el método de cambio actual.

2. Paginación de fondo

De hecho, la paginación de back-end es la idea correcta, porque en circunstancias normales, el back-end no enviará todos los datos al front-end a la vez y la eficiencia de transmisión es baja e insegura. Pero la paginación de fondo es relativamente problemática, pase lo que pase, registrémosla.

Primero echemos un vistazo a los resultados de mi paginación:

Insertar descripción de la imagen aquí

Todos usan datos de prueba y la paginación está en la esquina inferior derecha. De hecho, no hay diferencia en la visualización, pero la lógica es completamente diferente.

1. Código de fondo

El backend ha escrito dos interfaces. Las escribí usando node. Una es para obtener el número total de listas y la otra es para monitorear el cambio de página y devolver los datos de la página actual al frontend.

El código se muestra a continuación:

// 分页
// 获取列表总数
exports.getAdminListLength = (req, res) => {
    
    
  const sql = "select * from users where identity = ?";
  db.query(sql, req.body.identity, (err, results) => {
    
    
    if (err) res.cc(err);
    res.send({
    
    
      length: results.length,
    });
  });
};

// 监听换页,返回数据,参数为页码和身份
exports.returnListData = (req, res) => {
    
    
  // 每页显示10条,offset是起始处的偏移量
  const number = req.body.page * 10;
  const sql = `select * from users where identity = ? limit 10 offset ${
      
      number}`;
  db.query(sql, [req.body.identity, number], (err, results) => {
    
    
    if (err) res.cc(err);
    results.forEach((item) => {
    
    
      item.password = "";
      item.create_time = "";
      item.update_time = item.update_time.slice(0, 19);
    });
    res.send(results);
  });
};

No hay nada que decir acerca de obtener el número total de listas, es solo una declaración de consulta.

Mire principalmente el método returnListData

De hecho, el front-end pasa dos parámetros al back-end, uno es el número de página actual (página) y el otro es la condición de consulta (identidad).

Mira la declaración de consulta.

const sql = `select * from users where identity = ? limit 10 offset ${
      
      number}`;

límite 10 significa devolver los primeros 10 datos

El desplazamiento aquí es muy crítico, indica dónde comenzar a devolver 10 datos. Por ejemplo, si quiero consultar los datos en la página 3, entonces la página real=3 en el front-end,, entonces los datos de la página 3 deben ser los datos del índice 20-29, y el número aquí = 20, el desplazamiento 20 significa comenzar a recuperar datos del elemento 20 se pasa a la página real = página-1=2 en el backend (necesita comprender la lógica aquí)

La lógica del backend es así

2. Código de interfaz

Sube el código directamente

<template>
    <BreadCrumb ref="breadCrumb" :item="item"></BreadCrumb>
    <div class="table-wrapped">
        <div class="table-top">
            <div class="table-header">
                <div class="search-wrapped" style="display: flex">
                    <el-input v-model="input1" class="w-50 m-2" placeholder="输入账号搜索" :prefix-icon="Search"
                        @change="searchAdmin" />
                    <!-- <el-button type="primary" @click="getAdmin" style="margin-left: 10px;" circle :icon="Refresh"
                        title="重置列表"></el-button> -->
                </div>
                <div class="button-wrapped">
                    <el-button type="primary" @click="create">添加产品管理员</el-button>
                </div>
            </div>
            <div class="table-content">
                <el-table :data="tableData" border style="width: 100%">
                    <el-table-column type="index" width="50" />
                    <el-table-column prop="account" label="账号" />
                    <el-table-column prop="name" label="姓名" />
                    <el-table-column prop="sex" label="性别" />
                    <el-table-column prop="department" label="部门" />
                    <el-table-column prop="email" label="邮箱" />
                    <el-table-column prop="update_time" label="更新时间" />

                    <el-table-column label="操作" width="150">
                        <template #default="scope">
                            <el-button type="success" size="small"
                                @click="handleEdit(scope.$index, scope.row)">编辑</el-button>
                            <el-button type="danger" size="small"
                                @click="handleDelete(scope.$index, scope.row)">删除</el-button>
                        </template>
                    </el-table-column>

                </el-table>
            </div>
        </div>
        <div class="table-footer">
            <el-pagination :page-size="2" :current-page="paginationData.currentPage" :pager-count="5" :total="adminTotal"
                :page-count="paginationData.pageCount" @current-change="currentPageChange" layout="prev, pager, next" />
        </div>
    </div>
    <CreateAdmin></CreateAdmin>
    <EditAdmin></EditAdmin>
    <DeleteAdmin></DeleteAdmin>
</template>

<script setup>
import {
      
       ref, onMounted, onBeforeUnmount } from 'vue'
import {
      
       Refresh, Search } from '@element-plus/icons-vue'
import BreadCrumb from '@/components/BreadCrumb.vue';
import CreateAdmin from '../components/CreateAdmin.vue'
import EditAdmin from '../components/EditAdmin.vue'
import DeleteAdmin from '../components/DeleteAdmin.vue';
import {
      
       getAdminAPI, searchUserAPI, getAdminListLengthAPI, returnListDataAPI } from "@/apis/userinfo";
import mitt from '@/utils/mitt'
import {
      
       ElMessage } from 'element-plus';
const emitter = mitt

const item = ref({
      
      
    first: '用户管理',
    second: '产品管理员'
})
const input1 = ref('')
const tableData = ref([])

const create = () => {
      
      
    emitter.emit('openCreateDialog', '添加产品管理员')
}

const handleEdit = (index, row) => {
      
      
    emitter.emit('openEditDialog', {
      
       index, row, title: '编辑产品管理员' })
    // console.log('-----------', index, row)
}
const handleDelete = (index, row) => {
      
      
    emitter.emit('openDeleteDialog', {
      
       row })
}

const getAdmin = async () => {
      
      
    const res = await getAdminAPI({
      
       identity: '产品管理员' })
    if (res.status && res.status == 1) return ElMessage.error('获取数据出错')
    tableData.value = res
    // console.log(res)
}

emitter.on('refreshAdminList', async () => {
      
      
    // getAdmin()
    getAdminListLength()
    tableData.value = await returnListDataAPI({
      
       identity: '产品管理员', page: paginationData.value.currentPage - 1 })

})
const searchAdmin = async () => {
      
      
    const res = await searchUserAPI({
      
       account: input1.value })
    // console.log(res)
    tableData.value = res
}

// 分页
const paginationData = ref({
      
      
    // 总页数
    pageCount: 1,
    // 当前页
    currentPage: 1,
})

const adminTotal = ref(0)
const getAdminListLength = async () => {
      
      
    const res = await getAdminListLengthAPI({
      
       identity: '产品管理员' })
    adminTotal.value = res.length
    // 每页显示10条数据,所以除以10
    paginationData.value.pageCount = Math.ceil(res.length / 10)
}

// 默认获取第一页的数据
const getFirstPageList = async () => {
      
      
    tableData.value = await returnListDataAPI({
      
       identity: '产品管理员', page: 0 })
}
const currentPageChange = async (val) => {
      
      
    // console.log(val)
    paginationData.value.currentPage = val
    tableData.value = await returnListDataAPI({
      
       identity: '产品管理员', page: val - 1 })
}
onMounted(() => {
      
      
    // getAdmin()
    getAdminListLength()
    getFirstPageList()
})
onBeforeUnmount(() => {
      
      
    emitter.all.clear()
})
</script>

<style lang="scss" scoped></style>

El código es bastante largo, solo debemos centrarnos en la tabla y la paginación.

Los datos vinculados a la tabla son tableData. Tenga en cuenta que estos no son todos los datos, sino los datos de la página actual.

Componente de paginación:

<el-pagination :page-size="10" :current-page="paginationData.currentPage" :pager-count="5" :total="adminTotal"
   :page-count="paginationData.pageCount" @current-change="currentPageChange" layout="prev, pager, next" />

La entrada total de datos adminTotal se obtiene de la primera interfaz del backend, no es necesario escribir el atributo total page-count.

Los atributos no se presentarán en detalle, pero nos centraremos en los métodos relacionados con el cambio actual.

const currentPageChange = async (val) => {
    
    
    // console.log(val)
    paginationData.value.currentPage = val
    tableData.value = await returnListDataAPI({
    
     identity: '产品管理员', page: val - 1 })
}

Como se introdujo durante la paginación del front-end, el parámetro predeterminado pasado por el evento de cambio actual es el número de página actual. Este número de página es un parámetro muy importante que debe pasarse al backend. La página realmente pasada al backend es la valor después del número de página actual: 1.

Otra cosa que necesita atención es que cuando se monta el componente, los datos de la primera página deben mostrarse de forma predeterminada, por lo que debe escribir un método para obtener los datos de la primera página, es decir:

// 默认获取第一页的数据
const getFirstPageList = async () => {
    
    
    tableData.value = await returnListDataAPI({
    
     identity: '产品管理员', page: 0 })
}

En este punto, toda la lógica de la paginación de fondo está completa.

Tienes que escribir y practicar estas cosas con frecuencia. Si no escribes durante un tiempo, lo olvidarás todo. . . .

Supongo que te gusta

Origin blog.csdn.net/u012848304/article/details/134987359
Recomendado
Clasificación