关注前端小讴,阅读更多原创技术文章
【组件化】是每一个前端工程师的必备技能,诚然我们将element、iview、vant等UI组件库运用得娴熟自如,实际开发中还是经常需要封装更适合的业务组件,既帮助快速开发、又让代码简洁明了、还能锻炼我们的组件化能力。
梳理思路
以node.js官网的分页组件为例,假设我们要实现下面这样的分页:
从产品角度梳理思路后,要实现的分页组件有以下特点:
1.当前页页码颜色变化
2.最多显示5个页码,不足5个显示实际数量
3.总页数超过5个时:总页码-当前页>2,则末尾显示省略号;当前页>2,则开头显示省略号
4.总页数超过5个时:当前页为最后1页,则一共显示3个页码;当前页为倒数第二页,则一共显示4个页码;其余均显示5个页码
5.总页数超过5个、且同时满足总页码-当前页>2和当前页>2时,当前页总是显示在5个页码的最中间
6.点击最左、最右侧箭头,分别跳转到第1、最后1页
基本结构
先写一个静态的结构:
{{'«'}}
...
{{pageNum}}
...
{{'»'}}
在父组件引用该组件:
此时效果:将看到一个标准的、大于5页的静态分页:
props接收值
组件的某些值应该是父组件传递过来的,通过计算后挂载
props: {
// 内容总数
total: {
type: Number,
default: 0
},
// 每页数量
limit: {
type: Number,
default: 10
},
// 当前页码
page: {
type: Number,
default: 1
},
},
data () {
return {
pageList: [] // 页码列表
};
},
computed: {
// 最大页数
pageMax () {
return Math.ceil(this.total / this.limit);
},
},
onLoad () { // 我的框架是mpvue,vue用created
this.initData();
},
methods: {
// 生成pageList页码列表
initData () {
this.pageList = []; // 清空页码
var i = 1;
do {
this.pageList.push(i);
i++;
} while (i <= this.pageMax);
this.pageList.length > 5 && (this.pageList = this.pageList.slice(0, 5)); // 最多显示5页
}
}
父组件传递这些值:
data () {
return {
dataList: [], // 列表
page: 1, // 当前页码
limit: 20, // 每页数量
};
},
onLoad () {
this.getData();
},
methods: {
getData () {
// 动态获取列表 - 以后端分页为例
this.dataList = (await getDataList(this.limit, this.page)).data;
}
}
此时效果:将根据父组件——也就是使用该组件的页面——的真实数据,渲染分页组件。页码数量大于5和不大于5组件内容不同,且当前页码为首页
event事件回调
组件中追加事件,回调给父组件(调用的组件):
{{'«'}}
...
{{pageNum}}
...
{{'»'}}
methods: {
// 子组件事件回调:分页
pageChange (page) {
this.$emit("page-change", page);
},
}
父组件执行子组件回调过来的事件:
methods: {
// 分页
pageChange (page) {
this.page = page;
this.getData();
},
}
此时效果:点击页码颜色会发生变化,父组件接收到子组件的回调事件,返回一个值page——即当前页码,可根据页码做分页的内容渲染;点击最左、最右侧箭头,分别跳转到第1、最后1页
watch页码变化
由于不同页码要渲染的组件内容不同,因此需要监听页码变化,刷新组件内容;同时total总数更新时,重新加载组件
watch: {
// 监听页码变化 -> 页码列表更新
page (val) {
if (val <= 3) {
this.pageList = [];
var i = 1;
do {
this.pageList.push(i);
i++;
} while (i <= this.pageMax);
this.pageList.length > 5 && (this.pageList = this.pageList.slice(0, 5)); // 最多显示5页
} else if (val === this.pageMax) {
this.pageList = [val - 2, val - 1, val];
} else if (val === this.pageMax - 1) {
this.pageList = [val - 2, val - 1, val, val + 1];
} else {
this.pageList = [val - 2, val - 1, val, val + 1, val + 2];
}
},
// 监听页码变化 -> 总数更新
total (val) {
this.initData();
}
}
此时效果:组件根据页码变化及数量变化,渲染出不同的内容,至此该分页组件全部内容完成
扩展
可以像element和iview那样,为组件追加当前页显示数量下拉框,也可以由父组件决定子组件的样式布局,页码按钮的数量(本例为最大5个)。。。总体思路不变,即:
1.子组件接收值并根据值而改变渲染
2.子组件追加事件,回调给父组件
3.根据需要追加监听
完整代码
{{'«'}}
...
{{pageNum}}
...
{{'»'}}
api
props:
属性 | 说明 | 类型 | 默认值 |
---|---|---|---|
total | 内容总数 | Number | 0 |
limit | 每页数量 | Number | 10 |
page | 当前页码 | Number | 1 |
events:
事件名 | 说明 | 返回值 |
---|---|---|
page-change | 页码改变的回调,返回改变后的页码 | 当前页码 |