前言
上篇文章中, 已经使用 vue 实现前端分页效果, 这篇文章我们单独将分页抽离出来实现一个分页组件
先看实现效果图
代码实现
按照惯例, 我们在冻手实现的时候还是先想一想 vue 实现组件的思路
1, 需要提前设定哪些参数需要暴露出来给父组件传递
- <Paging
- :name="name"
- @change="onPageChange"
- :page-size="size"
- :total="total"
- layout="jumper,total"
- :current-page="curPage"
- />
方法及参数说明
属性
page-size 每页显示条目个数
total 总条目数
current-page 当前页数
layout 布局 默认不显示 jumper,total
事件
change 当前页改变时触发
2, 再一个就是涉及到的父子组件通信
这里主要通过 props 向子组件传递参数
在子组件中使用 emit 自定义事件返回数据给父组件
a. 字符串数组形式 props
props: ['title', 'likes', 'isPublished', 'commentIds', 'author']
或者指定每个 prop 的值类型
- props: {
- title: String,
- likes: Number,
- isPublished: Boolean,
- commentIds: Array,
- author: Object
- }
b.props 验证
- props: {
- // 基础的类型检查 (`null` 匹配任何类型)
- propA: Number,
- // 多个可能的类型
- propB: [String, Number],
- // 必填的字符串
- propC: {
- type: String,
- required: true
- },
- // 带有默认值的数字
- propD: {
- type: Number,
- default: 100
- },
- // 带有默认值的对象
- propE: {
- type: Object,
- // 对象或数组默认值必须从一个工厂函数获取
- default: function () {
- return { message: 'hello' }
- }
- },
- // 自定义验证函数
- propF: {
- validator: function (value) {
- // 这个值必须匹配下列字符串中的一个
- return ['success', 'warning', 'danger'].indexOf(value) !== -1
- }
- }
- }
使用 props 传递数据给子组件 , 子组件主要有三种形式来接收到父组件传递过来的参数
props 字符串数组, 指定每个 prop 值类型以及 props 验证, 通常我们会使用 props 验证
分析完之后, 接下来我们可以冻手实现了
1, 这里我们用 vue-cli 先创建一个 vue 项目
安装 vue-cli
$NPM install -g vue-cli
创建 vue 项目
$vue init webpack my-project
项目运行
- $cd my-project
- $NPM run dev
2, 在 components 文件下创建一个 Paging 组件
- <template>
- <div class="paging clearfix">
- <div class="page-size fl" v-if="isShowTotal">共 {{total}} 条</div>
- <ul class="page-list fl clearfix">
- <li @click="changePage(currentPage-1)">上一页</li>
- <li :class="{'active':currentPage==item.val}" v-for="item in pagelist" v-text="item.text" @click="changePage(item.val)">1</li>
- <li @click="changePage(currentPage+1)">下一页</li>
- </ul>
- <div class="page-jump fl" v-if="isShowJumper">
前往 < input class="input" type="text" v-model="toPage" @keydown="submit(toPage,$event)">页
- <!-- <button @click="changePage(toPage)">确定</button> -->
- </div>
- </div>
- </template>
- <script>
- export default {
- name: 'Paging',
- // props:[
- // 'name'
- // ],
- // prop 验证
- props:{
- name:String,
- pageSize: {
- type: Number,
- default: 10
- },
- total: {
- type: Number,
- default: 0
- },
- currentPage: {
- type: Number,
- default: 1
- },
- layout:{
- type: String
- }
- },
- data () {
- return {
- isShowJumper:false,
- isShowTotal:false,
- toPage:'',// 跳转到 x 页
- pageGroup:10// 可见分页数量 默认 10 个分页数
- }
- },
- created: function () {
- console.log('created');
- this.isShowTotal = this.layout.indexOf('total')!==-1;
- this.isShowJumper = this.layout.indexOf('jumper')!==-1;
- },
- mounted: function () {
- console.log('mounted',this.layout);
- },
- computed:{
- totalPage:function(){
- return Math.ceil(this.total / this.pageSize)
- },
- pagelist:function(){
- var list = [];
- var count = Math.floor(this.pageGroup/2), center = this.currentPage;
- var left = 1,right = this.totalPage;
- if(this.totalPage>this.pageGroup){
- if(this.currentPage>count+1){
- if(this.currentPage <this.totalPage - count){
- left = this.currentPage - count;
- right = this.currentPage + count-1;
- }else{
- left = this.totalPage - this.pageGroup+1;
- }
- }else{
- right = this.pageGroup;
- }
- }
- // 遍历添加到数组里
- while(left<=right){
- list.push({
- text:left,
- val:left
- });
- left++;
- }
- return list;
- }
- },
- methods:{
- // 回车事件
- submit(toPage,e){
- // console.log('e.keyCode',toPage,e.keyCode)
- // key.Code === 13 表示回车键
- if(e.keyCode === 13){
- // 逻辑处理
- this.changePage(toPage);
- }
- },
- changePage:function(idx){
- if(idx!=this.currentPage && idx>0 && idx<=this.totalPage){
- // 触发父组件事件 pageChange 会转换成小写 pagechange
- this.$emit('change',{curPage:Number(idx)});
- }
- }
- }
- }
- </script>
- <!-- Add "scoped" attribute to limit CSS to this component only -->
- <style scoped>
- *{
- padding: 0;
- margin: 0;
- }
- .fl{
- float: left;
- }
- .clearfix:after{
- display: block;
- content: '';
- clear: both;
- }
- .page-size{
- height: 26px;
- line-height: 26px;
- }
- .page-list{
- }
- .page-jump{
- height: 26px;
- line-height: 26px;
- margin-left: 20px;
- }
- .page-jump .input{
- width: 32px;
- padding: 4px 2px;
- border-radius: 2px;
- border: 1px solid #dcdfe6;
- margin: 0 4px;
- }
- ul{
- list-style: none;
- }
- ul li{
- float: left;
- color: #606266;
- background: #f4f4f5;
- padding: 2px 8px;
- cursor: pointer;
- border-radius: 2px;
- margin: 0 5px;
- }
- ul>li.active{
- background: #409eff;
- color:#fff;
- }
- </style>
3, 在父组件中引入并使用组件
- <template>
- <div>
- <!-- 分页组件 -->
- <Paging
- :name="name"
- @change="onPageChange"
- :page-size="size"
- :total="total"
- layout="jumper,total"
- :current-page="curPage"
- />
- </div>
- </template>
- <!--
- Paging 属性
- page-size 每页显示条目个数
- total 总条目数
- current-page 当前页数
- layout 布局 默认不显示 jumper,total
- Paging 事件
- change 当前页改变时触发
- -->
- <script>
- import Paging from '@/components/Paging';
- export default {
- name: 'Index',
- components:{
- Paging
- },
- data () {
- return {
- msg: 'hello',
- name:'阿健 a',
- size:10,
- total:201,
- curPage:1
- }
- },
- methods:{
- onPageChange:function(page){
- this.curPage = page.curPage;
- }
- }
- }
- </script>
遇到的问题
1, 在子组件中修改 currentPage 时报错
Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders
在使用组件时, 传入的 prop, 被组件内部又做了一次修改
避免直接修改 prop, 因为当父组件重新呈现时, 值将被覆盖
- changePage:function(idx){
- if(idx!=this.currentPage && idx>0 && idx<=this.totalPage){
- this.currentPage = idx;
- // 触发父组件事件 pageChange 会转换成小写 pagechange
- this.$emit('change');
- }
- }
解决
修改代码, 通过 emit 传递 curPage 给父组件, 让父组件修改
- changePage:function(idx){
- if(idx!=this.currentPage && idx>0 && idx<=this.totalPage){
- // 触发父组件事件 pageChange 会转换成小写 pagechange
- this.$emit('change',{curPage:idx});
- }
- }
父组件监听事件更新 curPage
- onPageChange:function(page){
- this.curPage = page.curPage;
- }
最后
以上就是分页组件的整个实现过程 , 其实只要搞清楚父子组件是如何传参的, 以及我们实现一个组件需要暴露哪些参数给父组件, 整个实现过程还是不难的
来源: https://www.cnblogs.com/fozero/p/9874334.html