在使用 Element Plus 组件时,有时会遇到组件不完全符合需求的情况,这时可能需要对其进行二次封装。在封装 Pagination 组件时,我们会发现一些属性和函数无法正常使用,下面将详细探讨这些问题,并提供一下思路和想法。
封装组件代码如下:
import { ElPagination } from 'element-plus';
import './index.less';
export default defineComponent({
name: 'MyPagination',
props: paginationProps,
setup(props, { attrs, slots }) {
return () => (
<div class={`pagination-common`}>
<ElPagination
{...props}
{...attrs}
>
{slots.default ? slots.default() : null}
</ElPagination>
</div>
);
},
});
1. 属性
1.1 pageSize 属性
在使用自定义 MyPagination 组件时:
import { defineComponent, ref } from "vue";
import { MyPagination } from "../MyPagination";
import "./index.less";
export default defineComponent({
name: "Demo",
setup() {
return () => (
<div class="paginationContainer">
<MyPagination
layout="total, sizes, prev, pager, next, jumper"
total={500}
pageSize={20}
/>
</div>
);
}
});
代码警告⚠️:
简单分析一下,可以看到是 pageSize 出现问题导致的报错,为什么呢?
对于 Element Plus 的 Pagination 组件而言,pageSize 是一个受控属性,也就是需要外部管理它的值并对变动进行响应。
那该属性应该怎么使用呢?
import { defineComponent, ref } from "vue";
import { MyPagination } from "../MyPagination";
import "./index.less";
export default defineComponent({
name: "Demo",
setup() {
const pageSize = ref(30);
return () => (
<div class="paginationContainer">
<MyPagination
layout="total, sizes, prev, pager, next, jumper"
total={500}
v-model:pageSize={pageSize.value}
/>
</div>
);
}
});
成功展示的原因:
1、双向绑定机制
使用 v-model 实现双向绑定,确保组件内的 pageSize 更新会自动反映到外部的数据(pageSizeRef),从而保持组件和外部状态的一致。
2、事件触发更新
Pagination 组件内部会触发 update:pageSize 事件来通知外部其 pageSize 的改变。使用 v-model:pageSize 可以自动捕获并处理这个事件,避免手动监听 update:pageSize 事件。
1.2 currentPage 属性
同理 currentPage 表示当前的页码,也是受控属性,需要绑定 v-model。当用户点击分页控件来切换页码时,Pagination 组件 会触发 update:currentPage 事件更新外部的 currentPage 绑定的变量。
使用如下:
import { defineComponent, ref } from "vue";
import { MyPagination } from "../MyPagination";
import "./index.less";
export default defineComponent({
name: "Demo",
setup() {
const currentPage = ref(3);
const pageSize = ref(30);
return () => (
<div class="paginationContainer">
<MyPagination
layout="total, sizes, prev, pager, next, jumper"
total={500}
v-model:pageSize={pageSize.value}
v-model:currentPage ={currentPage.value}
/>
</div>
);
}
});
1.3 total 属性
total 表示数据总数,也是受控属性。
虽然 total 本身不需要 v-mode(因为其通常是只读属性,用于展示总数据量),但在某些场景下会根据后端返回数据动态更新,因此不使用 v-model 绑定的情况较多。
2. 方法
大家如果使用过这个组件,肯定了解其身上存在 4 个常见方法,其中,唯一能够正常使用的方法是 currentChange,而其他方法则需要额外处理才能执行。感兴趣的朋友可以亲自尝试一下,这里就不详细介绍啦。
解决方法,我们点开 Pagination 组件 props 的源码可以看到方法的名称:
因此在使用的时候,严格遵循命名规则,如下:
import { defineComponent, ref } from "vue";
import { MyPagination } from "../MyPagination";
import "./index.less";
export default defineComponent({
name: "Demo",
setup() {
const currentPage = ref(3);
const pageSize = ref(30);
const handleCurrentChange = (val) => {
console.log(`当前页码已变更,新的页码为:${val} 页`);
};
const handleSizeChange = (size) => {
console.log(`每页显示的条数已变更,新的条数为:${size} 条`);
};
const handlePrevClick = (page) => {
console.log(`点击上一页按钮,点击之前页码为:${page} 页`);
};
const handleNextClick = (page) => {
console.log(`点击下一页按钮,点击之前页码为:${page} 页`);
};
return () => (
<div class="paginationContainer">
<MyPagination
layout="total, sizes, prev, pager, next, jumper"
total={500}
v-model:pageSize={pageSize.value}
v-model:currentPage ={currentPage.value}
onCurrent-change={handleCurrentChange}
onSize-change={handleSizeChange}
onPrev-click={handlePrevClick}
onNext-click={handleNextClick}
/>
</div>
);
}
});
所有的方法均可以成功使用:
如果到目前为止仍然存在一些问题,那么我们就需要使用 emits 来更新数据。
添加如下代码:
import { ElPagination } from 'element-plus';
import './index.less';
export default defineComponent({
name: 'MyPagination',
props: paginationProps,
emits: [
"update:prevClick",
"update:nextClick",
"currentChange",
"update:sizeChange",
],
setup(props, { attrs, slots }) {
return () => (
<div class={`pagination-common`}>
<ElPagination
{...props}
{...attrs}
>
{slots.default ? slots.default() : null}
</ElPagination>
</div>
);
},
});
emits 用于声明组件可以发出的自定义事件。这使得父组件能够监听这些事件,并对其作出响应。通过声明 emits 可以清晰地定义组件的外部接口。
至此,已经解决了我在封装 Pagination 组件所遇到的问题,如果还有其他的问题,可以继续深入探讨。