提交修改
Some checks are pending
Check / lint (push) Waiting to run
Check / typecheck (push) Waiting to run
Check / build (build, 18.x, ubuntu-latest) (push) Waiting to run
Check / build (build, 18.x, windows-latest) (push) Waiting to run
Check / build (build:app, 18.x, ubuntu-latest) (push) Waiting to run
Check / build (build:app, 18.x, windows-latest) (push) Waiting to run
Check / build (build:mp-weixin, 18.x, ubuntu-latest) (push) Waiting to run
Check / build (build:mp-weixin, 18.x, windows-latest) (push) Waiting to run

This commit is contained in:
wwt 2025-03-04 18:56:34 +08:00
commit b151f90fa6
15 changed files with 438 additions and 233 deletions

View File

@ -0,0 +1,73 @@
<!-- z-paging自定义的下拉刷新view -->
<template>
<view class="refresher-container">
<!-- 这里的图片请换成自己项目的图片 -->
<image
class="refresh-image rotating"
mode="aspectFit"
style="width:48rpx;height:48rpx;"
src="@/static/image/clockIn/loading@2x.png"
></image>
<text class="refresh-text">{{ refreshText }}</text>
</view>
</template>
<script setup>
import { computed } from 'vue';
const props = defineProps({
status: {
type: String,
default: ''
}
});
//
const refreshText = computed(() => {
const statusTextMap = {
'default': '哎呀,用点力继续下拉!',
'release-to-refresh': '拉疼我啦,松手刷新~~',
'loading': '正在努力刷新中...',
'complete': '刷新成功啦~'
};
return statusTextMap[props.status];
});
</script>
<style scoped>
.refresher-container {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
height: 150rpx;
background: rgba(249, 249, 253, 1);
flex-direction: column;
align-items: center;
justify-content: center;
}
.refresh-image {
width: 48rpx;
height: 48rpx;
margin-bottom: 10rpx;
margin-top: 10rpx;
}
.rotating {
animation: rotate 2s linear infinite;
}
@keyframes rotate {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
.refresh-text {
font-size: 28rpx;
color: rgba(0, 0, 0, 0.4);
}
</style>

View File

@ -1,20 +1,30 @@
<script setup> <script setup>
import {ref} from 'vue' import { ref } from "vue";
import ZPaging from '@/uni_modules/z-paging/components/z-paging/z-paging.vue' import ZPaging from "@/uni_modules/z-paging/components/z-paging/z-paging.vue";
const pagingRef=ref(null) const pagingRef = ref(null);
defineExpose({ defineExpose({
pagingRef pagingRef,
}) });
</script> </script>
<template> <template>
<z-paging ref="pagingRef" :show-scrollbar="false" :refresher-end-bounce-enabled="false" :refresher-complete-duration="500" :refresher-complete-delay="500" :refresher-fps="60" show-refresher-update-time use-virtual-list :fixed="false" v-bind="{ ...$attrs, ...$props}"> <z-paging
<template v-for="(slot, name) in $slots" :key="name" #[name]> ref="pagingRef"
<slot :name="name"></slot> :show-scrollbar="false"
</template> :refresher-end-bounce-enabled="false"
</z-paging> :refresher-complete-duration="500"
:refresher-complete-delay="500"
:refresher-fps="60"
show-refresher-update-time
use-virtual-list
:fixed="false"
v-bind="{ ...$attrs, ...$props }"
>
<template v-for="(slot, name) in $slots" :key="name" #[name]>
<slot :name="name"></slot>
</template>
</z-paging>
</template> </template>
<style scoped lang="scss"> <style scoped lang="scss">
</style> </style>

View File

@ -4,11 +4,12 @@
<div class="item-main-label"> <div class="item-main-label">
<span class="text-[32rpx] font-regular">{{ props?.item?.label }}</span> <span class="text-[32rpx] font-regular">{{ props?.item?.label }}</span>
</div> </div>
<div class="item-main-value" @click="toManagePage(props?.item)"> <div class="item-main-value" >
<span class="text-[32rpx] font-regular" v-if="props?.item?.value"> <span class="text-[32rpx] font-regular" v-if="props?.item?.value && props?.item?.value.length < 29">
{{ props?.item?.value }} {{ props?.item?.value }}
</span> </span>
<img <img
@click="toManagePage(props?.item)"
v-if=" v-if="
props?.item?.hasPointer && props?.item?.hasPointer &&
(props?.isManager || (props?.isManager ||
@ -30,7 +31,10 @@
></tm-switch> ></tm-switch>
</div> </div>
</div> </div>
<div class="item-sub" v-if="props?.item?.subValue"> <div class="item-sub" v-if="props?.item?.value && props?.item?.value.length > 28">
<span class="text-[32rpx] font-regular">{{ props?.item?.value }}</span>
</div>
<div class="item-sub cab1" v-if="props?.item?.subValue">
<span class="text-[32rpx] font-regular">{{ props?.item?.subValue }}</span> <span class="text-[32rpx] font-regular">{{ props?.item?.subValue }}</span>
</div> </div>
</div> </div>
@ -125,14 +129,17 @@ const changeSwitch = (e, item) => {
.item-sub { .item-sub {
margin: 28rpx 0 0; margin: 28rpx 0 0;
white-space: nowrap;
overflow: hidden;
max-width: 100%;
text-overflow: ellipsis;
span { span {
line-height: 44rpx; line-height: 44rpx;
color: #747474; color: #747474;
} }
} }
.cab1{
white-space: nowrap;
overflow: hidden;
max-width: 100%;
text-overflow: ellipsis;
}
} }
</style> </style>

View File

@ -1,237 +1,319 @@
<template> <template>
<div class="outer-layer"> <div class="outer-layer">
<div> <ZPaging
<tm-navbar class="index_top_navbar" :hideBack="false" hideHome title="" :leftWidth="420"> class="paging_container"
<template v-slot:left> ref="paging"
<div class="flex items-center ml-[48rpx]"> refresher-enabled
<image :refresher-threshold="80"
class="w-[72rpx] h-[72rpx]" :refresher-max-angle="0"
style="border-radius: 50%;" :refresher-pull-rate="0.5"
:src="userStore.avatar" :refresher-fixed-bac-height="80"
mode="scaleToFill" refresher-fixed-background="#F9F9FD"
refresher-background="#F9F9FD"
v-model="items"
@query="queryList"
:loading-more-enabled="false"
:refresher-end-bounce-enabled="false"
:auto="true"
:empty-view-show="isEmptyViewShow"
@refresherRefresh="onRefresh"
>
<template #top>
<div>
<tm-navbar
class="index_top_navbar"
:hideBack="false"
hideHome
title=""
:leftWidth="420"
>
<template v-slot:left>
<div class="flex items-center ml-[48rpx]">
<image
class="w-[72rpx] h-[72rpx]"
style="border-radius: 50%"
:src="userStore.avatar"
mode="scaleToFill"
/>
<div class="ml-[24rpx] text-[36rpx] font-bold">
{{ userStore.nickname }}
</div>
</div>
</template>
<template v-slot:right>
<div class="mr-[48rpx] popoverBox">
<tm-popover position="br" color="#333333" :width="260">
<image
class="w-[48rpx] h-[48rpx]"
style="border-radius: 50%"
:src="addCircle"
mode="scaleToFill"
/>
<template v-slot:label>
<div
class="w-full h-[208rpx] pt-[22rpx] pb-[32rpx] pl-[14rpx] pr-[12rpx]"
>
<div
@click="creatGroupChat"
class="flex items-center pl-[22rpx] mb-[32rpx]"
>
<div class="mr-[26rpx] flex items-center">
<tm-image
:width="40"
:height="39"
:src="cahtPopover"
></tm-image>
</div>
<div
class="leading-[54rpx] text-[32rpx] text-[#FFFFFF] font-bold"
>
发起群聊
</div>
</div>
<div class="divider"></div>
<div
@click="toAddressBookPage"
class="flex items-center pl-[22rpx] mt-[32rpx]"
>
<div class="mr-[26rpx] flex items-center">
<tm-image
:width="40"
:height="43"
:src="zu3289"
></tm-image>
</div>
<div
class="leading-[54rpx] text-[32rpx] text-[#FFFFFF] font-bold"
>
通讯录
</div>
</div>
</div>
</template>
</tm-popover>
</div>
</template>
</tm-navbar>
</div>
</template>
<template #refresher="{ refresherStatus }">
<custom-refresher :status="refresherStatus" />
</template>
<div class="content">
<div class="root">
<div class="searchRoot" @click="toSearchPage">
<tm-input
placeholder="请输入…"
color="#F9F9FD"
:round="1"
prefix="tmicon-search"
prefixColor="#46299D"
placeholderStyle="color:#BABABA"
class="input_search"
></tm-input>
</div>
<div class="contentRoot">
<chatItem
v-for="(item, index) in items"
:key="item.index_name"
:index="index"
:data="item"
/> />
<div class="ml-[24rpx] text-[36rpx] font-bold">
{{ userStore.nickname }}
</div>
</div> </div>
</template> </div>
<template v-slot:right> </div>
<div class="mr-[48rpx] popoverBox"> </ZPaging>
<tm-popover position="br" color="#333333" :width="260"> </div>
<image
class="w-[48rpx] h-[48rpx]"
style="border-radius: 50%;"
:src="addCircle"
mode="scaleToFill"
/>
<template v-slot:label>
<div
class="w-full h-[208rpx] pt-[22rpx] pb-[32rpx] pl-[14rpx] pr-[12rpx]"
>
<div
@click="creatGroupChat"
class="flex items-center pl-[22rpx] mb-[32rpx]"
>
<div class="mr-[26rpx] flex items-center">
<tm-image
:width="40"
:height="39"
:src="cahtPopover"
></tm-image>
</div>
<div
class="leading-[54rpx] text-[32rpx] text-[#FFFFFF] font-bold"
>
发起群聊
</div>
</div>
<div class="divider"></div>
<div
@click="toAddressBookPage"
class="flex items-center pl-[22rpx] mt-[32rpx]"
>
<div class="mr-[26rpx] flex items-center">
<tm-image
:width="40"
:height="43"
:src="zu3289"
></tm-image>
</div>
<div
class="leading-[54rpx] text-[32rpx] text-[#FFFFFF] font-bold"
>
通讯录
</div>
</div>
</div>
</template>
</tm-popover>
</div>
</template>
</tm-navbar>
</div>
<div class="root">
<div class="searchRoot" @click="toSearchPage">
<tm-input
placeholder="请输入…"
color="#F9F9FD"
:round="1"
prefix="tmicon-search"
prefixColor="#46299D"
placeholderStyle="color:#BABABA"
class="input_search"
></tm-input>
</div>
<div class="contentRoot">
<chatItem
v-for="(item, index) in items"
:key="item.index_name"
:index="index"
:data="item"
/>
</div>
</div>
</div>
</template> </template>
<script setup> <script setup>
import { ref, watch, computed } from 'vue' import { ref, watch, computed } from "vue";
import { onShow, onLoad } from '@dcloudio/uni-app' import { onShow, onLoad } from "@dcloudio/uni-app";
import { useChatList } from '@/store/chatList/index.js' import { useChatList } from "@/store/chatList/index.js";
import { useAuth } from '@/store/auth' import { useAuth } from "@/store/auth";
import { useTalkStore, useUserStore, useDialogueStore } from '@/store' import { useTalkStore, useUserStore, useDialogueStore } from "@/store";
import chatItem from './components/chatItem.vue' import chatItem from "./components/chatItem.vue";
import addCircle from '@/static/image/chatList/addCircle.png' import addCircle from "@/static/image/chatList/addCircle.png";
import cahtPopover from '@/static/image/chatList/cahtPopover.png' import cahtPopover from "@/static/image/chatList/cahtPopover.png";
import zu3289 from '@/static/image/chatList/zu3289@2x.png' import zu3289 from "@/static/image/chatList/zu3289@2x.png";
import ZPaging from "@/uni_modules/z-paging/components/z-paging/z-paging.vue";
const paging = ref();
const isEmptyViewShow = ref(false);
const talkStore = useTalkStore();
const userStore = useUserStore();
const dialogueStore = useDialogueStore();
const { userInfo } = useAuth();
const talkStore = useTalkStore() const topItems = computed(() => talkStore.topItems);
const userStore = useUserStore()
const dialogueStore = useDialogueStore()
const { userInfo } = useAuth()
const topItems = computed(() => talkStore.topItems)
const items = computed(() => { const items = computed(() => {
// if (searchKeyword.value.length === 0) { // if (searchKeyword.value.length === 0) {
return talkStore.talkItems console.log(talkStore.talkItems);
// }
// return talkStore.talkItems.filter((item) => { return talkStore.talkItems;
// let keyword = item.remark || item.name // }
// return keyword.toLowerCase().indexOf(searchKeyword.value.toLowerCase()) != -1 // return talkStore.talkItems.filter((item) => {
// }) // let keyword = item.remark || item.name
})
// return keyword.toLowerCase().indexOf(searchKeyword.value.toLowerCase()) != -1
// })
});
const queryList = (pageNo, pageSize) => {
// paging.value.complete(res.data.list);
console.log(talkStore);
talkStore.loadTalkList().then(() => {
isEmptyViewShow.value = talkStore.talkItems.length === 0;
//
paging.value.complete(talkStore.talkItems);
}).catch(error => {
//
console.error('加载失败', error);
paging.value.complete(false);
});
};
//
const onRefresh = () => {
console.log('触发下拉刷新');
talkStore.loadTalkList().then(() => {
//
paging.value.complete(talkStore.talkItems);
}).catch(error => {
//
console.error('加载失败', error);
paging.value.complete(false);
});
};
const creatGroupChat = () => { const creatGroupChat = () => {
uni.navigateTo({ uni.navigateTo({
url: '/pages/creatGroupChat/index', url: "/pages/creatGroupChat/index",
}) });
} };
const toSearchPage = () => { const toSearchPage = () => {
uni.navigateTo({ uni.navigateTo({
url: '/pages/search/index', url: "/pages/search/index",
}) });
} };
// //
const toAddressBookPage = () => { const toAddressBookPage = () => {
uni.navigateTo({ uni.navigateTo({
url: '/pages/chooseByDeps/index?chooseMode=3', url: "/pages/chooseByDeps/index?chooseMode=3",
}) });
} };
watch( /* watch(
() => talkStore, () => talkStore,
(newValue, oldValue) => { (newValue, oldValue) => {
// console.log(talkStore) // console.log(talkStore)
}, },
{ deep: true, immediate: true }, { deep: true, immediate: true }
) ); */
onShow(() => { onShow(() => {
talkStore.loadTalkList() //
}) talkStore.loadTalkList().then(() => {
// paging
if (paging.value) {
paging.value.reload();
}
}).catch(error => {
console.error('页面显示时数据加载失败', error);
});
});
onLoad((options) => { onLoad((options) => {
if (options?.openSessionIndexName) { console.log(options);
if (items?.value?.length > 0) {
items.value.forEach((openSession) => { if (options?.openSessionIndexName) {
if (openSession.index_name === options?.openSessionIndexName) { if (items?.value?.length > 0) {
dialogueStore.setDialogue(openSession) items.value.forEach((openSession) => {
if (openSession.unread_num > 0) { if (openSession.index_name === options?.openSessionIndexName) {
ServeClearTalkUnreadNum({ dialogueStore.setDialogue(openSession);
talk_type: openSession.talk_type, if (openSession.unread_num > 0) {
receiver_id: openSession.receiver_id, ServeClearTalkUnreadNum({
}).then(() => { talk_type: openSession.talk_type,
talkStore.updateItem({ receiver_id: openSession.receiver_id,
index_name: openSession.index_name, }).then(() => {
unread_num: 0, talkStore.updateItem({
}) index_name: openSession.index_name,
}) unread_num: 0,
} });
uni.navigateTo({ });
url: '/pages/dialog/index?sessionId=' + openSession.id, }
}) uni.navigateTo({
} url: "/pages/dialog/index?sessionId=" + openSession.id,
}) });
} }
} });
}) }
}
});
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
uni-page-body, uni-page-body,
page { page {
height: 100%; height: 100vh;
} background-image: url("@/static/image/clockIn/z3280@3x.png");
.outer-layer { background-size: cover;
overflow-y: auto;
flex: 1;
background-image: url('@/static/image/clockIn/z3280@3x.png');
background-size: cover;
padding: 0 32rpx 20rpx 32rpx;
display: flex;
flex-direction: column; flex-direction: column;
} }
.outer-layer {
::v-deep .index_top_navbar > .statusHeight:first-child{ height: 100%;
height: 70px !important;
} }
::v-deep .index_top_navbar .statusHeightTop{ .paging_container{
height: 70px !important; // border: 1px solid red;
} background: #fff;
::v-deep .index_top_navbar .statusHeightTop > .noNvueBorder:first-child{ margin: 0 32rpx 20rpx 32rpx;
height: 70px !important;
} }
::v-deep .index_top_navbar > .statusHeight:first-child {
height: 70px !important;
}
::v-deep .index_top_navbar .statusHeightTop {
height: 70px !important;
}
::v-deep .index_top_navbar .statusHeightTop > .noNvueBorder:first-child {
height: 70px !important;
}
.content{
// overflow: auto;
}
.root { .root {
flex: 1; flex: 1;
padding: 20rpx 0; padding: 20rpx 0;
} }
.searchRoot {
background-color: #fff;
padding: 22rpx 18rpx;
/* ::v-deep .input_search{
background: #F9F9FD !important; .searchRoot {
} */ background-color: #fff;
::v-deep .noNvueBorder > .noNvueBorder > .noNvueBorder{ padding: 22rpx 18rpx;
// border: 1px solid red !important; border-bottom: 16rpx rgba(249, 249, 253, 1) solid;
background: #F9F9FD !important; ::v-deep .noNvueBorder > .noNvueBorder > .noNvueBorder {
} background: #f9f9fd !important;
}
} }
.contentRoot { .contentRoot {
margin-top: 20rpx; margin-top: 20rpx;
background-color: #fff; background-color: #fff;
// min-height: calc(100vh - 180px);
} }
.divider { .divider {
height: 1rpx; height: 1rpx;
background-color: #7c7c7c; background-color: #7c7c7c;
opacity: 0.6; opacity: 0.6;
} }
.popoverBox { .popoverBox {
:deep(.popover-bcc) { :deep(.popover-bcc) {
transform: translateX(16rpx) translateY(48rpx); transform: translateX(16rpx) translateY(48rpx);
} }
} }
</style> </style>

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

@ -97,10 +97,10 @@ export const useTalkStore = defineStore('talk', {
// 加载会话列表 // 加载会话列表
loadTalkList() { loadTalkList() {
this.loadStatus = 2 this.loadStatus = 2
const resp = ServeGetTalkList() const resp = ServeGetTalkList()
resp.then(({ code, data }) => { // 返回 Promise 对象,使调用方可以使用 then/catch
return resp.then(({ code, data }) => {
if (code == 200) { if (code == 200) {
this.items = data.items.map((item) => { this.items = data.items.map((item) => {
const value = formatTalkItem(item) const value = formatTalkItem(item)
@ -118,13 +118,14 @@ export const useTalkStore = defineStore('talk', {
}) })
this.loadStatus = 3 this.loadStatus = 3
return this.items // 返回处理后的数据
} else { } else {
this.loadStatus = 4 this.loadStatus = 4
return Promise.reject(new Error('加载会话列表失败')) // 返回拒绝的 Promise
} }
}) }).catch((error) => {
resp.catch(() => {
this.loadStatus = 4 this.loadStatus = 4
return Promise.reject(error) // 继续向上传递错误
}) })
}, },

View File

@ -1,3 +1,9 @@
## 2.8.52025-02-09
1.`新增` 方法`scrollToX`支持控制x轴滚动到指定位置。
2.`修复` 快手小程序中报错`await isn't allowed in non-async function`的问题。
3.`修复` 在iOS+nvue中设置了`:loading-more-enabled="false"`后,调用`scrollToBottom`无法滚动到底部的问题。
4.`修复` 在支付宝小程序+页面滚动中,数据为空时空数据图未居中的问题。
5.`优化` fetch types修改。
## 2.8.42024-12-02 ## 2.8.42024-12-02
1.`修复` 在虚拟列表+vue2中顶部占位采用transformY方案在虚拟列表+vue3中顶部占位采用view占位方案。以解决在vue2+微信小程序+安卓+兼容模式中,可能出现的虚拟列表闪动的问题。 1.`修复` 在虚拟列表+vue2中顶部占位采用transformY方案在虚拟列表+vue3中顶部占位采用view占位方案。以解决在vue2+微信小程序+安卓+兼容模式中,可能出现的虚拟列表闪动的问题。
2.`修复` 在列表渲染时(尤其是在虚拟列表中)偶现的【点击加载更多】闪现的问题。 2.`修复` 在列表渲染时(尤其是在虚拟列表中)偶现的【点击加载更多】闪现的问题。

View File

@ -244,7 +244,7 @@ export default {
} }
} }
}, },
// 触发加载更多时调用,from:toBottom-滑动到底部触发;1、click-点击加载更多触发 // 触发加载更多时调用,from:toBottom-滑动到底部触发;click-点击加载更多触发
_onLoadingMore(from = 'click') { _onLoadingMore(from = 'click') {
// 如果是ios并且是滚动到底部的则在滚动到底部时候尝试将列表设置为禁止滚动然后设置为允许滚动以禁止底部bounce的效果 // 如果是ios并且是滚动到底部的则在滚动到底部时候尝试将列表设置为禁止滚动然后设置为允许滚动以禁止底部bounce的效果
if (this.isIos && from === 'toBottom' && !this.scrollToBottomBounceEnabled && this.scrollEnable) { if (this.isIos && from === 'toBottom' && !this.scrollToBottomBounceEnabled && this.scrollEnable) {

View File

@ -53,6 +53,8 @@ export default {
return { return {
scrollTop: 0, scrollTop: 0,
oldScrollTop: 0, oldScrollTop: 0,
scrollLeft: 0,
oldScrollLeft: 0,
scrollViewStyle: {}, scrollViewStyle: {},
scrollViewContainerStyle: {}, scrollViewContainerStyle: {},
scrollViewInStyle: {}, scrollViewInStyle: {},
@ -166,17 +168,24 @@ export default {
this._scrollIntoViewByNodeTop(nodeTop, offset, animate); this._scrollIntoViewByNodeTop(nodeTop, offset, animate);
}) })
}, },
// 滚动到指定位置(vue中有效)。y为与顶部的距离单位为pxoffset为偏移量单位为pxanimate为是否展示滚动动画默认为否 // y轴滚动到指定位置(vue中有效)。y为与顶部的距离单位为pxoffset为偏移量单位为pxanimate为是否展示滚动动画默认为否
scrollToY(y, offset, animate) { scrollToY(y, offset, animate) {
this.scrollTop = this.oldScrollTop; this.scrollTop = this.oldScrollTop;
this.$nextTick(() => { this.$nextTick(() => {
this._scrollToY(y, offset, animate); this._scrollToY(y, offset, animate);
}) })
}, },
// x轴滚动到指定位置(非页面滚动且在vue中有效)。x为与左侧的距离单位为pxoffset为偏移量单位为pxanimate为是否展示滚动动画默认为否
scrollToX(x, offset, animate) {
this.scrollLeft = this.oldScrollLeft;
this.$nextTick(() => {
this._scrollToX(x, offset, animate);
})
},
// 滚动到指定view(nvue中和虚拟列表中有效)。index为需要滚动的view的index(第几个从0开始)offset为偏移量单位为pxanimate为是否展示滚动动画默认为否 // 滚动到指定view(nvue中和虚拟列表中有效)。index为需要滚动的view的index(第几个从0开始)offset为偏移量单位为pxanimate为是否展示滚动动画默认为否
scrollIntoViewByIndex(index, offset, animate) { scrollIntoViewByIndex(index, offset, animate) {
if (index >= this.realTotalData.length) { if (index >= this.realTotalData.length) {
u.consoleErr('当前滚动的index超出已渲染列表长度请先通过refreshToPage加载到对应index页并等待渲染成功后再调用此方法') u.consoleErr('当前滚动的index超出已渲染列表长度请先通过refreshToPage加载到对应index页并等待渲染成功后再调用此方法');
return; return;
} }
this.$nextTick(() => { this.$nextTick(() => {
@ -381,7 +390,7 @@ export default {
this._scrollToY(nodeTop, offset, animate, true); this._scrollToY(nodeTop, offset, animate, true);
} }
}, },
// 滚动到指定位置 // y轴滚动到指定位置
_scrollToY(y, offset = 0, animate = false, addScrollTop = false) { _scrollToY(y, offset = 0, animate = false, addScrollTop = false) {
this._updatePrivateScrollWithAnimation(animate); this._updatePrivateScrollWithAnimation(animate);
u.delay(() => { u.delay(() => {
@ -402,14 +411,26 @@ export default {
} }
}, 10) }, 10)
}, },
// x轴滚动到指定位置
_scrollToX(x, offset = 0, animate = false) {
this._updatePrivateScrollWithAnimation(animate);
u.delay(() => {
if (!this.usePageScroll) {
this.scrollLeft = x - offset;
} else {
u.consoleErr('使用页面滚动时不支持scrollToX');
}
}, 10)
},
// scroll-view滚动中 // scroll-view滚动中
_scroll(e) { _scroll(e) {
this.$emit('scroll', e); this.$emit('scroll', e);
const scrollTop = e.detail.scrollTop; const { scrollTop, scrollLeft } = e.detail;
// #ifndef APP-NVUE // #ifndef APP-NVUE
this.finalUseVirtualList && this._updateVirtualScroll(scrollTop, this.oldScrollTop - scrollTop); this.finalUseVirtualList && this._updateVirtualScroll(scrollTop, this.oldScrollTop - scrollTop);
// #endif // #endif
this.oldScrollTop = scrollTop; this.oldScrollTop = scrollTop;
this.oldScrollLeft = scrollLeft;
// 滚动区域内容的总高度 - 当前滚动的scrollTop = 当前滚动区域的顶部与内容底部的距离 // 滚动区域内容的总高度 - 当前滚动的scrollTop = 当前滚动区域的顶部与内容底部的距离
const scrollDiff = e.detail.scrollHeight - this.oldScrollTop; const scrollDiff = e.detail.scrollHeight - this.oldScrollTop;
// 在非ios平台滚动中再次验证一下是否滚动到了底部。因为在一些安卓设备中有概率滚动到底部不触发@scrolltolower事件因此添加双重检测逻辑 // 在非ios平台滚动中再次验证一下是否滚动到了底部。因为在一些安卓设备中有概率滚动到底部不触发@scrolltolower事件因此添加双重检测逻辑

View File

@ -2,7 +2,7 @@
export default { export default {
// 当前版本号 // 当前版本号
version: '2.8.3', version: '2.8.5',
// 延迟操作的通用时间 // 延迟操作的通用时间
delayTime: 100, delayTime: 100,
// 请求失败时候全局emit使用的key // 请求失败时候全局emit使用的key

View File

@ -420,7 +420,12 @@ export default {
let scrollViewHeight = this.windowHeight - scrollViewTop; let scrollViewHeight = this.windowHeight - scrollViewTop;
scrollViewHeight -= finalScrollBottomNode ? finalScrollBottomNode[0].height : 0; scrollViewHeight -= finalScrollBottomNode ? finalScrollBottomNode[0].height : 0;
const additionHeight = u.convertToPx(this.autoHeightAddition); const additionHeight = u.convertToPx(this.autoHeightAddition);
const finalHeight = scrollViewHeight + additionHeight - (this.insideMore ? 1 : 0) + 'px !important'; // 在支付宝小程序中,添加!important会导致min-height失效因此在支付宝小程序中需要去掉
let importantSuffix = ' !important';
// #ifdef MP-ALIPAY
importantSuffix = '';
// #endif
const finalHeight = scrollViewHeight + additionHeight - (this.insideMore ? 1 : 0) + 'px' + importantSuffix;
this.$set(this.scrollViewStyle, heightKey, finalHeight); this.$set(this.scrollViewStyle, heightKey, finalHeight);
this.$set(this.scrollViewInStyle, heightKey, finalHeight); this.$set(this.scrollViewInStyle, heightKey, finalHeight);
} }
@ -432,7 +437,7 @@ export default {
}, },
// #ifdef MP-KUAISHOU // #ifdef MP-KUAISHOU
// 设置scroll-view内容器的最小高度等于scroll-view的高度(为了解决在快手小程序中内容较少时scroll-view内容器高度无法铺满scroll-view的问题) // 设置scroll-view内容器的最小高度等于scroll-view的高度(为了解决在快手小程序中内容较少时scroll-view内容器高度无法铺满scroll-view的问题)
_setFullScrollViewInHeight() { async _setFullScrollViewInHeight() {
try { try {
// 如果需要铺满全屏,则计算当前全屏可是区域的高度 // 如果需要铺满全屏,则计算当前全屏可是区域的高度
const scrollViewNode = await this._getNodeClientRect('.zp-scroll-view'); const scrollViewNode = await this._getNodeClientRect('.zp-scroll-view');

View File

@ -4,7 +4,7 @@
/ /_____| |_) | (_| | (_| | | | | | (_| | / /_____| |_) | (_| | (_| | | | | | (_| |
/___| | .__/ \__,_|\__, |_|_| |_|\__, | /___| | .__/ \__,_|\__, |_|_| |_|\__, |
|_| |___/ |___/ |_| |___/ |___/
v2.8.3 (2024-11-27) v2.8.5 (2025-02-09)
@author ZXLee <admin@zxlee.cn> @author ZXLee <admin@zxlee.cn>
--> -->
<!-- 文档地址https://z-paging.zxlee.cn --> <!-- 文档地址https://z-paging.zxlee.cn -->
@ -34,7 +34,7 @@ v2.8.3 (2024-11-27)
<view :class="{'zp-scroll-view-container':true,'zp-absoulte':finalIsOldWebView}" :style="[scrollViewContainerStyle]"> <view :class="{'zp-scroll-view-container':true,'zp-absoulte':finalIsOldWebView}" :style="[scrollViewContainerStyle]">
<scroll-view <scroll-view
ref="zp-scroll-view" :class="{'zp-scroll-view':true,'zp-scroll-view-absolute':!usePageScroll,'zp-scroll-view-hide-scrollbar':!showScrollbar}" :style="[chatRecordRotateStyle]" ref="zp-scroll-view" :class="{'zp-scroll-view':true,'zp-scroll-view-absolute':!usePageScroll,'zp-scroll-view-hide-scrollbar':!showScrollbar}" :style="[chatRecordRotateStyle]"
:scroll-top="scrollTop" :scroll-x="scrollX" :scroll-top="scrollTop" :scroll-left="scrollLeft" :scroll-x="scrollX"
:scroll-y="finalScrollable" :enable-back-to-top="finalEnableBackToTop" :scroll-y="finalScrollable" :enable-back-to-top="finalEnableBackToTop"
:show-scrollbar="showScrollbar" :scroll-with-animation="finalScrollWithAnimation" :show-scrollbar="showScrollbar" :scroll-with-animation="finalScrollWithAnimation"
:scroll-into-view="scrollIntoView" :lower-threshold="finalLowerThreshold" :upper-threshold="5" :scroll-into-view="scrollIntoView" :lower-threshold="finalLowerThreshold" :upper-threshold="5"
@ -284,7 +284,7 @@ v2.8.3 (2024-11-27)
@reload="_emptyViewReload" @viewClick="_emptyViewClick" /> @reload="_emptyViewReload" @viewClick="_emptyViewClick" />
</view> </view>
</component> </component>
<component is="header" v-if="!hideNvueBottomTag" ref="zp-n-list-bottom-tag" class="zp-n-list-bottom-tag"></component> <component :is="nViewIs" v-if="!hideNvueBottomTag" ref="zp-n-list-bottom-tag" class="zp-n-list-bottom-tag"></component>
</component> </component>
<view v-if="zSlots.right" class="zp-page-right"> <view v-if="zSlots.right" class="zp-page-right">
<slot name="right" /> <slot name="right" />

View File

@ -2,7 +2,7 @@
"id": "z-paging", "id": "z-paging",
"name": "z-paging", "name": "z-paging",
"displayName": "【z-paging下拉刷新、上拉加载】高性能全平台兼容。支持虚拟列表分页全自动处理", "displayName": "【z-paging下拉刷新、上拉加载】高性能全平台兼容。支持虚拟列表分页全自动处理",
"version": "2.8.4", "version": "2.8.5",
"description": "超简单、低耦合使用wxs+renderjs实现。支持自定义下拉刷新、上拉加载更多、虚拟列表、下拉进入二楼、自动管理空数据图、无闪动聊天分页、本地分页、国际化等数百项配置", "description": "超简单、低耦合使用wxs+renderjs实现。支持自定义下拉刷新、上拉加载更多、虚拟列表、下拉进入二楼、自动管理空数据图、无闪动聊天分页、本地分页、国际化等数百项配置",
"keywords": [ "keywords": [
"下拉刷新", "下拉刷新",

View File

@ -4,7 +4,7 @@
<img alt="logo" src="https://z-paging.zxlee.cn/img/title-logo.png" height="100" style="margin-bottom: 50px;" /> <img alt="logo" src="https://z-paging.zxlee.cn/img/title-logo.png" height="100" style="margin-bottom: 50px;" />
</p> </p>
[![version](https://img.shields.io/badge/version-2.8.3-blue)](https://github.com/SmileZXLee/uni-z-paging) [![license](https://img.shields.io/github/license/SmileZXLee/uni-z-paging)](https://en.wikipedia.org/wiki/MIT_License) [![version](https://img.shields.io/badge/version-2.8.5-blue)](https://github.com/SmileZXLee/uni-z-paging) [![license](https://img.shields.io/github/license/SmileZXLee/uni-z-paging)](https://en.wikipedia.org/wiki/MIT_License)
<img height="0" width="0" src="https://api.z-notify.zxlee.cn/v1/public/statistics/8293556910106066944/addOnly?from=uni" /> <img height="0" width="0" src="https://api.z-notify.zxlee.cn/v1/public/statistics/8293556910106066944/addOnly?from=uni" />
`z-paging-x`现已支持uniapp x持续完善中插件地址👉🏻 [https://ext.dcloud.net.cn/plugin?name=z-paging-x](https://ext.dcloud.net.cn/plugin?name=z-paging-x) `z-paging-x`现已支持uniapp x持续完善中插件地址👉🏻 [https://ext.dcloud.net.cn/plugin?name=z-paging-x](https://ext.dcloud.net.cn/plugin?name=z-paging-x)

View File

@ -364,7 +364,7 @@ declare interface ZPagingProps {
* Function@query类似fetch则@query将不再触发 * Function@query类似fetch则@query将不再触发
* @since 2.7.8 * @since 2.7.8
*/ */
fetch?: () => void fetch?: (...args: any[]) => any;
/** /**
* fetch的附加参数fetch配置后有效 * fetch的附加参数fetch配置后有效