电梯导航、联动菜单 Elevator
- 电梯导航、联动菜单组件。
兼容性
- 兼容:✅
- 不兼容:❌
- 未知:❔
H5 | 安卓 | 苹果 | 微信 | 支付宝 | 百度 | 抖音 | 快手 | 飞书 | 京东 | |
---|---|---|---|---|---|---|---|---|---|---|
✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
小红书 | 鸿蒙 | 360 | 华为快应用 | 快应用联盟 |
---|---|---|---|---|
✅ | ❔ | ❔ | ❔ | ❔ |
插件市场地址
组件介绍
共包含
5
个组件:pure-elevator
:最外层根组件。pure-elevator-floor
:楼层组件,对应左侧选项卡内容。pure-elevator-footer
:脚组件,用来放置底部加载状态等内容。pure-elevator-header
:楼层标题组件,使用二级分类功能时,用来放置二级分类。pure-elevator-group
:组组件,使用二级分类功能时,用来放置二级分类内容。
各组件结构如下:
vue
<template>
<!-- 根组件 -->
<!--
* list: 数据列表,必传
* value: 左侧选项卡激活项的值,必传
* subValue: 子分类激活项的值,可选
* @tabClick:左侧选项卡点击事件
* @tabChange: 左侧选项卡激活项改变事件,由用户触摸滚动右侧内容触发的改变事件
* @subTabChange: 二级分类激活项改变事件,由用户触摸滚动右侧内容触发的改变事件
* @scrolltolower: 上拉触底事件
-->
<pure-elevator
:list="list"
:value="tabValue"
:subValue="subTabValue"
@tabClick="handleTabClick"
@tabChange="handleTabChange"
@subTabChange="handleSubTabChange"
@scrolltolower="handleScrollToLower"
>
<!-- 楼层组件 -->
<!--
* value: 楼层的唯一标识,必传
* floor: 楼层数据,必传
-->
<pure-elevator-floor :value="floor.id" :floor="floor" v-for="floor in list" :key="floor.id">
<!-- 楼层组件头部,用来放置二级菜单 -->
<!-- floorValue: 楼层的唯一标识,必传 -->
<pure-elevator-header :floorValue="floor.id">
<!-- 演示,此处可以放置二级分类 tabs -->
<pure-elevator-tabs :value="subTabValue" @tabClick="handleSubTabClick">
<pure-tabs-item v-for="subTab in floor.children" :key="subTab.id" :value="subTab.id" :item="subTab"></pure-tabs-item>
</pure-elevator-tabs>
</pure-elevator-header>
<!-- 组组件,用来放置楼层内的二级分类分组内容 -->
<!--
* value: 分组的唯一标识,必传
* group: 分组数据,必传
* floorValue: 分组所在楼层的唯一标识,必传
-->
<pure-elevator-group v-for="group in floor.children" :key="floor.id" :value="group.id" :group="group" @floorValue="floor.id">
<!-- 演示,此处放置分组内容 -->
<view v-for="item in group.children" :key="item.id">
{{ item.name }}
</view>
</pure-elevator-group>
</pure-elevator-floor>
<!-- 楼脚组件,一般用来放置加载状态 -->
<pure-elevator-footer>
<!-- 演示,此处放置加载状态 -->
<pure-loadmore :status="loadmoreStatus"></pure-loadmore>
</pure-elevator-footer>
</pure-elevator>
</template>
基础使用
- 基础使用示例。
vue
<template>
<pure-elevator :list="list" :value="tabValue" @tabClick="handleTabClick" @tabChange="handleTabChange">
<!-- 自定义左侧 Tabs -->
<!-- 注意: 抖音小程序和飞书小程序必须使用自定义模式,这是因为在抖音和飞书中,组件套组件时,provide/inject不生效 -->
<template #tabs>
<!-- 这里建议用一个 view 组件进行包裹,因为在实际测试中,快手小程序如果不再包裹一层,会导致 provide/inject 的数据丢失 -->
<view>
<pure-tabs :value="tabValue" @tabClick="handleTabClick" vertical>
<pure-tabs-item v-for="(item, index) in list" :key="index" :value="item.id" :item="item" :disabled="item.disabled">
<text class="tab">{{ item.name }}</text>
</pure-tabs-item>
</pure-tabs>
</view>
</template>
<pure-elevator-floor v-for="floor in list" :key="floor.id" :value="floor.id" :floor="floor">
<view class="floor">
<view class="title">{{ floor.name }}</view>
<view class="rooms">
<view class="room" v-for="room in floor.products" :key="room.id">{{ room.name }}
</view>
</view>
</view>
</pure-elevator-floor>
</pure-elevator>
</template>
<script setup>
import { ref } from "vue";
import { onReady } from "@dcloudio/uni-app";
// ####################################################################################################
// 基础使用
const list = ref([]);
const tabValue = ref(2);
// 初始化数据
onReady(() => {
initList();
});
// 左侧标签点击事件
function handleTabClick(item) {
// 更新对应下标
tabValue.value = item.id;
}
// 初始化数据
function initList() {
list.value = [
{
id: 1,
name: "手机数码",
products: [
{ id: 1, name: "iPhone 14 Pro Max" },
{ id: 2, name: "华为 Mate 50" },
{ id: 3, name: "小米 13 Ultra" },
{ id: 4, name: "OPPO Find X6" },
{ id: 5, name: "vivo X90 Pro" },
{ id: 6, name: "三星 Galaxy S23" },
{ id: 7, name: "一加 11" },
{ id: 8, name: "荣耀 Magic5" },
{ id: 9, name: "红米 K60" },
{ id: 10, name: "realme GT Neo5" },
{ id: 11, name: "魅族 20" },
{ id: 12, name: "努比亚 Z50" },
{ id: 13, name: "索尼 Xperia 1 V" },
{ id: 14, name: "黑鲨 5 Pro" },
{ id: 15, name: "联想拯救者 Y90" },
{ id: 16, name: "华硕 ROG Phone 6" },
{ id: 17, name: "Google Pixel 7" },
{ id: 18, name: "诺基亚 X30" },
{ id: 19, name: "摩托罗拉 Edge 40" },
{ id: 20, name: "中兴 Axon 40 Ultra" }
]
},
// ...
];
}
// 左侧标签切换事件
// 主要用于自定义 tabs 用来切换选中项
function handleTabChange(value) {
// 更新对应下标
tabValue.value = value;
}
</script>
异步加载数据
- 异步加载数据示例。
vue
<template>
<pure-elevator
:list="asyncList"
:value="asyncListTabValue"
@tabClick="handleAsyncListTabClick"
@tabChange="handleAsyncListTabChange"
@scrolltolower="handleAsyncListScrollToLower"
>
<!-- 在京东和QQ小程序中,需要使用view标签包裹内容,不要给 view 添加任何内外边距,否则会滚动不准确 -->
<view>
<pure-elevator-floor
v-for="floor in asyncList"
:key="floor.id"
:value="floor.id"
:floor="floor"
>
<view class="floor" v-if="floor.products?.length">
<view class="title">{{ floor.name }}</view>
<view class="rooms">
<view class="room" v-for="room in floor.products" :key="room.id">{{ room.name }}
</view>
</view>
</view>
</pure-elevator-floor>
<!-- 加载数据的状态提示信息放到 Footer 组件中 -->
<pure-elevator-footer>
<view class="loamore">
<pure-loadmore :status="asyncListLoadMoreStatus"></pure-loadmore>
</view>
</pure-elevator-footer>
</view>
</pure-elevator>
</template>
<script setup>
import { ref } from "vue";
import { onReady } from "@dcloudio/uni-app";
// ####################################################################################################
// 异步加载数据演示
const asyncList = ref([]);
const asyncListTabValue = ref(2);
const asyncListLoadMoreStatus = ref("more");
const toUpper = ref(false);
// 初始化数据
onReady(() => {
// 先初始化标签和默认激活项数据
initAsyncList();
});
// 始化标签和默认激活项数据
function initAsyncList() {
let _asyncList = [];
for (let i = 0; i < _list.length; i++) {
_asyncList.push({
id: i,
name: _list[i].name,
products: []
});
if (i === asyncListTabValue.value) {
_asyncList[i].products = _list[i].products;
}
}
asyncList.value = _asyncList;
}
// 左侧标签点击事件
function handleAsyncListTabClick(tab) {
// loading 一下
uni.showLoading({
title: "加载中...",
mask: true
});
// 模拟异步加载数据
setTimeout(() => {
// 隐藏 loading
uni.hideLoading();
// 找到下标
const index = asyncList.value.findIndex((item) => tab.id === item.id);
// 设置数据
// 只是简单演示,并没有判断数据是否加载过等判断
asyncList.value[index].products = _list[index].products;
// 更新绑定值
asyncListTabValue.value = tab.id;
}, 2500);
}
// 滚动切换下标事件
// newValue: 新的值
function handleAsyncListTabChange(newValue) {
// 在这里实时更新用户滚动后左侧激活项的最新值
asyncListTabValue.value = newValue;
}
// 上拉加载
function handleAsyncListScrollToLower() {
// 没有更多了
if (asyncListLoadMoreStatus.value === "nomore" || asyncListLoadMoreStatus.value === 'loading') return;
// 更新状态
asyncListLoadMoreStatus.value = "loading";
// 模拟异步加载数据
setTimeout(() => {
// 找到下标
const index = asyncList.value.findIndex((item) => asyncListTabValue.value === item.id);
// 设置数据
// 只是简单演示,并没有判断数据是否加载过等判断
asyncList.value[index + 1].products = _list[index + 1].products;
// 更新激活项的值
// 在这里更新值,会将新的激活项对应内容滚动到最顶部
// 如果不更新,只会追加数据,不会滚动,根据个人喜好决定是否更新
if (toUpper.value) asyncListTabValue.value = asyncList.value[index + 1].id;
// 更新加载状态
if (index + 1 >= _list.length) {
asyncListLoadMoreStatus.value = "nomore";
} else {
asyncListLoadMoreStatus.value = "more";
}
}, 2500);
}
</script>
二级分类
- 二级分类使用演示。
提示
抖音小程序和飞书小程序不支持二级分类。 这是因为组件套组件时 provide 和 inject 会失效。 抖音和飞书的老问题了,至今还不修复~~~
vue
<template>
<pure-elevator
:list="subList"
:value="subListFirstTabValue"
:subValue="subListSecondTabValue"
subListKey="products"
@tabClick="handleSubListTabClick"
@tabChange="handleSubListTabChange"
@subTabChange="handleSubListSubTabChange"
>
<pure-elevator-floor
v-for="floor in subList"
:key="floor.id"
:value="floor.id"
:floor="floor"
>
<!-- Floor Header -->
<pure-elevator-header :floorValue="floor.id">
<view class="floor-tabs">
<!-- 同样使用 pure-tabs 组件实现的子分类 -->
<pure-tabs :value="subListSecondTabValue" @tabClick="handleSubListSubTabClick">
<pure-tabs-item
v-for="(subTab, subTabIndex) in floor.products"
:key="subTab.id"
:value="subTab.id"
:item="subTab"
:disabled="subTab.disabled"
>
<text class="subtab">{{ subTab.name }}</text>
</pure-tabs-item>
</pure-tabs>
</view>
</pure-elevator-header>
<!-- Groups -->
<pure-elevator-group
v-for="group in floor.products"
:key="group.id"
:value="group.id"
:group="group"
:floorValue="floor.id"
>
<!-- 装修分组标题 -->
<view class="group-title">{{ group.name }}</view>
<!-- 装修房间 -->
<view class="group-rooms">
<view class="group-room" v-for="room in group.goods" :key="room.id">{{room.name }}</view>
</view>
</pure-elevator-group>
</pure-elevator-floor>
</pure-elevator>
</template>
<script setup>
import { ref } from "vue";
import { onReady } from "@dcloudio/uni-app";
// ####################################################################################################
// 二级分类使用
const PureElevatorRef = ref(); // 定义一个组件 ref
const subList = ref([]);
const subListFirstTabValue = ref(1);
const subListSecondTabValue = ref(1); // 初始化所有子选项卡的下标
// 初始化数据
onReady(() => {
initSubList();
});
// 初始化数据
function initSubList() {
const _list = [];
for (let i = 0; i < 18; i++) {
const item = {
id: i + 1,
name: `分类${i + 1}`,
products: []
}
const jLength = 6;
for (let j = 0; j < jLength; j++) {
const product = {
id: `${i + 1} _ ${j + 1}`,
name: `#分类${i + 1}#子类${j + 1}`,
goods: []
}
for (let k = 0; k < 5; k++) {
const child = {
id: `${i + 1} _ ${j + 1}_${k + 1}`,
name: `#分类${i + 1}#子类${j + 1}#商品${k + 1}`
}
product.goods.push(child);
}
item.products.push(product);
}
_list.push(item);
}
subList.value = _list;
}
// 一级菜单点击事件
function handleSubListTabClick(item) {
subListFirstTabValue.value = item.id;
}
// 二级菜单点击事件
function handleSubListSubTabClick(item) {
subListSecondTabValue.value = item.id;
}
// 一级分类的值更新事件
function handleSubListTabChange(value) {
subListFirstTabValue.value = value;
}
// 子分类的值更新事件
function handleSubListSubTabChange(value) {
subListSecondTabValue.value = value;
}
</script>
Props
pure-elevator
属性名 | 说明 | 类型 | 默认值 | 可选值 | 版本 |
---|---|---|---|---|---|
list | 数据列表 | Array | [] | - | +1.0.0 |
value | 激活项的值,注意:需要和列表对应字段值的类型相同 | [Number, String] | null | - | +1.0.0 |
valueKey | value 字段名 | String | id | - | +1.0.0 |
nameKey | 显示文本字段的字段名 | String | id | - | +1.0.0 |
subValue | 子类激活项的值,重要提示: 需保证唯一性,不能有重复值 | [Number, String] | null | - | +1.0.0 |
subValueKey | subValue 字段名 | String | id | - | +1.0.0 |
subListKey | 子列表的字段名 | String | children | - | +1.0.0 |
scrollTop | 点击切换时楼层滚动到距离滚动容器顶部的距离,整数值表示 px ,小数值表示相对于滚动容器高度的比例 | Number | 0 | - | +1.0.0 |
offsetTop | 楼层距离滚动容器顶部多少距离更新选中项,整数值表示 px ,小数值表示相对于滚动容器高度的比例 | Number | 0 | - | +1.0.0 |
subScrollTop | 分组距离滚动容器顶部多少距离更新选中项,整数值表示 px ,小数值表示相对于滚动容器高度的比例 | Number | 0 | - | +1.0.0 |
subOffsetTop | 点击切换时分组滚动到距离滚动容器顶部的距离,整数值表示 px ,小数值表示相对于滚动容器高度的比例 | Number | 0 | - | +1.0.0 |
animation | 是否使用滚动过渡动画 | Boolean | false | - | +1.0.0 |
showScrollbar | 是否显示滚动条 | Boolean | false | - | +1.0.0 |
upperThreshold | 距顶部/左边多远时(单位px ),触发 scrolltoupper 事件,实测快手小程序 scroll-view 无法触发此事件,可能时快手的BUG | [Number, String] | 50 | - | +1.0.0 |
lowerThreshold | 距底部/右边多远时(单位px ),触发 scrolltolower 事件,实测快手小程序 scroll-view 无法触发此事件,不是组件问题,但时用代码模拟实现了该事件 | [Number, String] | 50 | - | +1.0.0 |
refresherEnabled | 开启自定义下拉刷新 | Boolean | false | - | +1.0.0 |
refresherThreshold | 设置自定义下拉刷新阈值 | Number | 45 | - | +1.0.0 |
refresherDefaultStyle | 设置自定义下拉刷新默认样式,支持设置 black ,white ,none ,none 表示不使用默认样式 | String | black | - | +1.0.0 |
refresherBackground | 设置自定义下拉刷新区域背景颜色 | String | #FFF | - | +1.0.0 |
refresherTriggered | 设置当前下拉刷新状态,true 表示下拉刷新已经被触发,false 表示下拉刷新未被触发 | Boolean | false | - | +1.0.0 |
提示
scroll-view
组件的兼容性参考官方地址
pure-elevator-floor
属性名 | 说明 | 类型 | 默认值 | 可选值 | 版本 |
---|---|---|---|---|---|
value | 值,对应 pure-elevator 的 value | [Number, String] | null | - | +1.0.0 |
floor | 楼层数据,对应 pure-elevator 的 list 的列表 item | [Array, Object] | [] | - | +1.0.0 |
pure-elevator-group
属性名 | 说明 | 类型 | 默认值 | 可选值 | 版本 |
---|---|---|---|---|---|
value | 值,唯一标识 | [Number, String] | null | - | +1.0.0 |
group | 分组数据 | [Array, Object] | [] | - | +1.0.0 |
floorValue | 分组所在楼层的值 | [Number, String] | null | - | +1.0.0 |
pure-elevator-header
属性名 | 说明 | 类型 | 默认值 | 可选值 | 版本 |
---|---|---|---|---|---|
floorValue | 所在楼层的值 | [Number, String] | null | - | +1.0.0 |
sticky | 是否吸附到顶部 | Boolean | true | - | +1.0.0 |
Event
pure-elevator
事件名 | 说明 | 回调参数 | 版本 |
---|---|---|---|
tabClick | 左侧选项卡点击事件 | item: 选项卡数据 | +1.0.0 |
tabChange | 左侧选项卡切换事件 | value: 选项卡的值 | +1.0.0 |
subTabChange | 子选项卡切换事件 | value: 选项卡的值 | +1.0.0 |
scrollUpper | 下拉触顶事件 | - | +1.0.0 |
scrollLower | 上拉触底事件 | - | +1.0.0 |
refresherPulling | 自定义下拉刷新控件被下拉 | - | +1.0.0 |
refresherRefresh | 自定义下拉刷新被触发 | - | +1.0.0 |
refresherRestore | 自定义下拉刷新被复位 | - | +1.0.0 |
refresherAbort | 自定义下拉刷新被中止 | - | +1.0.0 |
Slots
pure-elevator
名称 | 说明 | 参数 | 版本 |
---|---|---|---|
tabs | 左侧选项卡,可以在此处使用 pure-tabs-item 组件自定义选项卡 | - | +1.0.0 |
default | 默认,右侧区域 | - | +1.0.0 |
pure-elevator-floor
名称 | 说明 | 参数 | 版本 |
---|---|---|---|
default | 默认,楼层内容 | - | +1.0.0 |
pure-elevator-header
名称 | 说明 | 参数 | 版本 |
---|---|---|---|
default | 默认,楼层标题 | - | +1.0.0 |
pure-elevator-group
名称 | 说明 | 参数 | 版本 |
---|---|---|---|
default | 默认,分组内容 | - | +1.0.0 |
pure-elevator-footer
名称 | 说明 | 参数 | 版本 |
---|---|---|---|
default | 默认,右侧最底部内容 | - | +1.0.0 |