场景
- 小程序分页
- 分页的时候,如果用户在服务端返回数据之前,快速的多次触底(触发下一页请求的问题)
分析
- 小程序实现分页的方式分为两种
- 一种是使用scroll-view, 通过bindscrolltolower属性绑定处理;但是在纵向滚动的时候需要设置height, 这极可能导致图片被截断展示
- 另外一种是Page 的onReachBottom(触底)生成周期, 捕捉到事件,
- 组件中是没有这个生命周期的,但是可以在Page捕捉, 然后通过(不断变动的)属性和子组件通信, 子组件通过监控这个属性的变化(observer) 来判断加载下一页的时机
- 在触发下一页的时候 (重复加载数据的问题)
- 问题 如果在服务器还没有返回数据, 用户又再触底(上滑 然后下滑) 则会导致数据重复加载
- 解决 加锁, 如果上次请求没有返回 则不可以再次请求
解决
分页 将得到下一页的数据合并到原有的数据之上
需要避免死锁, 需要捕捉服务器返回异常的时候,将锁解开
_onNext(new_value, old_value) {
if (!this._canGetNext()) {
return;
}
this.setData({lock: true});
book_model.getSearchResult(this.data.input, this.data.page + 1).then(response => {
console.log(response, '搜索下一页书籍', new_value, old_value);
let list_search_result = this.data.list_search_result.concat(response.books);
this.setData({
list_search_result,
total: response.total,
page: response.page,
page_size: response.page_size,
lock: false
});
}).catch(response=>{
this.setData({
lock : false
});
});
完整代码
import KeywordModel from '../../models/keyword.js';
import BookModel from '../../models/book.js';
let keyword_model = new KeywordModel(),
book_model = new BookModel();
Component({
properties: {
unique_flag: {
type: String,
observer: '_onNext'
}
},
data: {
list_history: [],
list_hots: [],
list_search_result: [],
searching: 1,
input: '',
page: 1,
page_size: 10,
total: '',
lock: false,
},
attached: function() {
this.initEnv();
},
methods: {
_onNext(new_value, old_value) {
if (!this._canGetNext()) {
return;
}
this.setData({lock: true});
book_model.getSearchResult(this.data.input, this.data.page + 1).then(response => {
console.log(response, '搜索下一页书籍', new_value, old_value);
let list_search_result = this.data.list_search_result.concat(response.books);
this.setData({
list_search_result,
total: response.total,
page: response.page,
page_size: response.page_size,
lock: false
});
}).catch(response=>{
this.setData({
lock : false
});
});
},
_canGetNext() {
if (this.data.total - this.data.page * this.data.page_size <= 0) {
return false;
}
if (!this.data.input) {
return false;
}
if (this.data.lock) {
return false;
}
return true;
},
onClear(event) {
if (!this.data.input) {
return;
}
this.setData({
input: '',
searching: 1
});
this._initHistory();
},
initEnv() {
this._initHistory();
this._initHot();
},
_initHistory() {
let list_history = keyword_model.getHistory();
this.setData({
list_history
});
},
_initHot() {
keyword_model.getHot().then(response => {
this.setData({
list_hots: response.hot ? response.hot : []
});
});
},
onCannel(event) {
this.triggerEvent('cannel', {});
},
onTouch(event) {
console.log(event, '标签触摸事件');
let keyword = event.detail.content || event.detail.value;
if (!keyword) {
return;
}
this.setData({searching: 2});
book_model.getSearchResult(keyword).then(response => {
console.log(response, '搜索书籍');
keyword_model.addToHistory(keyword);
this.setData({
list_search_result: response.books ? response.books : [],
searching: 3,
input: keyword,
total: response.total,
page: response.page,
page_size: response.page_size
});
});
},
}
})