目录
一、全局
修改pages.json的"enablePullDownRefresh": true,
{
"pages": [
{
"path": "pages/tabBar/dashboard/index",
"style": {
"navigationBarTitleText": "项目管理",
"enablePullDownRefresh": true,
"navigationBarTextStyle": "white",
"navigationBarBackgroundColor": "#374449"
}
},
],
"globalStyle": {
"navigationBarTextStyle": "black",
"navigationBarTitleText": "管理平台",
"navigationBarBackgroundColor": "#F8F8F8",
"backgroundColor": "#F8F8F8"
},
}
页面中(onPullDownRefresh 处理函数和onLoad等生命周期函数同级 )
export default {
data() {
return {
productList: [], //列表
query: {
keyword: '', //搜索框
pagesize: 10,
page: 1,
},
total: 0, //总条数
showTotal: true, //是否显示“下拉加载更多~”
}
},
// 下拉刷新
onPullDownRefresh() {
var allTotal = this.query.page * this.query.pagesize
//this.page为加载次数,this.pageSize为每一次加载的数据条数
if (allTotal < this.total) {
//this.total为请求数据的总条数。只要现有条数小于总条数就执行一下代码
this.showTotal = true;
this.query.page++;
//加载次数递加
this.getlist() //请求更多数据列表
} else {
this.showTotal = false;
}
uni.stopPullDownRefresh();//停止刷新
},
}
二、局部
我使用的是插件https://ext.dcloud.net.cn/plugin?id=343
插件文档https://www.mescroll.com/uni.html
这个插件的还有相对应的案例我已经下载下来了,到时候直接放到编辑器打开即可 链接:https://pan.baidu.com/s/1q6IB-mCdCQqcvKaZmzJtcg 提取码:e66j
我的需求是顶部内容固定不动,列表下拉刷新(没有页码,数据一次性展示)
1、一个页面一个下拉刷新
页面使用
<template>
<view class="details-container">
<view class="example-body">
<view v-for="(item,index) in tags" :key="index"
:class="whichSelected===index?'stateBtnSelected':'stateBtnNoselect'" :circle="true"
@click="selectState(index)">{{item}}</view>
</view>
<view class="center" v-show="tabs===0">
<!-- 第一步:参数一个都不能少,三个事件是固定的 -->
<mescroll-body ref="mescrollRef" @init="mescrollInit" @down="downCallback" @up="upCallback"
:down="downOption" :up="upOption">
<Tree :list="list" :local='local'></Tree>
</mescroll-body>
</view>
</view>
</template>
<script>
import Tree from '../../components/Tree/index.vue'
//第二步:引入
import MescrollMixin from "@/uni_modules/mescroll-uni/components/mescroll-uni/mescroll-mixins.js";
export default {
mixins: [MescrollMixin],//第二步:引入
name: 'Details',
components: {
Tree,
},
data() {
return {
tags: [],
whichSelected: 0, //标签
tabs: 0, //标签对应页面
list: [], //列表
content: {}, //上一页数据
local: '',
//第三步:数据
//downOption和upOption的参数配置在mescroll-uni.js中查看
downOption: {
auto: false // 不自动加载 (mixin已处理第一个tab触发downCallback)
},
upOption: {
use: false, // 是否启用上拉加载; 默认true
auto: false
}
};
},
onLoad(e) {
let that = this
this.local = uni.getLocale()
this.content = JSON.parse(e.item)
if (this.local === 'zh-Hans') {
uni.setNavigationBarTitle({
title: that.content.Name,
})
} else {
uni.setNavigationBarTitle({
title: that.content.Name_EN,
})
}
this.GetFileListById()
this.tags.push(this.$t('word.whole'))
},
methods: {
//第三步:事件
/*下拉刷新的回调 */
downCallback() {
let that = this
this.api.GetFileListById({ //调用接口
datagramsid: that.content.Id
}).then(res => {
that.list = res.data.Data
this.$nextTick(() => {
this.mescroll.endSuccess(this.list.length)
})
}).catch(() => {
//联网失败, 结束加载
this.mescroll.endErr();
})
},
/*上拉 */
upCallback() {
let that = this
this.api.GetFileListById({ //调用接口
datagramsid: that.content.Id
}).then(res => {
that.list = res.data.Data
let curPageLen = this.list.length;
// 接口返回的是否有下一页 (true/false)
let hasNext = false;
setTimeout(() => {
this.mescroll.endSuccess(curPageLen, hasNext)
}, 20)
}).catch(() => {
//联网失败, 结束加载
this.mescroll.endErr();
})
},
GetFileListById() {
let that = this
this.api.GetFileListById({
datagramsid: that.content.Id
}).then(res => {
that.list = res.data.Data
})
},
}
}
</script>
2、一个页面多个下拉刷新(切换时滚动条回到顶部)
多页tabs切换,实现下拉刷新(没有页码,数据一次性展示) ,每个tab页面内容都不相同
插件上说不能使用v-if,是因为使用了v-if就不能实现切换tabs恢复滚动条位置(v-if是创建和销毁,v-show是隐藏和显示)。
但是我使用官方示例的代码重新加载列表数据或其他的方法都不行
// 详情返回列表,重新加载列表数据 onShow() { this.canReset && this.mescroll.resetUpScroll() // 重置列表数据为第一页 this.canReset && this.mescroll.scrollTo(0,0) // 重置列表数据为第一页时,建议把滚动条也重置到顶部,避免无法再次翻页的问题 this.canReset = true // 过滤第一次的onShow事件,避免初始化界面时重复触发upCallback, 无需配置auto:false // 注意: 子组件没有 onShow 的生命周期, 所以 // 对于 mescroll-more.vue 和 mescroll-swiper.vue 的返回刷新, 需更新 1.3.3 版本, 且参考对应示例的onShow写法 }
若是换成mescroll-body,并且使用v-show会出现切换tabs滚动条位置一致,也就是上一页滚动条在哪,下一页的滚动条就在哪。找了好久也不知道问题出在哪里,最后我只能写成组件使用mescroll-uni+v-if的方法。
但是你们使用还是要先根据官网来做,如果出现我这样的问题再安装我的方法做
第一步:创建组件放置tabs所对应的页面(这里我就只写一个子组件的格式)
pages/word/components/all.vue
注意:子组件使用onShow、onLoad无效,需要写在created中才行
<template>
<!-- 不能用v-if (i: 每个tab页的专属下标; index: 当前tab的下标; 申明在 MescrollMoreItemMixin )-->
<view v-if="i === index">
<mescroll-uni ref="mescrollRef0" top="92" @init="mescrollInit" @down="downCallback" @up="upCallback"
:down="downOption" :up="upOption">
<!-- 数据列表 -->
<Tree :list="list" :local='local'></Tree>
</mescroll-uni>
</view>
</template>
<script>
import Tree from '@/components/Tree/index.vue'
import MescrollMixin from "@/uni_modules/mescroll-uni/components/mescroll-uni/mescroll-mixins.js";
import MescrollMoreItemMixin from "@/uni_modules/mescroll-uni/components/mescroll-uni/mixins/mescroll-more-item.js";
export default {
mixins: [MescrollMixin, MescrollMoreItemMixin], // 使用mixin (在main.js注册全局组件)
components: {
Tree,
},
props: {
i: Number, // 每个tab页的专属下标 (除了支付宝小程序必须在这里定义, 其他平台都可不用写, 因为已在MescrollMoreItemMixin定义)
index: { // 当前tab的下标 (除了支付宝小程序必须在这里定义, 其他平台都可不用写, 因为已在MescrollMoreItemMixin定义)
type: Number,
default () {
return 0
}
},
tabs: { // 为了请求数据,演示用,可根据自己的项目判断是否要传
type: Array,
default () {
return []
}
}
},
data() {
return {
list: [], //下载列表
local: '',
downOption: {
auto: false // 不自动加载 (mixin已处理第一个tab触发downCallback)
},
upOption: {
use: false, // 是否启用上拉加载; 默认true
auto: false
}
}
},
created() {
this.local = uni.getLocale()
},
methods: {
/*上拉加载的回调: 其中page.num:当前页 从1开始, page.size:每页数据条数,默认10 */
downCallback() {
this.mescroll.resetUpScroll()
},
upCallback(page) {
let pageNum = page.num
this.api.GetFileTreeJson().then(res => {
// console.log(res.data.Data)
this.list = res.data.Data
this.mescroll.endByPage(this.list.length, 1);
//设置列表数据
if (page.num == 1) this.list = []; //如果是第一页需手动制空列表
this.list = this.list.concat(res.data.Data); //追加新数据
}).catch(() => {
//联网失败, 结束加载
this.mescroll.endErr();
})
},
}
}
</script>
pages/word/components/downitem.vue和上一个组件一致,只不过数据组件不一致,多了一个获取列表的方法给父组件使用
<template>
<!-- 不能用v-if (i: 每个tab页的专属下标; index: 当前tab的下标; 申明在 MescrollMoreItemMixin )-->
<view v-if="i === index">
<mescroll-uni ref="mescrollRef1" @init="mescrollInit" top="92" :down="downOption" @down="downCallback"
:up="upOption" @up="upCallback" @emptyclick="emptyClick">
<DownTree :records="records" :local='local'></DownTree>
</mescroll-uni>
</view>
</template>
<script>
import DownTree from '@/components/DownTree/index.vue'
import MescrollMixin from "@/uni_modules/mescroll-uni/components/mescroll-uni/mescroll-mixins.js";
import MescrollMoreItemMixin from "@/uni_modules/mescroll-uni/components/mescroll-uni/mixins/mescroll-more-item.js";
export default {
mixins: [MescrollMixin, MescrollMoreItemMixin],
components: {
DownTree
},
props: {
i: Number, // 每个tab页的专属下标 (除了支付宝小程序必须在这里定义, 其他平台都可不用写, 因为已在MescrollMoreItemMixin定义)
index: { // 当前tab的下标 (除了支付宝小程序必须在这里定义, 其他平台都可不用写, 因为已在MescrollMoreItemMixin定义)
type: Number,
default () {
return 0
}
},
tabs: { // 为了请求数据,演示用,可根据自己的项目判断是否要传
type: Array,
default () {
return []
}
}
},
data() {
return {
records: [], //下载列表
local: '',
downOption: {
auto: false // 不自动加载 (mixin已处理第一个tab触发downCallback)
},
upOption: {
use: false, // 是否启用上拉加载; 默认true
auto: false
}
}
},
created() {
this.local = uni.getLocale()
},
methods: {
/*下拉刷新的回调 */
downCallback() {
this.mescroll.resetUpScroll()
},
upCallback(page) {
let pageNum = page.num
this.api.GetWxUserDownloadList().then(res => {
this.records = res.data.Data
this.mescroll.endByPage(this.records.length, 1);
//设置列表数据
if (page.num == 1) this.records = []; //如果是第一页需手动制空列表
this.records = this.records.concat(res.data.Data); //追加新数据
}).catch(() => {
//联网失败, 结束加载
this.mescroll.endErr();
})
},
getrecords() {
this.api.GetWxUserDownloadList().then(res => {
this.records = res.data.Data
this.mescroll.endByPage(this.records.length, 1);
//设置列表数据
if (page.num == 1) this.records = []; //如果是第一页需手动制空列表
this.records = this.records.concat(res.data.Data); //追加新数据
}).catch(() => {
//联网失败, 结束加载
this.mescroll.endErr();
})
},
}
}
</script>
第三步:在页面中使用pages/word/components/index.vue
<template>
<view class="word-container">
<view class="example-body">
<view v-for="(item,index) in tags" :key="index"
:class="tabIndex===index?'stateBtnSelected':'stateBtnNoselect'" :circle="true"
@click="tabChange(index)" @input="changeload" v-model="tabIndex">{{item}}</view>
</view>
<!-- 全部 -->
<mescroll-all ref="mescrollItem0" :i="0" :index="tabIndex" :tabs="tags">
</mescroll-all>
<!-- 下载记录 -->
<MescrollDown ref="mescrollItem1" :i="1" :index="tabIndex" :tabs="tags">
</MescrollDown>
</view>
</template>
<script>
import MescrollAll from "./components/all.vue";
import MescrollDown from "./components/downitem.vue";
import MescrollMoreMixin from "@/uni_modules/mescroll-uni/components/mescroll-uni/mixins/mescroll-more.js";
export default {
mixins: [MescrollMoreMixin],
name: 'Word',
components: {
MescrollDown,
MescrollAll,
},
data() {
return {
tags: [],
local: '',
tabIndex: 0,//标签对应页面
};
},
onLoad() {
this.tags.push(this.$t('word.whole'), this.$t('word.download'))
uni.setNavigationBarTitle({
title: this.$t('pages.word'),
})
},
onShow() {
this.tabIndex = this.$store.state.tabs
this.local = uni.getLocale()
if (this.whichSelected === 1) {
const Token = uni.getStorageSync('GetPhone_Token')
if (Token) {
//点击下载列表tab的时候要判断有没有token,没有就要跳转到登录页,我登录成功后返回到这一页
//若是我不调用子组件的方法也就是获取列表数据,会出现一直显示加载中,所以我这里调用了方法,下面的标签切换同理
this.$refs.mescrollItem1.getrecords()
} else {
uni.navigateTo({
url: '/pages/login/index'
});
}
}
},
methods: {
// 标签切换
tabChange(index) {
this.whichSelected = index
this.tabIndex = index
this.$store.commit('SET_TABS', index)
if (this.tabIndex === 1) {
const Token = uni.getStorageSync('GetPhone_Token')
if (Token) {
this.$refs.mescrollItem1.getrecords()
} else {
uni.navigateTo({
url: '/pages/login/index'
});
}
}
},
}
}
</script>
<style lang="scss">
.vue-ref {
padding: 0 !important;
}
.word {
&container {
position: relative;
}
}
.left {
display: flex;
margin: 10px;
}
.example-body {
display: flex;
padding: 10px 20px;
background-color: #fff;
width: 100%;
position: fixed;
z-index: 2;
}
.center {
position: absolute;
top: 45px;
width: 100%;
// height: 100%;
border-top: 1px solid #e5e5e5;
}
.stateBtnSelected {
background-color: #bbe5ff;
color: #1480cd !important;
border-radius: 20px;
font-size: 14px;
height: 25px;
line-height: 25px;
// width: 60px;
margin: 0 5px;
padding: 0 15px;
text-align: center;
}
.stateBtnNoselect {
background-color: transparent;
color: #8f939c !important;
border: none !important;
font-size: 14px;
height: 25px;
line-height: 25px;
// width: 60px;
margin: 0 5px;
padding: 0 15px;
text-align: center;
}
.slot-image {
width: 30px;
height: 30px;
}
.slot-box {
margin-right: 10px;
}
.uni-list-item__container {
align-items: center !important;
line-height: 20px;
}
</style>
3、一个页面多个下拉刷新(切换时恢复滚动条位置)
如果tabs对应内容分别封装成各自组件,子组件封装的时候使用mescroll-uni,并且使用v-show会出现当列表数据多页时切换tabs,恢复滚动条位置不准确并且会触发上拉这样的问题。但是如果我把他放在一个组件里就不会产生这样的问题
第一步:组件pages/word/components/all.vue
Tree和DownTree组件使用的是uni-list的自定义插槽,不知道为啥我使用uni-list-item就会触发一次上拉,之后就不会了,但是不使用就不会触发
<template> <view class="word-container"> <!-- 使用这个切换tabs的时候,会触发上拉一次,之后就不会再触发了 --> <!-- <uni-list> <uni-list-item v-for="(item,index) in records" :key='index' :title="local==='zh-Hans'?item.filename:item.filename_EN" thumb-size="lg" :rightText="item.DownloadTime"> <template v-slot:header> <view class="slot-box"> <image v-if="item.fileExt==='.mp4'" class="slot-image" src="/static/shipin_lvhangyingxiang.png" mode="widthFix"> </image> <image v-else-if="item.fileExt==='.pdf'" class="slot-image" src="/static/pdfwenjian.png" mode="widthFix"> </image> <image v-else class="slot-image" src="/static/a-wenjianjiawenjian.png" mode="widthFix"> </image> </view> </template> </uni-list-item> </uni-list> --> <uni-list v-for="(item,j) in records" :key='j'> <view :border="none" :padding="0" :spacing="0" style="padding:0" :is-shadow="false" :isFull="true"> <view class="card-title" style="display: flex;justify-content: space-between;"> <view> <image v-if="item.fileExt==='.mp4'" class="slot-image" src="/static/shipin_lvhangyingxiang.png" mode="widthFix"> </image> <image v-else-if="item.fileExt==='.pdf'" class="slot-image" src="/static/pdfwenjian.png" mode="widthFix"> </image> <image v-else class="slot-image" src="/static/a-wenjianjiawenjian.png" mode="widthFix"> </image> </view> <view class="title-box" style="display: flex;justify-content: space-between;width: 100%;align-items: center;"> <view class="">{{local==='zh-Hans'?item.filename:item.filename_EN}} </view> <view class="">{{item.DownloadTime}}</view> </view> </view> </view> </uni-list> </view> </template>
<template>
<!-- 不能用v-if (i: 每个tab页的专属下标; index: 当前tab的下标; 申明在 MescrollMoreItemMixin )-->
<view v-show="i === index">
<mescroll-uni :ref="'mescrollRef'+i" top="92" @init="mescrollInit" @down="downCallback" @up="upCallback"
:down="downOption" :up="upOption">
<!-- 数据列表 -->
<!-- tab为0的时候 -->
<Tree v-if="index===0" :list="list" :local='local'></Tree>
<!-- tab为1的时候 -->
<DownTree v-else :records="records" :local='local'></DownTree>
</mescroll-uni>
</view>
</template>
<script>
import DownTree from '@/components/DownTree/index.vue'
import Tree from '@/components/Tree/index.vue'
import MescrollMixin from "@/uni_modules/mescroll-uni/components/mescroll-uni/mescroll-mixins.js";
import MescrollMoreItemMixin from "@/uni_modules/mescroll-uni/components/mescroll-uni/mixins/mescroll-more-item.js";
export default {
mixins: [MescrollMixin, MescrollMoreItemMixin], // 使用mixin (在main.js注册全局组件)
components: {
Tree,
DownTree
},
props: {
i: Number, // 每个tab页的专属下标 (除了支付宝小程序必须在这里定义, 其他平台都可不用写, 因为已在MescrollMoreItemMixin定义)
index: { // 当前tab的下标 (除了支付宝小程序必须在这里定义, 其他平台都可不用写, 因为已在MescrollMoreItemMixin定义)
type: Number,
default () {
return 0
}
},
tabs: { // 为了请求数据,演示用,可根据自己的项目判断是否要传
type: Array,
default () {
return []
}
}
},
data() {
return {
list: [], //下载列表
local: '',
records: [], //下载列表
downOption: {
auto: false // 不自动加载 (mixin已处理第一个tab触发downCallback)
},
upOption: {
use: false, // 是否启用上拉加载; 默认true
auto: false
}
}
},
created() {
this.local = uni.getLocale()
},
methods: {
/*上拉加载的回调: 其中page.num:当前页 从1开始, page.size:每页数据条数,默认10 */
downCallback() {
this.mescroll.resetUpScroll()
},
upCallback(page) {
if (this.index === 0) {
let pageNum = page.num
this.api.GetFileTreeJson().then(res => {
// console.log(res.data.Data)
this.list = res.data.Data
this.mescroll.endByPage(this.list.length, 1);
//设置列表数据
if (page.num == 1) this.list = []; //如果是第一页需手动制空列表
this.list = this.list.concat(res.data.Data); //追加新数据
}).catch(() => {
//联网失败, 结束加载
this.mescroll.endErr();
})
} else {
this.api.GetWxUserDownloadList().then(res => {
// console.log(res.data.Data)
this.records = res.data.Data
this.mescroll.endByPage(this.records.length, 1);
//设置列表数据
if (page.num == 1) this.records = []; //如果是第一页需手动制空列表
this.records = this.records.concat(res.data.Data); //追加新数据
}).catch(() => {
//联网失败, 结束加载
this.mescroll.endErr();
})
}
},
// 文件列表
GetFileTreeJson() {
this.api.GetFileTreeJson().then(res => {
// console.log(res.data.Data)
this.list = res.data.Data
this.mescroll.endByPage(this.list.length, 1);
//设置列表数据
if (page.num == 1) this.list = []; //如果是第一页需手动制空列表
this.list = this.list.concat(res.data.Data); //追加新数据
}).catch(() => {
//联网失败, 结束加载
this.mescroll.endErr();
})
},
getrecords() {
this.api.GetWxUserDownloadList().then(res => {
// console.log(res.data.Data)
this.records = res.data.Data
this.mescroll.endByPage(this.records.length, 1);
//设置列表数据
if (page.num == 1) this.records = []; //如果是第一页需手动制空列表
this.records = this.records.concat(res.data.Data); //追加新数据
}).catch(() => {
//联网失败, 结束加载
this.mescroll.endErr();
})
},
}
}
</script>
第二步:页面使用pages/word/components/index.vue
<template>
<view class="word-container">
<view class="example-body">
<view v-for="(item,index) in tags" :key="index"
:class="tabIndex===index?'stateBtnSelected':'stateBtnNoselect'" :circle="true"
@click="tabChange(index)" @input="changeload" v-model="tabIndex">{{item}}</view>
</view>
<mescrollItem0 ref="mescrollItem0" :i="0" :index="tabIndex" :tabs="tags">
</mescrollItem0>
<mescrollItem0 ref="mescrollItem1" :i="1" :index="tabIndex" :tabs="tags">
</mescrollItem0>
</view>
</template>
<script>
import mescrollItem0 from "./components/all.vue";
import mescrollItem1 from "./components/downitem.vue";
// import MescrollMixin from "@/uni_modules/mescroll-uni/components/mescroll-uni/mescroll-mixins.js";
import MescrollMoreMixin from "@/uni_modules/mescroll-uni/components/mescroll-uni/mixins/mescroll-more.js";
export default {
mixins: [MescrollMixin],
name: 'Word',
components: {
mescrollItem0,
mescrollItem1,
},
data() {
return {
tags: [],
list: [],
records: [], //下载列表
local: '',
tabIndex: 0,//标签对应页面
};
},
onLoad() {
this.tags.push(this.$t('word.whole'), this.$t('word.download'))
uni.setNavigationBarTitle({
title: this.$t('pages.word'),
})
},
onShow() {
this.whichSelected = this.$store.state.tabs
this.tabIndex = this.$store.state.tabs
this.local = uni.getLocale()
if (this.whichSelected === 1) {
const Token = uni.getStorageSync('GetPhone_Token')
if (Token) {
this.$refs.mescrollItem1.getrecords()
} else {
uni.navigateTo({
url: '/pages/login/index'
});
}
}
},
methods: {
// 标签切换
tabChange(index) {
this.whichSelected = index
this.tabIndex = index
this.$store.commit('SET_TABS', index)
if (this.tabIndex === 1) {
const Token = uni.getStorageSync('GetPhone_Token')
if (Token) {
this.$refs.mescrollItem1.getrecords()
} else {
uni.navigateTo({
url: '/pages/login/index'
});
}
}
},
}
}
</script>
<style lang="scss">
.vue-ref {
padding: 0 !important;
}
.word {
&container {
position: relative;
}
}
.left {
display: flex;
margin: 10px;
}
.example-body {
display: flex;
padding: 10px 20px;
background-color: #fff;
width: 100%;
position: fixed;
z-index: 2;
}
.center {
position: absolute;
top: 45px;
width: 100%;
// height: 100%;
border-top: 1px solid #e5e5e5;
}
.stateBtnSelected {
background-color: #bbe5ff;
color: #1480cd !important;
border-radius: 20px;
font-size: 14px;
height: 25px;
line-height: 25px;
// width: 60px;
margin: 0 5px;
padding: 0 15px;
text-align: center;
}
.stateBtnNoselect {
background-color: transparent;
color: #8f939c !important;
border: none !important;
font-size: 14px;
height: 25px;
line-height: 25px;
// width: 60px;
margin: 0 5px;
padding: 0 15px;
text-align: center;
}
.slot-image {
width: 30px;
height: 30px;
}
.slot-box {
margin-right: 10px;
}
.uni-list-item__container {
align-items: center !important;
line-height: 20px;
}
</style>
到这里就结束啦,这篇文章看完如果您觉得有所收获,认为还行的话,就点个赞收藏一下