uniapp下拉框(【uniapp】页面下拉刷新)
目录
一 、全局
二 、局部
1 、一个页面一个下拉刷新
2 、一个页面多个下拉刷新(切换时滚动条回到顶部)
3 、一个页面多个下拉刷新(切换时恢复滚动条位置)
一 、全局
修改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>创心域SEO版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!