# Conflicts:
#	components.d.ts
This commit is contained in:
18631081161 2025-07-25 13:29:11 +08:00
commit e56d98c23b
66 changed files with 3671 additions and 190 deletions

View 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
View File

@ -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']
}
}

View File

View 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({
// indexswiper
tabIndex: {
type: Number,
default: 0
},
// swiperindex
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) => {
// pageNopageSize
//
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-pagingreload
paging.value.reload();
};
// swiper
const contentHeightChanged = (height) => {
const finalHeight = dataList.value.length ? height : 0;
// z-tabs使slot="top"viewminHeightslot="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>

View 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-10
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
}
});
// DOMSlideLabel
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>

View 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>

View File

@ -1,4 +1,11 @@
{
"easycom": {
"autoscan": true,
"custom": {
// guyu <>-<>
"^guyu-([a-z]+)-(.*)": "@/components/guyu/$1/$2.vue"
}
},
"pages": [ //pageshttps://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"

View File

@ -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); // tabscurrenttab
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
});
};
// tabsswiper
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"viewslot="top"view80rpx
height = uni.getSystemInfoSync().windowHeight - uni.upx2px(80);
}
swiperHeight.value = height;
};
const _setCurrent = (currentVal) => {
if (currentVal !== current.value) {
//tabtab
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>

View File

@ -0,0 +1,51 @@
## 2.8.72025-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.62025-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.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
1.`修复` 在虚拟列表+vue2中顶部占位采用transformY方案在虚拟列表+vue3中顶部占位采用view占位方案。以解决在vue2+微信小程序+安卓+兼容模式中,可能出现的虚拟列表闪动的问题。
2.`修复` 在列表渲染时(尤其是在虚拟列表中)偶现的【点击加载更多】闪现的问题。
3.`优化` 统一在RefresherStatus枚举中Loading取值。
4.`优化` `defaultPageNo`&`defaultPageSize`修改为只允许number类型。
5.`优化` 提升兼容性&细节优化。
## 2.8.32024-11-27
1.`修复` `doInsertVirtualListItem`插入数据无效的问题。
2.`优化` 提升兼容性&细节优化。
## 2.8.22024-11-25
1.`优化` types中`ZPagingRef`和`ZPagingInstance`支持泛型。
## 2.8.12024-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.02024-10-21
1.`新增` 全面支持鸿蒙Next。
2.`修复` 设置了`refresher-complete-delay`后在下拉刷新期间调用reload导致的无法再次下拉刷新的问题。
3.`优化` 废弃虚拟列表transformY顶部占位方案修改为空view占位。解决因使用旧方案导致的vue3中可能出现的虚拟列表闪动问题。提升虚拟列表的兼容性。

View File

@ -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中获取则整合它们的数据

View 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"
}
}
}
}
}

View 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>
[![version](https://img.shields.io/badge/version-2.8.7-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" />
`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&nvuevue2&vue3js&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)
***
### 预览
***
| 自定义下拉刷新效果演示 | 滑动切换选项卡+吸顶演示 | 聊天记录模式演示 |
| :----------------------------------------------------------: | :----------------------------------------------------------: | ------------------------------------------------------------ |
| ![](https://z-paging.zxlee.cn/public/img/z-paging-demo5.gif) | ![](https://z-paging.zxlee.cn/public/img/z-paging-demo6.gif) | ![](https://z-paging.zxlee.cn/public/img/z-paging-demo7.gif) |
| 虚拟列表(流畅渲染1万+条)演示 | 下拉进入二楼演示 | 在弹窗内使用演示 |
| :----------------------------------------------------------: | :----------------------------------------------------------: | ------------------------------------------------------------ |
| ![](https://z-paging.zxlee.cn/public/img/z-paging-demo8.gif) | ![](https://z-paging.zxlee.cn/public/img/z-paging-demo9.gif) | ![](https://z-paging.zxlee.cn/public/img/z-paging-demo10.gif) |
### 在线demo体验地址
* [https://demo.z-paging.zxlee.cn](https://demo.z-paging.zxlee.cn)
| 扫码体验 |
| ------------------------------------------------------------ |
| ![](https://z-paging.zxlee.cn/public/img/code.png) |
### 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
View 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 {}

View File

@ -0,0 +1,9 @@
export interface AllowedComponentProps {
class?: unknown;
style?: unknown;
}
export interface VNodeProps {
key?: string | number | symbol;
ref?: unknown;
}

View 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

View File

@ -0,0 +1,95 @@
import { AllowedComponentProps, VNodeProps } from './_common'
// ****************************** Props ******************************
declare interface ZPagingEmptyViewProps {
/**
* z-pagingz-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

View File

@ -0,0 +1,95 @@
import { AllowedComponentProps, VNodeProps } from './_common'
// ****************************** Props ******************************
declare interface ZPagingSwiperItemProps {
/**
* indexswiper中的第几个
* @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
/**
* 122
* @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

View 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

File diff suppressed because it is too large Load Diff

24
uni_modules/z-paging/types/index.d.ts vendored Normal file
View 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']

View File

@ -0,0 +1,9 @@
## 0.3.02024-10-21
支持鸿蒙Next
## 0.2.72024-07-18
1.`新增` 支持切换rpx&px
2.`修复` 宽度小于屏幕时底部tabs位置不正确的问题
3.`修复` 偶现的Cannot read property 'left' of undefind的问题
## 0.2.52023-01-09
修复可能出现的可能出现的与swiper联动时报错node不存在的bug

View 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"
}
}
}
}
}

View File

@ -0,0 +1,177 @@
# z-tabs
[![version](https://img.shields.io/badge/version-0.3.0-blue)](https://github.com/SmileZXLee/uni-z-tabs)
[![license](https://img.shields.io/github/license/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>
```