Merge branch 'main' of http://192.168.195.14:3000/shang/guyu
# Conflicts: # components.d.ts
This commit is contained in:
commit
e56d98c23b
11
.cursor/rules/important.mdc
Normal file
11
.cursor/rules/important.mdc
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
---
|
||||
alwaysApply: true
|
||||
---
|
||||
1、回复用中文
|
||||
2、不要修改用户需求之外的代码
|
||||
3、对于长代码,进行分批次修改,每次提交行数不要超过580行
|
||||
4、对于大型代码文件,使用search_replace工具比edit_file更可靠
|
||||
5、每次修改只处理一小部分代码(少于508行)
|
||||
6、精确定位需要修改的代码块
|
||||
7、将复杂修改拆分为多个简单的、独立的修改步骤
|
||||
8、对于新文件创建,可以先创建基本结构,再逐步添加功能
|
||||
27
components.d.ts
vendored
27
components.d.ts
vendored
|
|
@ -1,27 +0,0 @@
|
|||
/* eslint-disable */
|
||||
// @ts-nocheck
|
||||
// Generated by unplugin-vue-components
|
||||
// Read more: https://github.com/vuejs/core/pull/3399
|
||||
// biome-ignore lint: disable
|
||||
export {}
|
||||
|
||||
/* prettier-ignore */
|
||||
declare module 'vue' {
|
||||
export interface GlobalComponents {
|
||||
HomeGoodsItem: typeof import('./components/guyu-home-container/home-goods-item.vue')['default']
|
||||
HomeNotice: typeof import('./components/guyu-home-container/home-notice.vue')['default']
|
||||
HomeRecommend: typeof import('./components/guyu-home-container/home-recommend.vue')['default']
|
||||
HomeSearch: typeof import('./components/guyu-home-container/home-search.vue')['default']
|
||||
HomeSwiper: typeof import('./components/guyu-home-container/home-swiper.vue')['default']
|
||||
RouterLink: typeof import('vue-router')['RouterLink']
|
||||
RouterView: typeof import('vue-router')['RouterView']
|
||||
ZPaging: typeof import('./components/z-paging/z-paging.vue')['default']
|
||||
ZPagingCell: typeof import('./components/z-paging-cell/z-paging-cell.vue')['default']
|
||||
ZPagingEmptyView: typeof import('./components/z-paging-empty-view/z-paging-empty-view.vue')['default']
|
||||
ZPagingLoadMore: typeof import('./components/z-paging/components/z-paging-load-more.vue')['default']
|
||||
ZPagingRefresh: typeof import('./components/z-paging/components/z-paging-refresh.vue')['default']
|
||||
ZPagingSwiper: typeof import('./components/z-paging-swiper/z-paging-swiper.vue')['default']
|
||||
ZPagingSwiperItem: typeof import('./components/z-paging-swiper-item/z-paging-swiper-item.vue')['default']
|
||||
ZTabs: typeof import('./components/z-tabs/z-tabs.vue')['default']
|
||||
}
|
||||
}
|
||||
0
components/guyu/home/container.vue
Normal file
0
components/guyu/home/container.vue
Normal file
168
components/guyu/home/goods-list.vue
Normal file
168
components/guyu/home/goods-list.vue
Normal file
|
|
@ -0,0 +1,168 @@
|
|||
<!-- 在这个文件对每个tab对应的列表进行渲染 -->
|
||||
<template>
|
||||
<view class="content">
|
||||
<!-- 这里设置了z-paging加载时禁止自动调用reload方法,自行控制何时reload(懒加载)-->
|
||||
<z-paging ref="paging" v-model="dataList" @query="queryList" use-page-scroll :scrollable="false"
|
||||
:hide-empty-view="hideEmptyView" :refresher-enabled="false" @contentHeightChanged="contentHeightChanged"
|
||||
:auto="false" :auto-clean-list-when-reload="false">
|
||||
<!-- 如果希望其他view跟着页面滚动,可以放在z-paging标签内 -->
|
||||
<view class="grid-container">
|
||||
<view v-for="(item, index) in dataList" :key="index">
|
||||
<guyu-home-goods-item :goods-item="item" />
|
||||
<!-- <view class="item-title">{{ item.title }}</view>
|
||||
<view class="item-detail">{{ item.detail }}</view>
|
||||
<view class="item-line"></view> -->
|
||||
</view>
|
||||
</view>
|
||||
|
||||
</z-paging>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, watch, nextTick, defineProps, defineExpose } from 'vue';
|
||||
|
||||
// 定义props
|
||||
const props = defineProps({
|
||||
// 当前组件的index,也就是当前组件是swiper中的第几个
|
||||
tabIndex: {
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
// 当前swiper切换到第几个index
|
||||
currentIndex: {
|
||||
type: Number,
|
||||
default: 0
|
||||
}
|
||||
});
|
||||
|
||||
// 定义emit
|
||||
const emit = defineEmits(['heightChanged']);
|
||||
|
||||
// 响应式数据
|
||||
// v-model绑定的这个变量不要在分页请求结束中自己赋值!!!
|
||||
const dataList = ref([]);
|
||||
const height = ref(0);
|
||||
const hideEmptyView = ref(true);
|
||||
const completeFunc = ref(null);
|
||||
const paging = ref(null);
|
||||
|
||||
// 监听currentIndex变化
|
||||
watch(
|
||||
() => props.currentIndex,
|
||||
(newVal) => {
|
||||
if (newVal === props.tabIndex) {
|
||||
// 懒加载,当滑动到当前的item时,才去加载
|
||||
nextTick(() => {
|
||||
setTimeout(() => {
|
||||
paging.value.reload();
|
||||
}, 100);
|
||||
});
|
||||
}
|
||||
},
|
||||
{ immediate: true }
|
||||
);
|
||||
|
||||
// 组件方法
|
||||
// 组件加载时会自动触发此方法,因此默认页面加载时会自动触发,无需手动调用
|
||||
const queryList = (pageNo, pageSize) => {
|
||||
// 这里的pageNo和pageSize会自动计算好,直接传给服务器即可
|
||||
// 模拟请求服务器获取分页数据,请替换成自己的网络请求
|
||||
const params = {
|
||||
pageNo: pageNo,
|
||||
pageSize: pageSize,
|
||||
type: props.tabIndex + 1
|
||||
}
|
||||
let c = [];
|
||||
for (let i = 0; i < 10; i++) {
|
||||
c.push({
|
||||
title: '测试' + i,
|
||||
detail: '详情' + i
|
||||
})
|
||||
}
|
||||
paging.value.complete(c);
|
||||
hideEmptyView.value = false;
|
||||
//请求结束,调用父组件的下拉刷新结束回调函数,使得父组件中的z-paging下拉刷新结束
|
||||
if (completeFunc.value) {
|
||||
completeFunc.value();
|
||||
}
|
||||
};
|
||||
|
||||
// 页面通知当前子组件刷新列表
|
||||
const reload = (completeFn) => {
|
||||
// 先把父组件下拉刷新的回调函数存起来
|
||||
completeFunc.value = completeFn;
|
||||
// 调用z-paging的reload方法
|
||||
paging.value.reload();
|
||||
};
|
||||
|
||||
// 当列表高度改变时,通知页面的swiper同步更改高度
|
||||
const contentHeightChanged = (height) => {
|
||||
const finalHeight = dataList.value.length ? height : 0;
|
||||
// 限制内容最小高度为屏幕可见高度减z-tabs高度。注意,页面中有使用slot="top"插入的view,则此处的minHeight还应该减去slot="top"插入的view的高度
|
||||
const minHeight = uni.getSystemInfoSync().windowHeight - uni.upx2px(80);
|
||||
emit('heightChanged', Math.max(finalHeight, minHeight));
|
||||
};
|
||||
|
||||
// 页面通知当前子组件加载更多数据
|
||||
const doLoadMore = () => {
|
||||
paging.value.doLoadMore();
|
||||
};
|
||||
|
||||
// 页面通知当前子组件清除数据
|
||||
const clear = () => {
|
||||
paging.value.clear();
|
||||
hideEmptyView.value = true;
|
||||
};
|
||||
|
||||
// 将方法暴露给父组件
|
||||
defineExpose({
|
||||
reload,
|
||||
doLoadMore,
|
||||
clear
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
/* 注意,1、父节点需要固定高度,z-paging的height:100%才会生效 */
|
||||
/* 注意,2、请确保z-paging与同级的其他view的总高度不得超过屏幕宽度,以避免超出屏幕高度时页面的滚动与z-paging内部的滚动冲突 */
|
||||
.content {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.item {
|
||||
position: relative;
|
||||
height: 150rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 0rpx 30rpx;
|
||||
}
|
||||
|
||||
.item-detail {
|
||||
padding: 5rpx 15rpx;
|
||||
border-radius: 10rpx;
|
||||
font-size: 28rpx;
|
||||
color: white;
|
||||
background-color: #007AFF;
|
||||
}
|
||||
|
||||
.item-line {
|
||||
position: absolute;
|
||||
bottom: 0rpx;
|
||||
left: 0rpx;
|
||||
height: 1px;
|
||||
width: 100%;
|
||||
background-color: #eeeeee;
|
||||
}
|
||||
|
||||
.grid-container {
|
||||
width: 100%;
|
||||
display: grid;
|
||||
/* 3列等宽 */
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
/* 间距 */
|
||||
gap: 20rpx;
|
||||
padding: 20rpx 0rpx;
|
||||
}
|
||||
</style>
|
||||
192
components/guyu/home/tabs.vue
Normal file
192
components/guyu/home/tabs.vue
Normal file
|
|
@ -0,0 +1,192 @@
|
|||
<template>
|
||||
<view class="tabs-container">
|
||||
<view class="tabs-wrapper">
|
||||
<template v-for="(item, index) in slideLableList" :key="index">
|
||||
<view class="tab-item-wrapper" @click="clickTab(index)" :style="{ width: item.width }">
|
||||
<SlideLabel ref="slideLabels" :defaultColor="item.active ? '#F5D677' : '#fff'">
|
||||
<text class="tab-text myZt-500w">{{ item.name }}</text>
|
||||
</SlideLabel>
|
||||
</view>
|
||||
</template>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
import { onMounted, ref, watch, nextTick } from 'vue';
|
||||
import SlideLabel from '@/components/guyu/page/slide-label.vue';
|
||||
|
||||
const props = defineProps({
|
||||
list: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
current: {
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
});
|
||||
|
||||
// 滑动方向:1表示向右滑,-1表示向左滑,0表示初始状态
|
||||
let slideDirection = ref(0);
|
||||
// 标签列表
|
||||
let slideLableList = ref([]);
|
||||
// 滑块组件引用
|
||||
let slideLabels = ref([]);
|
||||
|
||||
// 初始化和更新slideLableList的函数
|
||||
const initSlideLableList = () => {
|
||||
slideLableList.value = props.list.map((item, index) => {
|
||||
return {
|
||||
name: item.name,
|
||||
width: getLableWidth(item.name),
|
||||
active: index === props.current,
|
||||
data: item
|
||||
}
|
||||
});
|
||||
|
||||
// 确保DOM更新后再操作SlideLabel实例
|
||||
nextTick(() => {
|
||||
updateLabelsState();
|
||||
});
|
||||
}
|
||||
|
||||
// 监听props.list的变化
|
||||
watch(() => props.list, () => {
|
||||
initSlideLableList();
|
||||
}, { deep: true });
|
||||
|
||||
// 监听current变化,处理标签切换
|
||||
watch(() => props.current, (newCurrent, oldCurrent) => {
|
||||
if (newCurrent !== oldCurrent && slideLableList.value.length > 0) {
|
||||
// 更新激活状态
|
||||
slideLableList.value.forEach((item, index) => {
|
||||
item.active = index === newCurrent;
|
||||
});
|
||||
|
||||
// nextTick(() => {
|
||||
// updateLabelsState();
|
||||
// });
|
||||
}
|
||||
});
|
||||
|
||||
// 更新所有标签状态
|
||||
const updateLabelsState = () => {
|
||||
if (!slideLabels.value || slideLabels.value.length === 0) return;
|
||||
|
||||
// 重置所有标签状态
|
||||
slideLabels.value.forEach((label, index) => {
|
||||
if (label && label.reset) {
|
||||
label.reset();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
initSlideLableList();
|
||||
})
|
||||
|
||||
const getLableWidth = (name) => {
|
||||
let t = name.length * 20 + 40;
|
||||
if (t < 80) {
|
||||
t = 80;
|
||||
}
|
||||
return t + "rpx";
|
||||
}
|
||||
|
||||
const systemWidth = parseInt(uni.getWindowInfo().screenWidth * 0.96);
|
||||
const emit = defineEmits(['change']);
|
||||
let isClick = false;
|
||||
// 点击标签
|
||||
const clickTab = (index) => {
|
||||
console.log('点击标签');
|
||||
if (index == props.current) {
|
||||
return;
|
||||
}
|
||||
isClick = true;
|
||||
emit("change", index);
|
||||
}
|
||||
|
||||
// 滑动效果处理函数
|
||||
const setDx = (dx) => {
|
||||
if (!slideLabels.value || slideLabels.value.length === 0 || isClick) return;
|
||||
// console.log('滑动处理了');
|
||||
|
||||
// 计算滑动百分比(0-100)
|
||||
const absDx = Math.abs(dx);
|
||||
const percent = Math.min(100, Math.round((absDx / systemWidth) * 100));
|
||||
|
||||
// 确定滑动方向
|
||||
const direction = dx > 0 ? 1 : (dx < 0 ? -1 : 0);
|
||||
slideDirection.value = direction;
|
||||
|
||||
const currentIndex = props.current;
|
||||
|
||||
if (direction > 0 && currentIndex + 1 < slideLableList.value.length) {
|
||||
// 向右滑动 - 当前标签颜色消失,下一标签颜色出现
|
||||
const nextIndex = currentIndex + 1;
|
||||
|
||||
// 当前标签从右侧被透明覆盖
|
||||
slideLabels.value[currentIndex]?.coverFromLeft('#fff', percent);
|
||||
|
||||
// 下一个标签从左侧被颜色覆盖
|
||||
slideLabels.value[nextIndex]?.coverFromLeft('#F5D677', percent);
|
||||
|
||||
} else if (direction < 0 && currentIndex > 0) {
|
||||
// 向左滑动 - 当前标签颜色消失,前一标签颜色出现
|
||||
const prevIndex = currentIndex - 1;
|
||||
|
||||
// 当前标签从左侧被透明覆盖
|
||||
slideLabels.value[currentIndex]?.coverFromRight('#fff', percent);
|
||||
|
||||
// 前一个标签从右侧被颜色覆盖
|
||||
slideLabels.value[prevIndex]?.coverFromRight('#F5D677', percent);
|
||||
}
|
||||
}
|
||||
|
||||
// 滑动结束,重置状态
|
||||
const unlockDx = () => {
|
||||
slideDirection.value = 0;
|
||||
if (isClick) {
|
||||
isClick = false;
|
||||
}
|
||||
// 更新所有标签状态
|
||||
nextTick(() => {
|
||||
updateLabelsState();
|
||||
|
||||
// 确保当前选中的标签显示正确的颜色
|
||||
slideLableList.value.forEach((item, index) => {
|
||||
item.active = index === props.current;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// 暴露方法给父组件
|
||||
defineExpose({
|
||||
setDx,
|
||||
unlockDx
|
||||
});
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.tabs-container {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.tabs-wrapper {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
margin-top: 32.64rpx;
|
||||
}
|
||||
|
||||
.tab-item-wrapper {
|
||||
min-width: 80rpx;
|
||||
margin-right: 26.39rpx;
|
||||
text-align: center;
|
||||
line-height: 40rpx;
|
||||
height: 50rpx;
|
||||
}
|
||||
|
||||
.tab-text {
|
||||
font-size: 22rpx;
|
||||
}
|
||||
</style>
|
||||
208
components/guyu/page/slide-label.vue
Normal file
208
components/guyu/page/slide-label.vue
Normal file
|
|
@ -0,0 +1,208 @@
|
|||
<template>
|
||||
<view class="slide-label" :style="containerStyle">
|
||||
<!-- 默认颜色背景 -->
|
||||
<view class="color-bg default-color" :style="{ background: defaultColor }"></view>
|
||||
|
||||
<!-- 右侧覆盖颜色 -->
|
||||
<view class="color-bg right-cover" :style="rightCoverStyle" v-if="showRightCover"></view>
|
||||
|
||||
<!-- 左侧覆盖颜色 -->
|
||||
<view class="color-bg left-cover" :style="leftCoverStyle" v-if="showLeftCover"></view>
|
||||
|
||||
<!-- 内容层 -->
|
||||
<view class="content-layer">
|
||||
<slot>{{ content }}</slot>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed } from 'vue';
|
||||
|
||||
// 定义组件属性
|
||||
const props = defineProps({
|
||||
// 默认颜色
|
||||
defaultColor: {
|
||||
type: String,
|
||||
default: '#FFFFFF'
|
||||
},
|
||||
// 显示文本
|
||||
content: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
// 高度
|
||||
height: {
|
||||
type: [Number, String],
|
||||
default: '45rpx'
|
||||
},
|
||||
// 圆角
|
||||
borderRadius: {
|
||||
type: [Number, String],
|
||||
default: '25rpx'
|
||||
},
|
||||
// 文字颜色
|
||||
textColor: {
|
||||
type: String,
|
||||
default: '#000000'
|
||||
}
|
||||
});
|
||||
|
||||
// 发出事件
|
||||
const emit = defineEmits(['coverChange']);
|
||||
|
||||
// 右侧覆盖颜色状态
|
||||
const rightCoverColor = ref('');
|
||||
const rightCoverPercent = ref(0);
|
||||
const showRightCover = ref(false);
|
||||
|
||||
// 左侧覆盖颜色状态
|
||||
const leftCoverColor = ref('');
|
||||
const leftCoverPercent = ref(0);
|
||||
const showLeftCover = ref(false);
|
||||
|
||||
// 容器样式
|
||||
const containerStyle = computed(() => {
|
||||
return {
|
||||
height: typeof props.height === 'number' ? `${props.height}rpx` : props.height,
|
||||
borderRadius: typeof props.borderRadius === 'number' ? `${props.borderRadius}rpx` : props.borderRadius,
|
||||
color: props.textColor
|
||||
};
|
||||
});
|
||||
|
||||
// 右侧覆盖层样式
|
||||
const rightCoverStyle = computed(() => {
|
||||
return {
|
||||
background: rightCoverColor.value,
|
||||
width: `${rightCoverPercent.value}%`,
|
||||
right: 0
|
||||
};
|
||||
});
|
||||
|
||||
// 左侧覆盖层样式
|
||||
const leftCoverStyle = computed(() => {
|
||||
return {
|
||||
background: leftCoverColor.value,
|
||||
width: `${leftCoverPercent.value}%`,
|
||||
left: 0
|
||||
};
|
||||
});
|
||||
|
||||
/**
|
||||
* 从右侧覆盖颜色
|
||||
* @param {String} color 新颜色
|
||||
* @param {Number} percent 覆盖百分比(0-100)
|
||||
*/
|
||||
function coverFromRight(color, percent = 0) {
|
||||
// 确保百分比在有效范围内
|
||||
const safePercent = Math.max(0, Math.min(100, percent));
|
||||
|
||||
// 设置覆盖颜色
|
||||
rightCoverColor.value = color;
|
||||
rightCoverPercent.value = safePercent;
|
||||
|
||||
// 显示覆盖层
|
||||
showRightCover.value = safePercent > 0;
|
||||
|
||||
// 如果覆盖层宽度为0,隐藏它
|
||||
if (safePercent === 0) {
|
||||
showRightCover.value = false;
|
||||
}
|
||||
|
||||
// 触发覆盖变化事件
|
||||
emit('coverChange', {
|
||||
direction: 'right',
|
||||
color: color,
|
||||
percent: safePercent
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 从左侧覆盖颜色
|
||||
* @param {String} color 新颜色
|
||||
* @param {Number} percent 覆盖百分比(0-100)
|
||||
*/
|
||||
function coverFromLeft(color, percent = 0) {
|
||||
// 确保百分比在有效范围内
|
||||
const safePercent = Math.max(0, Math.min(100, percent));
|
||||
|
||||
// 设置覆盖颜色
|
||||
leftCoverColor.value = color;
|
||||
leftCoverPercent.value = safePercent;
|
||||
|
||||
// 显示覆盖层
|
||||
showLeftCover.value = safePercent > 0;
|
||||
|
||||
// 如果覆盖层宽度为0,隐藏它
|
||||
if (safePercent === 0) {
|
||||
showLeftCover.value = false;
|
||||
}
|
||||
|
||||
// 触发覆盖变化事件
|
||||
emit('coverChange', {
|
||||
direction: 'left',
|
||||
color: color,
|
||||
percent: safePercent
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 重置所有覆盖层
|
||||
*/
|
||||
function reset() {
|
||||
rightCoverPercent.value = 0;
|
||||
leftCoverPercent.value = 0;
|
||||
showRightCover.value = false;
|
||||
showLeftCover.value = false;
|
||||
}
|
||||
|
||||
// 暴露方法
|
||||
defineExpose({
|
||||
coverFromRight,
|
||||
coverFromLeft,
|
||||
reset
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.slide-label {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
border: 1rpx solid #9A8F79;
|
||||
}
|
||||
|
||||
.color-bg {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
transition: width 0.3s ease-out;
|
||||
}
|
||||
|
||||
.default-color {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.right-cover {
|
||||
height: 100%;
|
||||
top: 0;
|
||||
/* border-radius: 25rpx; */
|
||||
}
|
||||
|
||||
.left-cover {
|
||||
height: 100%;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.content-layer {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
</style>
|
||||
10
pages.json
10
pages.json
|
|
@ -1,4 +1,11 @@
|
|||
{
|
||||
"easycom": {
|
||||
"autoscan": true,
|
||||
"custom": {
|
||||
// 通用规则:匹配 guyu 下任意子目录的组件,格式 <目录名>-<组件名>
|
||||
"^guyu-([a-z]+)-(.*)": "@/components/guyu/$1/$2.vue"
|
||||
}
|
||||
},
|
||||
"pages": [ //pages数组中第一项表示应用启动页,参考:https://uniapp.dcloud.io/collocation/pages
|
||||
{
|
||||
"path": "pages/index/index",
|
||||
|
|
@ -89,7 +96,8 @@
|
|||
"selectedColor": "#333333",
|
||||
"borderStyle": "black",
|
||||
"height": "129.17rpx",
|
||||
"list": [{
|
||||
"list": [
|
||||
{
|
||||
"pagePath": "pages/home/home-page",
|
||||
"iconPath": "/static/tabbar/ic_home.png",
|
||||
"selectedIconPath": "/static/tabbar/ic_s.png"
|
||||
|
|
|
|||
|
|
@ -1,176 +1,146 @@
|
|||
<!-- 滑动切换选项卡+吸顶演示(上一个tab数据不保留,滚动流畅) -->
|
||||
<template>
|
||||
<view class="content">
|
||||
<!-- 搜索 -->
|
||||
<home-search style="width: 100%;" />
|
||||
<!-- 公告 -->
|
||||
<home-notice :notice-info="homeData?.noticeInfo" />
|
||||
<!-- 轮播图 -->
|
||||
<home-swiper :advert-list="homeData?.advertList" style="width: 100%;" />
|
||||
<!-- 推荐位 -->
|
||||
<home-recommend :rec-list="homeData?.recList" @item-click="toDetails" style="width: 100%;" />
|
||||
<view>
|
||||
<z-paging ref="pagePaging" refresher-only @onRefresh="onRefresh" @scrolltolower="scrolltolower"
|
||||
@scroll="scroll">
|
||||
<view class="content">
|
||||
<guyu-home-search style="width: 100%;"></guyu-home-search>
|
||||
<!-- 公告 -->
|
||||
<guyu-home-notice :notice-info="homeData?.noticeInfo" />
|
||||
<!-- 轮播图 -->
|
||||
<guyu-home-swiper :advert-list="homeData?.advertList" style="width: 100%;" />
|
||||
<!-- 推荐位 -->
|
||||
<guyu-home-recommend :rec-list="homeData?.recList" style="width: 100%;" />
|
||||
|
||||
<!-- tab -->
|
||||
<view class="" style="width: 100%; display: flex; flex-direction: row; margin-top: 32.64rpx;">
|
||||
<view class="" v-for="(item, index) in homeData.categories" :key="index" @click="clickTab(index)"
|
||||
:style="setTabBg(index)"
|
||||
style="padding: 0 16.67rpx 6rpx 16.67rpx ; margin-right: 26.39rpx; border-radius: 50rpx;">
|
||||
<text class="myZt-500w" style=" font-size: 23.61rpx;">{{ item.name }}</text>
|
||||
<!-- 小程序中直接修改组件style为position: sticky;无效,需要在组件外层套一层view -->
|
||||
<view class="bar-view" style="z-index:97;position: sticky;top :0;background-color: #fff;">
|
||||
<view :style="{ height: tabsBarHeight + 'px' }" class="status-bar"> </view>
|
||||
<guyu-home-tabs ref="tabs" :list="homeData?.categories" @change="tabsChange" :current="current" />
|
||||
</view>
|
||||
<swiper class="swiper" :style="[{ height: swiperHeight + 'px' }]" :current="current"
|
||||
@transition="swiperTransition" @animationfinish="swiperAnimationfinish">
|
||||
<swiper-item class="swiper-item" v-for="(item, index) in homeData?.categories" :key="index">
|
||||
<guyu-home-goods-list ref="swiperList" :tabIndex="index" :currentIndex="current"
|
||||
@heightChanged="heightChanged">
|
||||
</guyu-home-goods-list>
|
||||
</swiper-item>
|
||||
</swiper>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 商品列表 -->
|
||||
<view class="grid-container">
|
||||
<home-goods-item v-for="(item, index) in goodsLsit" :key="index" :goods-item="item" />
|
||||
</view>
|
||||
</z-paging>
|
||||
</view>
|
||||
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {
|
||||
ref,
|
||||
reactive
|
||||
} from 'vue';
|
||||
import {
|
||||
homeData,
|
||||
isLoading,
|
||||
error,
|
||||
preloadHomeData,
|
||||
refreshHomeData
|
||||
} from '@/common/server/home';
|
||||
import HomeSearch from '@/components/guyu-home-container/home-search.vue';
|
||||
import HomeNotice from '@/components/guyu-home-container/home-notice.vue';
|
||||
import HomeSwiper from '@/components/guyu-home-container/home-swiper.vue';
|
||||
import HomeRecommend from '@/components/guyu-home-container/home-recommend.vue';
|
||||
import HomeGoodsItem from '@/components/guyu-home-container/home-goods-item.vue';
|
||||
import { ref, onMounted } from 'vue';
|
||||
import {
|
||||
homeData,
|
||||
isLoading,
|
||||
error,
|
||||
preloadHomeData,
|
||||
refreshHomeData
|
||||
} from '@/common/server/home';
|
||||
// 状态变量
|
||||
const swiperHeight = ref(0);
|
||||
const tabList = ref(['测试1', '测试2', '测试3', '测试4']);
|
||||
const current = ref(0); // tabs组件的current值,表示当前活动的tab选项
|
||||
const tabsBarHeight = ref(0);
|
||||
const statusBarHeight = ref(uni.getSystemInfoSync().statusBarHeight);
|
||||
const isQuerying = ref(false);
|
||||
|
||||
// 组件引用
|
||||
const pagePaging = ref(null);
|
||||
const tabs = ref(null);
|
||||
const swiperList = ref(null);
|
||||
|
||||
onLoad(() => {
|
||||
onLoad(() => {
|
||||
|
||||
});
|
||||
// 初始化加载
|
||||
onMounted(() => {
|
||||
if (!homeData.value) preloadHomeData();
|
||||
});
|
||||
const currendIndex = ref(0);
|
||||
|
||||
|
||||
const goodsLsit = reactive([{
|
||||
id: 1,
|
||||
title: "坂本日常坂本日常坂本日常坂本日常坂本日常坂本日常坂本日常坂本日常坂本日常坂本日常坂本日常",
|
||||
imgUrl: "",
|
||||
type: "",
|
||||
price: "20"
|
||||
},
|
||||
{
|
||||
id: 1,
|
||||
title: "坂本日常坂本日常坂本日常坂本日常",
|
||||
imgUrl: "",
|
||||
type: "",
|
||||
price: "20"
|
||||
},
|
||||
{
|
||||
id: 1,
|
||||
title: "坂本日常坂本日常坂本日常坂本日常",
|
||||
imgUrl: "",
|
||||
type: "",
|
||||
price: "20"
|
||||
},
|
||||
{
|
||||
id: 1,
|
||||
title: "坂本日常坂本日常坂本日常坂本日常",
|
||||
imgUrl: "",
|
||||
type: "",
|
||||
price: "20"
|
||||
},
|
||||
{
|
||||
id: 1,
|
||||
title: "坂本日常坂本日常坂本日常坂本日常",
|
||||
imgUrl: "",
|
||||
type: "",
|
||||
price: "20"
|
||||
},
|
||||
{
|
||||
id: 1,
|
||||
title: "坂本日常坂本日常坂本日常坂本日常",
|
||||
imgUrl: "",
|
||||
type: "",
|
||||
price: "20"
|
||||
},
|
||||
{
|
||||
id: 1,
|
||||
title: "坂本日常坂本日常坂本日常坂本日常",
|
||||
imgUrl: "",
|
||||
type: "",
|
||||
price: "20"
|
||||
},
|
||||
{
|
||||
id: 1,
|
||||
title: "坂本日常坂本日常坂本日常坂本日常",
|
||||
imgUrl: "",
|
||||
type: "",
|
||||
price: "20"
|
||||
},
|
||||
{
|
||||
id: 1,
|
||||
title: "坂本日常坂本日常坂本日常坂本日常",
|
||||
imgUrl: "",
|
||||
type: "",
|
||||
price: "20"
|
||||
},
|
||||
{
|
||||
id: 1,
|
||||
title: "坂本日常坂本日常坂本日常坂本日常",
|
||||
imgUrl: "",
|
||||
type: "",
|
||||
price: "20"
|
||||
});
|
||||
// 初始化加载
|
||||
onMounted(() => {
|
||||
if (!homeData.value) preloadHomeData();
|
||||
});
|
||||
// 方法
|
||||
const scroll = (e) => {
|
||||
// #ifdef MP
|
||||
if (e.detail.scrollTop < 700 && statusBarHeight.value > 0) {
|
||||
if (isQuerying.value) {
|
||||
return;
|
||||
}
|
||||
]);
|
||||
|
||||
// 方法
|
||||
const clickTab = (index) => {
|
||||
currendIndex.value = index;
|
||||
};
|
||||
|
||||
const setTabBg = (index) => {
|
||||
if (currendIndex.value == index) {
|
||||
return {
|
||||
backgroundColor: '#F5D677',
|
||||
border: '1rpx solid transparent'
|
||||
isQuerying.value = true;
|
||||
const query = uni.createSelectorQuery();
|
||||
query.select('.bar-view').boundingClientRect(rect => {
|
||||
if (rect) {
|
||||
// 判断元素是否粘滞
|
||||
if (rect.top <= 0 && tabsBarHeight.value == 0) {
|
||||
tabsBarHeight.value = statusBarHeight.value;
|
||||
} else if (rect.top > 30 && statusBarHeight.value > 0) {
|
||||
tabsBarHeight.value = 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
backgroundColor: 'transparent',
|
||||
border: '1rpx solid #9A8F79'
|
||||
}
|
||||
}
|
||||
};
|
||||
isQuerying.value = false;
|
||||
}).exec();
|
||||
}
|
||||
// #endif
|
||||
};
|
||||
|
||||
const toDetails = (id) => {
|
||||
uni.navigateTo({
|
||||
url: '/pages/home/product-details?id=' + id
|
||||
});
|
||||
};
|
||||
// tabs通知swiper切换
|
||||
const tabsChange = (index) => {
|
||||
_setCurrent(index);
|
||||
};
|
||||
|
||||
// 下拉刷新时,通知当前显示的列表进行reload操作
|
||||
const onRefresh = () => {
|
||||
swiperList.value[current.value].reload(() => {
|
||||
//当当前显示的列表刷新结束,结束当前页面的刷新状态
|
||||
pagePaging.value.endRefresh();
|
||||
});
|
||||
};
|
||||
|
||||
// 当滚动到底部时,通知当前显示的列表加载更多
|
||||
const scrolltolower = () => {
|
||||
swiperList.value[current.value].doLoadMore();
|
||||
};
|
||||
|
||||
// swiper滑动中
|
||||
const swiperTransition = (e) => {
|
||||
tabs.value.setDx(e.detail.dx);
|
||||
};
|
||||
|
||||
// swiper滑动结束
|
||||
const swiperAnimationfinish = (e) => {
|
||||
_setCurrent(e.detail.current);
|
||||
tabs.value.unlockDx();
|
||||
};
|
||||
|
||||
// 设置swiper的高度
|
||||
const heightChanged = (height) => {
|
||||
if (height === 0) {
|
||||
// 默认swiper高度为屏幕可用高度-tabsView高度-slot="top"内view的高度
|
||||
// 注意:uni.upx2px(80)不是固定的,它等于slot="top"内view的高度,如果slot="top"内view的高度不为80rpx,则需要修改这个值
|
||||
height = uni.getSystemInfoSync().windowHeight - uni.upx2px(80);
|
||||
}
|
||||
swiperHeight.value = height;
|
||||
};
|
||||
|
||||
const _setCurrent = (currentVal) => {
|
||||
if (currentVal !== current.value) {
|
||||
//切换tab时,将上一个tab的数据清空
|
||||
swiperList.value[current.value].clear();
|
||||
}
|
||||
current.value = currentVal;
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.content {
|
||||
width: 94%;
|
||||
height: 100vh;
|
||||
margin: 0 auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
position: relative;
|
||||
align-items: center;
|
||||
}
|
||||
<style lang="scss" scoped>
|
||||
.content {
|
||||
width: 96%;
|
||||
margin-left: 2%;
|
||||
background-color: url('@@:static/bg.png');
|
||||
background-size: 100% 100%;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
.grid-container {
|
||||
width: 100%;
|
||||
display: grid;
|
||||
/* 3列等宽 */
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
/* 间距 */
|
||||
gap: 34.72rpx;
|
||||
padding: 20rpx;
|
||||
}
|
||||
.swiper {
|
||||
height: 1000px;
|
||||
}
|
||||
</style>
|
||||
51
uni_modules/z-paging/changelog.md
Normal file
51
uni_modules/z-paging/changelog.md
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
## 2.8.7(2025-05-30)
|
||||
1.`新增` props:`layout-only`,支持仅使用基础布局。
|
||||
2.`新增` `goF2`方法,支持手动触发进入二楼。
|
||||
3.`新增` `@scrollDirectionChange`事件,支持监听列表滚动方向改变。
|
||||
4.`新增` props:`paging-class`,支持直接设置`z-paging`的`class`。
|
||||
5.`新增` `addKeyboardHeightChangeListener`方法,支持手动添加键盘高度变化监听。
|
||||
6.`修复` `scrollIntoViewById`方法在存在`slot=top`或局部区域滚动时,滚动的位置不准确的问题。
|
||||
7.`优化` 重构底部安全区域处理逻辑,修改为占位view的方式,处理方案更灵活并支持自定义底部安全区域颜色。
|
||||
8.`优化` 兼容在`nvue`+`vue3`中使用`waterfall`。
|
||||
9.`优化` 规范`types`中对`style`类型的约束。
|
||||
## 2.8.6(2025-03-17)
|
||||
1.`新增` 聊天记录模式流式输出(类似chatGPT回答)演示demo。
|
||||
2.`新增` z-paging及其公共子组件支持`HBuilderX`代码文档提示。
|
||||
3.`新增` props:`virtual-in-swiper-slot`,用以解决vue3+(微信小程序或QQ小程序)中,使用非内置列表写法时,若z-paging在`swiper-item`中存在的无法获取slot插入的cell高度进而导致虚拟列表失败的问题。
|
||||
4.`新增` `@scrolltolower`和@`scrolltoupper`支持nvue。
|
||||
5.`修复` 由`v2.8.1`引出的方法`scrollIntoViewById`在微信小程序+vue3中无效的问题。
|
||||
6.`修复` 由`v2.8.1`引出的在子组件内使用z-paging虚拟列表无效的问题。
|
||||
7.`修复` 在微信小程序中基础库版本较高时`wx.getSystemInfoSync is deprecated`警告。
|
||||
8.`优化` 提升下拉刷新在鸿蒙Next中的性能。
|
||||
9.`优化` `@scrolltolower`和`@scrolltoupper`在倒置的聊天记录模式下的触发逻辑。
|
||||
10.`优化` 其他细节调整。
|
||||
## 2.8.5(2025-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.4(2024-12-02)
|
||||
1.`修复` 在虚拟列表+vue2中,顶部占位采用transformY方案;在虚拟列表+vue3中,顶部占位采用view占位方案。以解决在vue2+微信小程序+安卓+兼容模式中,可能出现的虚拟列表闪动的问题。
|
||||
2.`修复` 在列表渲染时(尤其是在虚拟列表中)偶现的【点击加载更多】闪现的问题。
|
||||
3.`优化` 统一在RefresherStatus枚举中Loading取值。
|
||||
4.`优化` `defaultPageNo`&`defaultPageSize`修改为只允许number类型。
|
||||
5.`优化` 提升兼容性&细节优化。
|
||||
## 2.8.3(2024-11-27)
|
||||
1.`修复` `doInsertVirtualListItem`插入数据无效的问题。
|
||||
2.`优化` 提升兼容性&细节优化。
|
||||
## 2.8.2(2024-11-25)
|
||||
1.`优化` types中`ZPagingRef`和`ZPagingInstance`支持泛型。
|
||||
## 2.8.1(2024-11-24)
|
||||
1.`新增` 完整的`props`、`slots`、`methods`、`events`的typescript types声明,可在ts中获得绝佳的代码提示体验。
|
||||
2.`新增` `virtual-cell-id-prefix`:虚拟列表cell id的前缀,适用于一个页面有多个虚拟列表的情况,用以区分不同虚拟列表cell的id。
|
||||
3.`修复` 在vue3+(微信小程序或QQ小程序)中,使用非内置列表写法时,若`z-paging`在`swiper-item`标签内的情况下存在的无法获取slot插入的cell高度的问题。
|
||||
4.`修复` 在虚拟列表中分页数据小于1页时插入新数据,虚拟列表未生效的问题。
|
||||
5.`修复` 在虚拟列表中调用`refresh`时,cell的index计算不正确的问题。
|
||||
6.`修复` 在快手小程序中内容较少或空数据时`z-paging`未能铺满全屏的问题。
|
||||
7.`优化` `events`中的参数涉及枚举的部分,统一由之前的number类型修改为string类型,展示更直观!涉及的events:`@query`中的`from`参数;`@refresherStatusChange`中的`status`参数;`@loadingStatusChange`中的`status`参数;`slot=refresher`中的`refresherStatus`参数;`slot=chatLoading`中的`loadingMoreStatus`参数。更新版本请特别留意!
|
||||
## 2.8.0(2024-10-21)
|
||||
1.`新增` 全面支持鸿蒙Next。
|
||||
2.`修复` 设置了`refresher-complete-delay`后,在下拉刷新期间调用reload导致的无法再次下拉刷新的问题。
|
||||
3.`优化` 废弃虚拟列表transformY顶部占位方案,修改为空view占位。解决因使用旧方案导致的vue3中可能出现的虚拟列表闪动问题。提升虚拟列表的兼容性。
|
||||
|
||||
|
|
@ -140,9 +140,11 @@ function getSystemInfoSync(useCache = false) {
|
|||
const infoTypes = ['DeviceInfo', 'AppBaseInfo', 'WindowInfo'];
|
||||
const { deviceInfo, appBaseInfo, windowInfo } = infoTypes.reduce((acc, key) => {
|
||||
const method = `get${key}`;
|
||||
if (uni[method] && uni.canIUse(method)) {
|
||||
acc[key.charAt(0).toLowerCase() + key.slice(1)] = uni[method]();
|
||||
}
|
||||
try{
|
||||
if (uni[method] && uni.canIUse(method)) {
|
||||
acc[key.charAt(0).toLowerCase() + key.slice(1)] = uni[method]();
|
||||
}
|
||||
}catch{}
|
||||
return acc;
|
||||
}, {});
|
||||
// 如果deviceInfo、appBaseInfo和windowInfo都可以从各自专属的api中获取,则整合它们的数据
|
||||
89
uni_modules/z-paging/package.json
Normal file
89
uni_modules/z-paging/package.json
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
{
|
||||
"id": "z-paging",
|
||||
"name": "z-paging",
|
||||
"displayName": "【z-paging下拉刷新、上拉加载】高性能,全平台兼容。支持虚拟列表,分页全自动处理",
|
||||
"version": "2.8.7",
|
||||
"description": "超简单、低耦合!使用wxs+renderjs实现。支持自定义下拉刷新、上拉加载更多、虚拟列表、下拉进入二楼、自动管理空数据图、无闪动聊天分页、本地分页、国际化等数百项配置",
|
||||
"keywords": [
|
||||
"下拉刷新",
|
||||
"上拉加载",
|
||||
"分页器",
|
||||
"nvue",
|
||||
"虚拟列表"
|
||||
],
|
||||
"repository": "https://github.com/SmileZXLee/uni-z-paging",
|
||||
"engines": {
|
||||
"HBuilderX": "^3.0.7"
|
||||
},
|
||||
"dcloudext": {
|
||||
"sale": {
|
||||
"regular": {
|
||||
"price": "0.00"
|
||||
},
|
||||
"sourcecode": {
|
||||
"price": "0.00"
|
||||
}
|
||||
},
|
||||
"contact": {
|
||||
"qq": "393727164"
|
||||
},
|
||||
"declaration": {
|
||||
"ads": "无",
|
||||
"data": "无",
|
||||
"permissions": "无"
|
||||
},
|
||||
"npmurl": "https://www.npmjs.com/package/z-paging",
|
||||
"type": "component-vue"
|
||||
},
|
||||
"uni_modules": {
|
||||
"dependencies": [],
|
||||
"encrypt": [],
|
||||
"platforms": {
|
||||
"cloud": {
|
||||
"tcb": "y",
|
||||
"aliyun": "y",
|
||||
"alipay": "n"
|
||||
},
|
||||
"client": {
|
||||
"App": {
|
||||
"app-vue": "y",
|
||||
"app-nvue": "y",
|
||||
"app-harmony": "u",
|
||||
"app-uvue": "u"
|
||||
},
|
||||
"H5-mobile": {
|
||||
"Safari": "y",
|
||||
"Android Browser": "y",
|
||||
"微信浏览器(Android)": "y",
|
||||
"QQ浏览器(Android)": "y"
|
||||
},
|
||||
"H5-pc": {
|
||||
"Chrome": "y",
|
||||
"IE": "y",
|
||||
"Edge": "y",
|
||||
"Firefox": "y",
|
||||
"Safari": "y"
|
||||
},
|
||||
"小程序": {
|
||||
"微信": "y",
|
||||
"阿里": "y",
|
||||
"百度": "y",
|
||||
"字节跳动": "y",
|
||||
"QQ": "y",
|
||||
"钉钉": "y",
|
||||
"快手": "y",
|
||||
"飞书": "y",
|
||||
"京东": "y"
|
||||
},
|
||||
"快应用": {
|
||||
"华为": "y",
|
||||
"联盟": "y"
|
||||
},
|
||||
"Vue": {
|
||||
"vue2": "y",
|
||||
"vue3": "y"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
57
uni_modules/z-paging/readme.md
Normal file
57
uni_modules/z-paging/readme.md
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
# z-paging
|
||||
|
||||
<p align="center">
|
||||
<img alt="logo" src="https://z-paging.zxlee.cn/img/title-logo.png" height="100" style="margin-bottom: 50px;" />
|
||||
</p>
|
||||
|
||||
[](https://github.com/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" />
|
||||
|
||||
`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)
|
||||
|
||||
### 文档地址:[https://z-paging.zxlee.cn](https://z-paging.zxlee.cn)
|
||||
|
||||
### 更新组件前,请注意[版本差异](https://z-paging.zxlee.cn/start/upgrade-guide.html)
|
||||
|
||||
***
|
||||
### 功能&特点
|
||||
* 【配置简单】仅需两步(绑定网络请求方法、绑定分页结果数组)轻松完成完整下拉刷新,上拉加载更多功能。
|
||||
* 【低耦合,低侵入】分页自动管理。在page中无需处理任何分页相关逻辑,无需在data中定义任何分页相关变量,全由z-paging内部处理。
|
||||
* 【超灵活,支持各种类型自定义】支持自定义下拉刷新,自定义上拉加载更多等各种自定义效果;支持使用内置自动分页,同时也支持通过监听下拉刷新和滚动到底部事件自行处理;支持使用自带全屏布局规范,同时也支持将z-paging自由放在任意容器中。
|
||||
* 【功能丰富】支持国际化,支持自定义且自动管理空数据图,支持主题模式切换,支持本地分页,支持无闪动聊天分页模式,支持展示最后更新时间,支持吸顶效果,支持内部scroll-view滚动与页面滚动,支持一键滚动到顶部,支持下拉进入二楼等诸多功能。
|
||||
* 【【全平台兼容】支持vue&nvue,vue2&vue3,js&ts,支持h5、app、鸿蒙Next及各家小程序。
|
||||
* 【高性能】在app-vue、h5、微信小程序、QQ小程序上使用wxs+renderjs在视图层实现下拉刷新;支持虚拟列表,轻松渲染百万级列表数据!
|
||||
|
||||
***
|
||||
### 反馈qq群
|
||||
* 官方1群`已满`:[790460711](https://jq.qq.com/?_wv=1027&k=vU2fKZZH)
|
||||
|
||||
* 官方2群`已满`:[371624008](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=avPmibADf2TNi4LxkIwjCE5vbfXpa-r1&authKey=dQ%2FVDAR87ONxI4b32Py%2BvmXbhnopjHN7%2FJPtdsqJdsCPFZB6zDQ17L06Uh0kITUZ&noverify=0&group_code=371624008)
|
||||
* 官方3群:[343409055](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=sIaNqiCMIjxGQVksjytCw6R8DSiibHR7&authKey=pp995q8ZzFtl5F2xUwvvceP24QTcguWW%2FRVoDnMa8JZF4L2DmS%2B%2FV%2F5sYrcgPsmW&noverify=0&group_code=343409055)
|
||||
|
||||
***
|
||||
|
||||
### 预览
|
||||
|
||||
***
|
||||
|
||||
| 自定义下拉刷新效果演示 | 滑动切换选项卡+吸顶演示 | 聊天记录模式演示 |
|
||||
| :----------------------------------------------------------: | :----------------------------------------------------------: | ------------------------------------------------------------ |
|
||||
|  |  |  |
|
||||
|
||||
| 虚拟列表(流畅渲染1万+条)演示 | 下拉进入二楼演示 | 在弹窗内使用演示 |
|
||||
| :----------------------------------------------------------: | :----------------------------------------------------------: | ------------------------------------------------------------ |
|
||||
|  |  |  |
|
||||
|
||||
|
||||
### 在线demo体验地址:
|
||||
|
||||
* [https://demo.z-paging.zxlee.cn](https://demo.z-paging.zxlee.cn)
|
||||
|
||||
| 扫码体验 |
|
||||
| ------------------------------------------------------------ |
|
||||
|  |
|
||||
|
||||
### demo下载
|
||||
* 支持vue2&vue3的`选项式api`写法demo下载,请点击页面右上角的【使用HBuilderX导入示例项目】或【下载示例项目ZIP】。
|
||||
* 支持vue3的`组合式api`写法demo下载,请访问[github](https://github.com/SmileZXLee/uni-z-paging)。
|
||||
11
uni_modules/z-paging/types/comps.d.ts
vendored
Normal file
11
uni_modules/z-paging/types/comps.d.ts
vendored
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
declare module 'vue' {
|
||||
export interface GlobalComponents {
|
||||
['z-paging']: typeof import('./comps/z-paging')['ZPaging']
|
||||
['z-paging-swiper']: typeof import('./comps/z-paging-swiper')['ZPagingSwiper']
|
||||
['z-paging-swiper-item']: typeof import('./comps/z-paging-swiper-item')['ZPagingSwiperItem']
|
||||
['z-paging-empty-view']: typeof import('./comps/z-paging-empty-view')['ZPagingEmptyView']
|
||||
['z-paging-cell']: typeof import('./comps/z-paging-cell')['ZPagingCell']
|
||||
}
|
||||
}
|
||||
|
||||
export {}
|
||||
9
uni_modules/z-paging/types/comps/_common.d.ts
vendored
Normal file
9
uni_modules/z-paging/types/comps/_common.d.ts
vendored
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
export interface AllowedComponentProps {
|
||||
class?: unknown;
|
||||
style?: unknown;
|
||||
}
|
||||
|
||||
export interface VNodeProps {
|
||||
key?: string | number | symbol;
|
||||
ref?: unknown;
|
||||
}
|
||||
29
uni_modules/z-paging/types/comps/z-paging-cell.d.ts
vendored
Normal file
29
uni_modules/z-paging/types/comps/z-paging-cell.d.ts
vendored
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
import { AllowedComponentProps, VNodeProps } from './_common'
|
||||
|
||||
// ****************************** Props ******************************
|
||||
declare interface ZPagingCellProps {
|
||||
/**
|
||||
* z-paging-cell样式
|
||||
*/
|
||||
cellStyle?: Partial<CSSStyleDeclaration>
|
||||
}
|
||||
|
||||
// ****************************** Slots ******************************
|
||||
declare interface ZPagingCellSlots {
|
||||
// ******************** 主体布局Slot ********************
|
||||
/**
|
||||
* 默认插入的view
|
||||
*/
|
||||
['default']?: () => any
|
||||
}
|
||||
|
||||
declare interface _ZPagingCell {
|
||||
new (): {
|
||||
$props: AllowedComponentProps &
|
||||
VNodeProps &
|
||||
ZPagingCellProps
|
||||
$slots: ZPagingCellSlots
|
||||
}
|
||||
}
|
||||
|
||||
export declare const ZPagingCell: _ZPagingCell
|
||||
95
uni_modules/z-paging/types/comps/z-paging-empty-view.d.ts
vendored
Normal file
95
uni_modules/z-paging/types/comps/z-paging-empty-view.d.ts
vendored
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
import { AllowedComponentProps, VNodeProps } from './_common'
|
||||
|
||||
// ****************************** Props ******************************
|
||||
declare interface ZPagingEmptyViewProps {
|
||||
/**
|
||||
* 空数据图片是否铺满z-paging,默认为是。若设置为否,则为填充满z-paging的剩余部分
|
||||
* @default false
|
||||
* @since 2.0.3
|
||||
*/
|
||||
emptyViewFixed?: boolean;
|
||||
|
||||
/**
|
||||
* 空数据图描述文字
|
||||
* @default "没有数据哦~"
|
||||
*/
|
||||
emptyViewText?: string;
|
||||
|
||||
/**
|
||||
* 空数据图图片,默认使用z-paging内置的图片
|
||||
* - 建议使用绝对路径,开头不要添加"@",请以"/"开头
|
||||
*/
|
||||
emptyViewImg?: string;
|
||||
|
||||
/**
|
||||
* 空数据图点击重新加载文字
|
||||
* @default "重新加载"
|
||||
* @since 1.6.7
|
||||
*/
|
||||
emptyViewReloadText?: string;
|
||||
|
||||
/**
|
||||
* 空数据图样式,可设置空数据view的top等
|
||||
* - 如果空数据图不是fixed布局,则此处是`margin-top`
|
||||
*/
|
||||
emptyViewStyle?: Partial<CSSStyleDeclaration>;
|
||||
|
||||
/**
|
||||
* 空数据图img样式
|
||||
*/
|
||||
emptyViewImgStyle?: Partial<CSSStyleDeclaration>;
|
||||
|
||||
/**
|
||||
* 空数据图描述文字样式
|
||||
*/
|
||||
emptyViewTitleStyle?: Partial<CSSStyleDeclaration>;
|
||||
|
||||
/**
|
||||
* 空数据图重新加载按钮样式
|
||||
* @since 1.6.7
|
||||
*/
|
||||
emptyViewReloadStyle?: Partial<CSSStyleDeclaration>;
|
||||
|
||||
/**
|
||||
* 是否显示空数据图重新加载按钮(无数据时)
|
||||
* @default false
|
||||
* @since 1.6.7
|
||||
*/
|
||||
showEmptyViewReload?: boolean;
|
||||
|
||||
/**
|
||||
* 是否是加载失败
|
||||
* @default false
|
||||
*/
|
||||
isLoadFailed?: boolean;
|
||||
|
||||
/**
|
||||
* 空数据图中布局的单位
|
||||
* @default 'rpx'
|
||||
* @since 2.6.7
|
||||
*/
|
||||
unit?: 'rpx' | 'px';
|
||||
|
||||
// ****************************** Events ******************************
|
||||
/**
|
||||
* 点击了重新加载按钮
|
||||
*/
|
||||
onReload?: () => void
|
||||
|
||||
/**
|
||||
* 点击了空数据view
|
||||
* @since 2.3.3
|
||||
*/
|
||||
onViewClick?: () => void
|
||||
}
|
||||
|
||||
declare interface _ZPagingEmptyView {
|
||||
new (): {
|
||||
$props: AllowedComponentProps &
|
||||
VNodeProps &
|
||||
ZPagingEmptyViewProps
|
||||
}
|
||||
}
|
||||
|
||||
export declare const ZPagingEmptyView: _ZPagingEmptyView
|
||||
|
||||
95
uni_modules/z-paging/types/comps/z-paging-swiper-item.d.ts
vendored
Normal file
95
uni_modules/z-paging/types/comps/z-paging-swiper-item.d.ts
vendored
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
import { AllowedComponentProps, VNodeProps } from './_common'
|
||||
|
||||
// ****************************** Props ******************************
|
||||
declare interface ZPagingSwiperItemProps {
|
||||
/**
|
||||
* 当前组件的index,也就是当前组件是swiper中的第几个
|
||||
* @default 0
|
||||
*/
|
||||
tabIndex?: number
|
||||
|
||||
/**
|
||||
* 当前swiper切换到第几个index
|
||||
* @default 0
|
||||
*/
|
||||
currentIndex?: number
|
||||
|
||||
/**
|
||||
* 是否使用虚拟列表。使用页面滚动或nvue时,不支持虚拟列表。在nvue中z-paging内置了list组件,效果与虚拟列表类似,并且可以提供更好的性能。
|
||||
* @default false
|
||||
*/
|
||||
useVirtualList?: boolean
|
||||
|
||||
/**
|
||||
* 虚拟列表cell高度模式,默认为`fixed`,也就是每个cell高度完全相同,将以第一个cell高度为准进行计算。
|
||||
* @default 'fixed'
|
||||
*/
|
||||
cellHeightMode?: 'fixed' | 'dynamic'
|
||||
|
||||
/**
|
||||
* 预加载的列表可视范围(列表高度)页数。此数值越大,则虚拟列表中加载的dom越多,内存消耗越大(会维持在一个稳定值),但增加预加载页面数量可缓解快速滚动短暂白屏问题。
|
||||
* @default 12
|
||||
*/
|
||||
preloadPage?: number | string
|
||||
|
||||
/**
|
||||
* 虚拟列表列数,默认为1。常用于每行有多列的情况,例如每行有2列数据,需要将此值设置为2。
|
||||
* @default 1
|
||||
* @since 2.2.8
|
||||
*/
|
||||
virtualListCol?: number | string
|
||||
|
||||
/**
|
||||
* 虚拟列表scroll取样帧率,默认为80,过低容易出现白屏问题,过高容易出现卡顿问题
|
||||
* @default 80
|
||||
*/
|
||||
virtualScrollFps?: number | string
|
||||
|
||||
/**
|
||||
* 是否在z-paging内部循环渲染列表(使用内置列表)。
|
||||
* @default false
|
||||
*/
|
||||
useInnerList?: boolean
|
||||
|
||||
/**
|
||||
* 内置列表cell的key名称(仅nvue有效,在nvue中开启use-inner-list时必须填此项)
|
||||
* @since 2.2.7
|
||||
*/
|
||||
cellKeyName?: string
|
||||
|
||||
/**
|
||||
* innerList样式
|
||||
*/
|
||||
innerListStyle?: Partial<CSSStyleDeclaration>
|
||||
}
|
||||
|
||||
// ****************************** Methods ******************************
|
||||
declare interface _ZPagingSwiperItemRef {
|
||||
/**
|
||||
* 重新加载分页数据,pageNo恢复为默认值,相当于下拉刷新的效果
|
||||
*
|
||||
* @param [animate=false] 是否展示下拉刷新动画
|
||||
*/
|
||||
reload: (animate?: boolean) => void;
|
||||
|
||||
/**
|
||||
* 请求结束
|
||||
* - 当通过complete传进去的数组长度小于pageSize时,则判定为没有更多了
|
||||
*
|
||||
* @param [data] 请求结果数组
|
||||
* @param [success=true] 是否请求成功
|
||||
*/
|
||||
complete: (data?: any[] | false, success?: boolean) => void;
|
||||
}
|
||||
|
||||
declare interface _ZPagingSwiperItem {
|
||||
new (): {
|
||||
$props: AllowedComponentProps &
|
||||
VNodeProps &
|
||||
ZPagingSwiperItemProps
|
||||
}
|
||||
}
|
||||
|
||||
export declare const ZPagingSwiperItem: _ZPagingSwiperItem
|
||||
|
||||
export declare const ZPagingSwiperItemRef: _ZPagingSwiperItemRef
|
||||
89
uni_modules/z-paging/types/comps/z-paging-swiper.d.ts
vendored
Normal file
89
uni_modules/z-paging/types/comps/z-paging-swiper.d.ts
vendored
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
import { AllowedComponentProps, VNodeProps } from './_common'
|
||||
|
||||
// ****************************** Props ******************************
|
||||
declare interface ZPagingSwiperProps {
|
||||
/**
|
||||
* 是否使用fixed布局,若使用fixed布局,则z-paging-swiper的父view无需固定高度,z-paging高度默认铺满屏幕,页面中的view请放z-paging-swiper标签内,需要固定在顶部的view使用slot="top"包住,需要固定在底部的view使用slot="bottom"包住。
|
||||
* @default true
|
||||
*/
|
||||
fixed?: boolean
|
||||
|
||||
/**
|
||||
* 是否开启底部安全区域适配
|
||||
* @default false
|
||||
*/
|
||||
safeAreaInsetBottom?: boolean
|
||||
|
||||
/**
|
||||
* z-paging-swiper样式
|
||||
*/
|
||||
swiperStyle?: Partial<CSSStyleDeclaration>
|
||||
}
|
||||
|
||||
|
||||
// ****************************** Slots ******************************
|
||||
declare interface ZPagingSwiperSlots {
|
||||
// ******************** 主体布局Slot ********************
|
||||
/**
|
||||
* 默认插入的view
|
||||
*/
|
||||
['default']?: () => any
|
||||
|
||||
/**
|
||||
* 可以将自定义导航栏、tab-view等需要固定的(不需要跟着滚动的)元素放入slot="top"的view中。
|
||||
* 注意,当有多个需要固定的view时,请用一个view包住它们,并且在这个view上设置slot="top"。需要固定在顶部的view请勿设置position: fixed;
|
||||
* @since 1.5.5
|
||||
*/
|
||||
['top']?: () => any
|
||||
|
||||
/**
|
||||
* 可以将需要固定在底部的(不需要跟着滚动的)元素放入slot="bottom"的view中。
|
||||
* 注意,当有多个需要固定的view时,请用一个view包住它们,并且在这个view上设置slot="bottom"。需要固定在底部的view请勿设置position: fixed;
|
||||
* @since 1.6.2
|
||||
*/
|
||||
['bottom']?: () => any
|
||||
|
||||
/**
|
||||
* 可以将需要固定在左侧的(不需要跟着滚动的)元素放入slot="left"的view中。
|
||||
* 注意,当有多个需要固定的view时,请用一个view包住它们,并且在这个view上设置slot="left"。需要固定在左侧的view请勿设置position: fixed;
|
||||
* @since 2.2.3
|
||||
*/
|
||||
['left']?: () => any
|
||||
|
||||
/**
|
||||
* 可以将需要固定在左侧的(不需要跟着滚动的)元素放入slot="right"的view中。
|
||||
* 注意,当有多个需要固定的view时,请用一个view包住它们,并且在这个view上设置slot="right"。需要固定在右侧的view请勿设置position: fixed;
|
||||
* @since 2.2.3
|
||||
*/
|
||||
['right']?: () => any
|
||||
}
|
||||
|
||||
// ****************************** Methods ******************************
|
||||
declare interface _ZPagingSwiperRef {
|
||||
/**
|
||||
* 更新slot="left"和slot="right"宽度,当slot="left"或slot="right"宽度动态改变后调用
|
||||
*
|
||||
* @since 2.3.5
|
||||
*/
|
||||
updateLeftAndRightWidth: () => void;
|
||||
|
||||
/**
|
||||
* 更新fixed模式下z-paging-swiper的布局,在onShow时候调用,以修复在iOS+h5+tabbar+fixed+底部有安全区域的设备中从tabbar页面跳转到无tabbar页面后返回,底部有一段空白区域的问题
|
||||
*
|
||||
* @since 2.6.5
|
||||
*/
|
||||
updateFixedLayout: () => void;
|
||||
}
|
||||
|
||||
declare interface _ZPagingSwiper {
|
||||
new (): {
|
||||
$props: AllowedComponentProps &
|
||||
VNodeProps &
|
||||
ZPagingSwiperProps
|
||||
$slots: ZPagingSwiperSlots
|
||||
}
|
||||
}
|
||||
|
||||
export declare const ZPagingSwiper: _ZPagingSwiper
|
||||
|
||||
export declare const ZPagingSwiperRef: _ZPagingSwiperRef
|
||||
2131
uni_modules/z-paging/types/comps/z-paging.d.ts
vendored
Normal file
2131
uni_modules/z-paging/types/comps/z-paging.d.ts
vendored
Normal file
File diff suppressed because it is too large
Load Diff
24
uni_modules/z-paging/types/index.d.ts
vendored
Normal file
24
uni_modules/z-paging/types/index.d.ts
vendored
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
/// <reference path="./comps.d.ts" />
|
||||
declare module 'z-paging' {
|
||||
export function install() : void
|
||||
/**
|
||||
* z-paging全局配置
|
||||
* - uni.$zp
|
||||
*
|
||||
* @since 2.6.5
|
||||
*/
|
||||
interface $zp {
|
||||
/**
|
||||
* 全局配置
|
||||
*/
|
||||
config : Record<string, any>;
|
||||
}
|
||||
global {
|
||||
interface Uni {
|
||||
$zp : $zp
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
declare type ZPagingSwiperRef = typeof import('./comps/z-paging-swiper')['ZPagingSwiperRef']
|
||||
declare type ZPagingSwiperItemRef = typeof import('./comps/z-paging-swiper-item')['ZPagingSwiperItemRef']
|
||||
9
uni_modules/z-tabs/changelog.md
Normal file
9
uni_modules/z-tabs/changelog.md
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
## 0.3.0(2024-10-21)
|
||||
支持鸿蒙Next
|
||||
## 0.2.7(2024-07-18)
|
||||
1.`新增` 支持切换rpx&px
|
||||
2.`修复` 宽度小于屏幕时底部tabs位置不正确的问题
|
||||
3.`修复` 偶现的Cannot read property 'left' of undefind的问题
|
||||
|
||||
## 0.2.5(2023-01-09)
|
||||
修复可能出现的可能出现的与swiper联动时报错node不存在的bug
|
||||
83
uni_modules/z-tabs/package.json
Normal file
83
uni_modules/z-tabs/package.json
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
{
|
||||
"id": "z-tabs",
|
||||
"name": "z-tabs",
|
||||
"displayName": "【z-tabs】一个简单轻量的tabs组件",
|
||||
"version": "0.3.0",
|
||||
"description": "全平台兼容,支持nvue、vue3",
|
||||
"keywords": [
|
||||
"tabs"
|
||||
],
|
||||
"repository": "https://github.com/SmileZXLee/uni-z-tabs",
|
||||
"engines": {
|
||||
"HBuilderX": "^3.0.7"
|
||||
},
|
||||
"dcloudext": {
|
||||
"sale": {
|
||||
"regular": {
|
||||
"price": "0.00"
|
||||
},
|
||||
"sourcecode": {
|
||||
"price": "0.00"
|
||||
}
|
||||
},
|
||||
"contact": {
|
||||
"qq": "393727164"
|
||||
},
|
||||
"declaration": {
|
||||
"ads": "无",
|
||||
"data": "无",
|
||||
"permissions": "无"
|
||||
},
|
||||
"npmurl": "https://www.npmjs.com/package/@zxlee/z-tabs",
|
||||
"type": "component-vue"
|
||||
},
|
||||
"uni_modules": {
|
||||
"dependencies": [],
|
||||
"encrypt": [],
|
||||
"platforms": {
|
||||
"cloud": {
|
||||
"tcb": "y",
|
||||
"aliyun": "y",
|
||||
"alipay": "n"
|
||||
},
|
||||
"client": {
|
||||
"App": {
|
||||
"app-vue": "y",
|
||||
"app-nvue": "y"
|
||||
},
|
||||
"H5-mobile": {
|
||||
"Safari": "y",
|
||||
"Android Browser": "y",
|
||||
"微信浏览器(Android)": "y",
|
||||
"QQ浏览器(Android)": "y"
|
||||
},
|
||||
"H5-pc": {
|
||||
"Chrome": "y",
|
||||
"IE": "y",
|
||||
"Edge": "y",
|
||||
"Firefox": "y",
|
||||
"Safari": "y"
|
||||
},
|
||||
"小程序": {
|
||||
"微信": "y",
|
||||
"阿里": "y",
|
||||
"百度": "y",
|
||||
"字节跳动": "y",
|
||||
"QQ": "y",
|
||||
"钉钉": "y",
|
||||
"快手": "y",
|
||||
"飞书": "y",
|
||||
"京东": "y"
|
||||
},
|
||||
"快应用": {
|
||||
"华为": "y",
|
||||
"联盟": "y"
|
||||
},
|
||||
"Vue": {
|
||||
"vue2": "y",
|
||||
"vue3": "y"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
177
uni_modules/z-tabs/readme.md
Normal file
177
uni_modules/z-tabs/readme.md
Normal file
|
|
@ -0,0 +1,177 @@
|
|||
# z-tabs
|
||||
|
||||
[](https://github.com/SmileZXLee/uni-z-tabs)
|
||||
[](https://en.wikipedia.org/wiki/MIT_License)
|
||||
|
||||
***
|
||||
|
||||
### 反馈qq群(点击加群):[371624008](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=avPmibADf2TNi4LxkIwjCE5vbfXpa-r1&authKey=dQ%2FVDAR87ONxI4b32Py%2BvmXbhnopjHN7%2FJPtdsqJdsCPFZB6zDQ17L06Uh0kITUZ&noverify=0&group_code=371624008)
|
||||
|
||||
***
|
||||
|
||||
## z-tabs文档
|
||||
|
||||
### 安装
|
||||
|
||||
#### 方式1(推荐):通过uni_modules安装,在插件市场中点击右上角【使用HbuilderX导入插件】即可。
|
||||
|
||||
***
|
||||
|
||||
#### 方式2:通过npm安装
|
||||
|
||||
```bash
|
||||
//若项目之前未使用npm管理依赖(项目根目录下无package.json文件),先在项目根目录执行命令初始化npm工程
|
||||
npm init -y
|
||||
|
||||
//安装
|
||||
npm install @zxlee/z-tabs --save
|
||||
//更新
|
||||
npm update @zxlee/z-tabs
|
||||
```
|
||||
|
||||
然后在`pages.json`中配置`easycom`(注意:下方配置只有在使用npm安装时才需要配置!!!!!)
|
||||
|
||||
```json
|
||||
"easycom": {
|
||||
"^z-tabs": "@zxlee/z-tabs/components/z-tabs/z-tabs.vue"
|
||||
}
|
||||
```
|
||||
|
||||
### 基本使用
|
||||
|
||||
```html
|
||||
<template>
|
||||
<z-tabs :list="list"></z-tabs>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
list: []
|
||||
}
|
||||
},
|
||||
onLoad() {
|
||||
const list = [];
|
||||
for(let i = 0;i < 10;i++) {
|
||||
// list内item支持字符串或对象,下方这个是字符串
|
||||
list.push('tab标题');
|
||||
|
||||
// 如果要展示徽标数,则list中item的数据结构应为:
|
||||
list.push({
|
||||
name: 'tab标题',
|
||||
badge: {
|
||||
// 设置徽标数为6
|
||||
count: 6
|
||||
},
|
||||
// 可以禁用某个item
|
||||
disabled: true
|
||||
});
|
||||
}
|
||||
this.list = list;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
|
||||
|
||||
### props
|
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 | 可选值 |
|
||||
| :------------------ | :----------------------------------------------------------- | :------------- | :------ | :----- |
|
||||
| list | 数据源数组,支持形如`['tab1','tab2']`的格式或`[{name:'tab1',value:1}]`的格式 | Array | [] | - |
|
||||
| current | 当前选中的index | Number\|String | 0 | - |
|
||||
| scroll-count | list数组长度超过scrollCount时滚动显示(不自动铺满全屏) | Number\|String | 5 | - |
|
||||
| tab-width | 自定义每个tab的宽度,默认为0,即代表根据内容自动撑开,单位rpx,支持传100、"100px"或"100rpx" | Number\|String | 0 | 0 |
|
||||
| bar-width | 滑块宽度,单位rpx,支持传100、"100px"或"100rpx" | Number\|String | 45rpx | - |
|
||||
| bar-height | 滑块高度,单位rpx,支持传100、"100px"或"100rpx" | Number\|String | 8rpx | - |
|
||||
| bar-style | 滑块样式,其中的`width`和`height`将被`bar-width`和`bar-height`覆盖 | Object | {} | - |
|
||||
| bottom-space | tabs与底部的间距,单位rpx,支持传100、"100px"或"100rpx" | Number\|String | 8rpx | - |
|
||||
| bar-animate-mode | 【v0.1.5起支持】切换tab时滑块动画模式,与`swiper`联动时有效,点击切换tab时无效,必须调用`setDx`。默认为`line`,即切换tab时滑块宽度保持不变,线性运动。可选值为`worm`,即为类似毛毛虫蠕动效果 | String | line | worm |
|
||||
| name-key | list中item的name(标题)的key | String | name | - |
|
||||
| value-key | list中item的value的key | String | value | - |
|
||||
| active-color | 激活状态tab的颜色 | String | #007AFF | - |
|
||||
| inactive-color | 未激活状态tab的颜色 | String | #666666 | - |
|
||||
| disabled-color | 禁用状态tab的颜色 | String | #bbbbbb | - |
|
||||
| active-style | 激活状态tab的样式 | Object | {} | - |
|
||||
| inactive-style | 未激活状态tab的样式 | Object | {} | - |
|
||||
| disabled-style | 禁用状态tab的样式 | Object | {} | - |
|
||||
| badge-max-count | 徽标数最大数字限制,超过这个数字将变成`badge-max-count`+ | Number\|String | 99 | - |
|
||||
| badge-style | 徽标样式,例如可自定义背景色,字体等等 | Object | {} | - |
|
||||
| bg-color | z-tabs背景色 | String | white | - |
|
||||
| tabs-style | z-tabs样式 | Object | {} | - |
|
||||
| init-trigger-change | 初始化时是否自动触发change事件 | Boolean | true | false |
|
||||
| unit | z-tabs中布局的单位,默认为rpx | String | rpx | px |
|
||||
|
||||
|
||||
|
||||
### events
|
||||
|
||||
| 事件名 | 说明 | 回调参数 |
|
||||
| ------------ | -------------------- | ------------------------------------------------------------ |
|
||||
| @change | tabs改变(点击)时触发 | `参数1`:index(当前切换到的index);<br/>`参数2`:value(当前切换到的value) |
|
||||
| @secondClick | tabs二次点击时触发 | `参数1`:index(当前切换到的index);<br/>`参数2`:value(当前切换到的value) |
|
||||
|
||||
### methods
|
||||
|
||||
| 方法名 | 说明 | 参数 |
|
||||
| ------------------- | ------------------------------------------------------------ | -------------------------------------- |
|
||||
| setDx | 根据swiper的`@transition`实时更新底部dot位置 | swiper的`@transition`中的`e.detail.dx` |
|
||||
| unlockDx | 在swiper的`@animationfinish`中通知`z-tabs`结束多`setDx`的锁定,若在父组件中调用了`setDx`,则必须调用`unlockDx` | - |
|
||||
| updateSubviewLayout | 在nvue+安卓中,若在cell中使用`z-tabs`,且页面加载时cell在屏幕之外,因cell的复用机制,可能导致`z-tabs`内部的布局失效:例如底部bar无法显示,此时可在list滚动到一定区域内(例如快显示`z-tabs`)的时候调用此方法以更新其内部布局。其他情况无需调用! | - |
|
||||
|
||||
### slots
|
||||
|
||||
| 名称 | 说明 |
|
||||
| :---- | ------------ |
|
||||
| left | tabs左侧插槽 |
|
||||
| right | tabs右侧插槽 |
|
||||
|
||||
### 支持全局配置
|
||||
|
||||
* 在`/z-tabs/components/z-tabs/config/index.js`文件中进行配置
|
||||
|
||||
```js
|
||||
export default {
|
||||
'active-color': 'red'
|
||||
}
|
||||
```
|
||||
|
||||
### 【v0.1.4起支持】底部dot与swiper联动演示
|
||||
|
||||
```html
|
||||
<template>
|
||||
<z-tabs ref="tabs" :list="tabList" :current="current" @change="tabsChange" />
|
||||
<swiper :current="current" @transition="swiperTransition" @animationfinish="swiperAnimationfinish">
|
||||
<swiper-item class="swiper-item" v-for="(item, index) in tabList" :key="index">
|
||||
xxx
|
||||
</swiper-item>
|
||||
</swiper>
|
||||
<template>
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
tabList: ['测试1','测试2','测试3','测试4'],
|
||||
current: 0, // tabs组件的current值,表示当前活动的tab选项
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
//tabs通知swiper切换
|
||||
tabsChange(index) {
|
||||
this.current = index;
|
||||
},
|
||||
//swiper滑动中
|
||||
swiperTransition(e) {
|
||||
this.$refs.tabs.setDx(e.detail.dx);
|
||||
},
|
||||
//swiper滑动结束
|
||||
swiperAnimationfinish(e) {
|
||||
this.current = e.detail.current;
|
||||
this.$refs.tabs.unlockDx();
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
```
|
||||
Loading…
Reference in New Issue
Block a user