这里要分两步,
-
第一步:如何生成分页条
-
可以看到所有的分页栏内容都是写死的。
(1)
-
当前页:肯定是由页面来决定的,点击按钮会切换到对应的页
-
总页数:需要后台传递给我们
-
总条数:需要后台传递给我们
var vm = new Vue({
el: "#searchApp",
data: {
ly,
search:{
key:"", // 搜索页面的关键字
page: 1,
},
goodsList:[],
total: 0, // 总条数
totalPage: 0 ,// 总页数
},
created(){
// 判断是否有请求参数
if(!location.search){
return;
}
// 调用common.js文件中定义的方法,将请求参数字符串格式化为js对象
const search = ly.parse(location.search.substring(1));
//对page进行初始化,防止第一次访问时,page为空
search.page=search.page ? parseInt(search.page) : 1;
// 记录在data的search对象中
this.search = search;
// 发起请求,根据条件搜索
this.loadData();
},
(2)后台提供数据
(3)
loadData(){
// ly.http.post("/search/page", ly.stringify(this.search)).then(resp=>{
//注意:http在common.js文件定义的,实际上就是axios
//resp表示后台响应的数据对象,resp.data为数据
ly.http.post("/search/page", this.search).then(resp=>{
if(resp.data.items.length===0){
return
}
this.total=resp.data.total;
this.totalPage=resp.data.totalPage;
//遍历goodsList集合
resp.data.items.forEach(goods=>{
//将skus字段这个json字符串转换为json对象
goods.skus=JSON.parse(goods.skus);
//扩展一个selected属性
goods.selected=goods.skus[0];
});
this.goodsList=resp.data.items;
});
然后看下我们要实现的效果:
思路分析:
-
最多有5个按钮,因此我们可以用
v-for
-
但是分页条不一定是从1开始:
-
如果当前页值小于等于3的时候,分页条位置从1开始到5结束
-
如果总页数小于等于5的时候,分页条位置从1开始到总页数结束
-
如果当前页码大于3,应该从page-3开始
-
但是如果当前页码大于totalPage-3,应该从totalPage-5开始
-
举例分析:若总页数为50
<!--分页部分--> <div class="fr"> <div class="sui-pagination pagination-large"> <ul> <li class="prev disabled"> <a href="#">«上一页</a> </li> <!--通过v-for 遍历生成指定个数的li标签,当totalpage<5时,li个标签数为totalpage--> <!--active 通过判断当前页是否等于index(i),设置li标签是否为激活状态--> <li :class="{active : search.page==index(i)}" v-for="i in Math.min(5,totalPage)"> <a href="#">{{index(i)}}</a> </li> <li class="dotted"><span>...</span></li> <li class="next"> <a href="#">下一页»</a> </li> </ul> <div><span>共10页 </span><span> 到第 <input type="text" class="page-num"> 页 <button class="page-confirm" onclick="alert(1)">确定</button></span></div> </div> </div>
效果图:
2.
所以,我们在上一页
、下一页
<!--分页部分--> <div class="fr"> <div class="sui-pagination pagination-large"> <ul> <!--若当前页是1,则li标签为失效模式--> <li class="prev " :class="{disabled: search.page==1}" @click="prev()"> <a href="#">«上一页</a> </li> <!--通过v-for 遍历生成指定个数的li标签,当totalpage<5时,li个标签数为totalpage--> <!--active 通过判断当前页是否等于index(i),设置li标签是否为激活状态--> <!--@click="search.page=index(i) 绑定点击事件,将当前页设置为index(i)的索引值--> <li :class="{active : search.page==index(i)}" v-for="i in Math.min(5,totalPage)" @click="search.page=index(i)"> <a href="#">{{index(i)}}</a> </li> <li class="dotted"><span>...</span></li> <li class="next" :class="{disabled: search.page==totalPage}" @click="next()"> <a href="#">下一页»</a> </li> </ul> <div><span>共10页 </span><span> 到第 <input type="text" class="page-num"> 页 <button class="page-confirm" onclick="alert(1)">确定</button></span></div> </div> </div>
翻页事件的方法(vue对象中的方法):
prev(){ //上一页:当前页>1 if(this.search.page>1){ this.search.page--; } }, next(){ //下一页:当前页比总页数少 if(this.search.page<this.totalPage){ this.search.page++; } },
效果图(重点看分页条):
不过,如果我们直接发起ajax请求,那么浏览器的地址栏中是不会有变化的,没有记录下分页信息。如果用户刷新页面,那么就会回到第一页。
这样不太友好,我们应该把搜索条件记录在地址栏的查询参数中。
watch:{
search:{
deep:true,
handler(val){
// 把search对象变成请求参数,拼接在url路径
window.location.href = "http://www.leyou.com/search.html?" + ly.stringify(val);
}
}
},
因为Vue实例初始化的钩子函数中,我们读取请求参数,赋值给search的时候,也触发了watch监视!也就是说,每次页面创建完成,都会触发watch,然后就会去修改window.location路径,然后页面被刷新,再次触发created钩子,又触发watch,周而复始,无限循环。
所以,我们需要在watch中进行监控,如果发现是第一次初始化,则不继续向下执行。
那么问题是,如何判断是不是第一次?
watch:{
search:{
deep:true,
handler(val,old){
if(!old || !old.key){
// 如果旧的search值为空,或者search中的key为空,证明是第一次
return;
}
// 把search对象变成请求参数,拼接在url路径
window.location.href = "http://www.leyou.com/search.html?" + ly.stringify(val);
}
}
}
3.
<div class="top-pagination"> <span>共 <i style="color: #222;">{{total}}+</i> 商品</span> <span><i style="color: red;">{{search.page}}</i>/{{totalPage}}</span> <a class="btn-arrow" href="#" style="display: inline-block" @click="prev()"><</a> <a class="btn-arrow" href="#" style="display: inline-block" @click="next()">></a> </div>
分页最终效果图: