Files
2025-01-21 01:46:34 +08:00

234 lines
6.8 KiB
Vue
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!-- 虚拟列表演示(不使用内置列表)(vue) -->
<!-- 写法较简单在页面中对当前需要渲染的虚拟列表数据进行for循环在vue3中兼容性良好 -->
<!-- 在各平台兼容性请查阅https://z-paging.zxlee.cn/module/virtual-list.html -->
<template>
<view class="content">
<!-- 如果页面中的cell高度是固定不变的则不需要设置cell-height-mode如果页面中高度是动态改变的则设置cell-height-mode="dynamic" -->
<!-- 原先的v-model修改为@virtualListChange="virtualListChange"并赋值处理后的虚拟列表 -->
<z-paging ref="paging" use-virtual-list :force-close-inner-list="true" :paging-style="{ paddingTop: paddingTop + 'px', paddingBottom: paddingBottom + 'rpx' }" cell-height-mode="dynamic" @virtualListChange="virtualListChange" @query="queryList">
<!-- 需要固定在顶部不滚动的view放在slot="top"的view中如果需要跟着滚动则不要设置slot="top" -->
<template #top>
<nav-bar :title="title" @initNav="initNav">
<template v-if="$slots.navLeft" #left>
<slot name="navLeft"></slot>
</template>
<template v-if="$slots.navContent" #content>
<slot name="navContent"></slot>
</template>
</nav-bar>
</template>
<view>
<slot name="top"></slot>
</view>
<!-- :id="`zp-id-${item.zp_index}`":key="item.zp_index" 必须写必须写 -->
<!-- 这里for循环的index不是数组中真实的index了请使用item.zp_index获取真实的index -->
<view class="item" :id="`zp-id-${item.zp_index}`" :key="item.zp_index" v-for="(item,index) in virtualList">
<view-item :index="index" :item="item" @onLongPress="onLongPress"></view-item>
</view>
</z-paging>
<view class="shade" v-show="showShade" @tap="hidePop">
<view class="pop" :style="popStyle" :class="{'show':showPop}">
<view v-for="(item,index) in popButton" :key="index" @tap="pickerMenu" :data-index="index">{{item}}</view>
</view>
</view>
</view>
</template>
<script>
import NavBar from '@/pages/tabbar/components/member/navBar.vue';
import ViewItem from '@/pages/tabbar/components/member/viewItem.vue';
import UserApi from '@/sheep/api/member/user';
export default {
components: {
NavBar,
ViewItem,
},
props: {
title: {
type: String,
default: '',
}
},
data() {
return {
// 虚拟列表数组,通过@virtualListChange监听获得最新数组
virtualList: [],
winSize: {},
/* 显示遮罩 */
showShade: false,
/* 显示操作弹窗 */
showPop: false,
/* 弹窗按钮列表 */
popButton: ["标为关注", "置顶聊天", "删除该聊天"],
/* 弹窗定位样式 */
popStyle: "",
/* 选择的用户下标 */
pickerUserIndex: -1,
paddingTop: 0,
paddingBottom: 100,
navSwiper: false,
navSwiperH: 80,
navNotice: false,
navNoticeH: 90,
height: 0,
}
},
methods: {
initNav(e) {
this.height = e.height;
this.paddingTop = this.height;
if(this.navSwiper){
this.paddingTop = this.paddingTop + this.navSwiperH;
}
if(this.navNotice){
this.paddingTop = this.paddingTop + this.navNoticeH;
}
},
// 监听虚拟列表数组改变并赋值给virtualList进行重新渲染
virtualListChange(vList) {
this.virtualList = vList;
},
queryList(pageNo, pageSize) {
// 组件加载时会自动触发此方法,因此默认页面加载时会自动触发,无需手动调用
// 这里的pageNo和pageSize会自动计算好直接传给服务器即可
// 模拟请求服务器获取分页数据,请替换成自己的网络请求
const params = {
pageNo: pageNo,
pageSize: pageSize,
random: this.tabIndex === 1
}
UserApi.getUserPage(params).then(res => {
// 将请求的结果数组传递给z-paging
this.$refs.paging.complete(res.data.list);
}).catch(res => {
// 如果请求失败写this.$refs.paging.complete(false);
// 注意每次都需要在catch中写这句话很麻烦z-paging提供了方案可以全局统一处理
// 在底层的网络请求抛出异常时写uni.$emit('z-paging-error-emit');即可
this.$refs.paging.complete(false);
})
},
/* 获取窗口尺寸 */
getWindowSize() {
uni.getSystemInfo({
success: (res) => {
this.winSize = {
"witdh": res.windowWidth,
"height": res.windowHeight
}
}
})
},
/* 长按监听 */
onLongPress(e) {
let [touches, style, index] = [e.touches[0], "", e.currentTarget.dataset.index];
/* 因 非H5端不兼容 style 属性绑定 Object ,所以拼接字符 */
if (touches.clientY > (this.winSize.height / 2)) {
style = `bottom:${this.winSize.height-touches.clientY}px;`;
} else {
style = `top:${touches.clientY}px;`;
}
if (touches.clientX > (this.winSize.witdh / 2)) {
style += `right:${this.winSize.witdh-touches.clientX}px`;
} else {
style += `left:${touches.clientX}px`;
}
this.popStyle = style;
this.pickerUserIndex = Number(index);
this.showShade = true;
this.$nextTick(() => {
setTimeout(() => {
this.showPop = true;
}, 10);
});
},
/* 隐藏弹窗 */
hidePop() {
this.showPop = false;
this.pickerUserIndex = -1;
setTimeout(() => {
this.showShade = false;
}, 250);
},
/* 选择菜单 */
pickerMenu(e) {
let index = Number(e.currentTarget.dataset.index);
console.log(`${this.pickerUserIndex+1}个用户,第${index+1}个按钮`);
// 在这里开启你的代码秀
uni.showToast({
title: `${this.pickerUserIndex+1}个用户,第${index+1}个按钮`,
icon: "none",
mask: true,
duration: 600
});
/*
因为隐藏弹窗方法中会将当前选择的用户下标还原为-1,
如果行的菜单方法存在异步情况,请在隐藏之前将该值保存,或通过参数传入异步函数中
*/
this.hidePop();
},
}
}
</script>
<style lang="scss" scoped>
.item {
background-color: #fff;
}
/* 遮罩 */
.shade {
position: fixed;
z-index: 100;
top: 0;
right: 0;
bottom: 0;
left: 0;
-webkit-touch-callout: none;
.pop {
position: fixed;
z-index: 101;
width: 260rpx;
box-sizing: border-box;
font-size: 28upx;
text-align: left;
color: #333;
background-color: #fff;
box-shadow: 0 0 5px rgba(0, 0, 0, 0.5);
line-height: 80upx;
transition: transform 0.15s ease-in-out 0s;
user-select: none;
-webkit-touch-callout: none;
transform: scale(0, 0);
&.show {
transform: scale(1, 1);
}
&>view {
padding: 0 20upx;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
user-select: none;
-webkit-touch-callout: none;
&:active {
background-color: #f3f3f3;
}
}
}
}
</style>