样式可以左右滑动,可以加无数个子数据

<!-- 主页面(如 pages/member/member.vue) -->
<template>
<view class="member-page">
<!-- 顶部查询栏 -->
<view class="search-bar">
<text class="label">账号</text>
<input class="input" placeholder="请输入账号" value="DF993111" />
<button class="search-btn">查询</button>
</view>
<!-- 会员信息:整体横向滚动容器(核心) -->
<view class="scroll-container">
<!-- 会员信息卡片(宽度自适应,实现横向滑动) -->
<view class="member-card">
<!-- 会员信息标题栏 -->
<view class="section-title">会员信息</view>
<!-- 会员树:引入预编译的递归组件 -->
<view class="member-tree">
<MemberTreeItem v-for="(item, index) in memberData" :key="index" :node="item" :level="1"
@toggle="handleToggle" />
</view>
</view>
</view>
</view>
</template>
<script>
// 引入单独的递归组件(路径根据实际项目调整,components目录可直接写组件名)
import MemberTreeItem from '../../components/MemberTreeItem.vue';
export default {
components: {
MemberTreeItem // 注册组件,直接使用
},
data() {
return {
// 模拟N级会员数据(支持无限层级,可替换为接口数据)
memberData: [{
info: 'DF688278(1)[第100层][经理][无级别][审核时间]',
expanded: false,
children: [{
info: 'DF786622(2)[第101层][经理][无级别][审核时间]',
expanded: true,
children: [{
info: 'DF768677(3)[第102层][经理][无级别][审核时间]',
expanded: true,
children: [{
info: 'DF282282(4)[第103层][经理][无级别][审核时间]',
expanded: true,
children: [{
info: 'DF134414(5)[第104层][经理][无级别][审核时间]',
expanded: true,
children: [{
info: 'DF134414(6)[第104层][经理][无级别][审核时间]',
expanded: true,
children: [{
info: 'DF134414(7)[第104层][经理][无级别][审核时间]',
expanded: false,
children: []
}]
}]
}]
}]
}]
}]
},
{
info: 'DF266888(02)[第107层][经理][无级别][审核时间]',
expanded: false,
children: []
}
]
};
},
methods: {
// 处理折叠/展开切换:修改节点的expanded状态
handleToggle(node) {
node.expanded = !node.expanded;
}
}
};
</script>
<style scoped>
/* 页面全局样式 */
.member-page {
background-color: #f5f5f5;
min-height: 100vh;
padding: 20rpx;
box-sizing: border-box;
}
/* 顶部查询栏样式 */
.search-bar {
background-color: #ffffff;
display: flex;
align-items: center;
padding: 16rpx 20rpx;
border-radius: 4rpx;
margin-bottom: 20rpx;
box-shadow: 0 1rpx 3rpx rgba(0, 0, 0, 0.05);
}
.search-bar .label {
font-size: 28rpx;
color: #333333;
width: 80rpx;
}
.search-bar .input {
flex: 1;
height: 60rpx;
border: 1rpx solid #e5e5e5;
border-radius: 4rpx;
padding: 0 16rpx;
margin: 0 16rpx;
font-size: 28rpx;
color: #333;
}
.search-bar .search-btn {
background-color: #008000;
color: #ffffff;
font-size: 28rpx;
padding: 0 24rpx;
height: 60rpx;
border-radius: 4rpx;
border: none;
line-height: 60rpx;
}
/* 核心:会员信息整体横向滚动容器 */
.scroll-container {
width: 100%;
overflow-x: auto;
white-space: nowrap;
-webkit-overflow-scrolling: touch;
/* 移动端顺滑滚动 */
background-color: #fff;
border-radius: 4rpx;
box-shadow: 0 1rpx 3rpx rgba(0, 0, 0, 0.05);
}
/* 隐藏横向滚动条,优化视觉 */
.scroll-container::-webkit-scrollbar {
display: none;
}
/* 会员卡片:宽度自适应内容,最小占满屏幕 */
.member-card {
display: inline-block;
width: auto;
min-width: 100%;
background-color: #ffffff;
border-radius: 4rpx;
}
/* 会员信息标题栏 */
.section-title {
background-color: #f0f0f0;
color: #666666;
font-size: 28rpx;
padding: 16rpx 20rpx;
border-bottom: 1rpx solid #e5e5e5;
white-space: nowrap;
}
/* 会员树容器 */
.member-tree {
width: auto;
}
</style>
引入样式在components里面创建一个MemberTreeItem.vue
<!-- components/MemberTreeItem.vue 递归组件单文件 -->
<template>
<view class="member-item">
<!-- 项头部:箭头 + 会员信息 -->
<view class="item-header" @click="handleClick">
<!-- 折叠/展开箭头,层级动态缩进 -->
<view class="arrow-icon" :class="{ expanded: node.expanded }" :style="{ marginLeft: (level - 1) * 30 + 'rpx' }"></view>
<!-- 会员信息文本,不换行随整体滑动 -->
<text class="info-text">{{ node.info }}</text>
</view>
<!-- 递归渲染子项:仅展开且有子项时显示 -->
<view class="child-tree" v-if="node.expanded && node.children.length > 0">
<MemberTreeItem
v-for="(child, cIndex) in node.children"
:key="cIndex"
:node="child"
:level="level + 1"
@toggle="$emit('toggle', $event)"
/>
</view>
</view>
</template>
<script>
export default {
name: 'MemberTreeItem', // 组件名,递归调用需指定
props: {
// 会员节点数据(info/expanded/children)
node: {
type: Object,
required: true,
default: () => ({ info: '', expanded: false, children: [] })
},
// 节点层级,控制缩进
level: {
type: Number,
required: true,
default: 1
}
},
emits: ['toggle'], // 声明自定义事件,避免警告
methods: {
// 点击切换展开/收起状态,向上传递事件
handleClick() {
this.$emit('toggle', this.node);
}
}
};
</script>
<style scoped>
/* 会员项底部分割线 */
.member-item {
border-bottom: 1rpx solid #f0f0f0;
}
/* 项头部布局:弹性对齐,禁止换行 */
.item-header {
display: flex;
align-items: center;
padding: 16rpx 20rpx 16rpx 0;
cursor: pointer;
white-space: nowrap;
}
/* 折叠/展开箭头:CSS绘制,替代图片 */
.arrow-icon {
width: 24rpx;
height: 24rpx;
margin-right: 12rpx;
position: relative;
transition: transform 0.2s ease;
}
/* 未展开:右箭头 */
.arrow-icon::after {
content: '';
position: absolute;
top: 50%;
left: 50%;
transform: translate(-60%, -50%);
width: 0;
height: 0;
border-top: 6rpx solid transparent;
border-bottom: 6rpx solid transparent;
border-left: 8rpx solid #666;
}
/* 展开:下箭头(旋转动画) */
.arrow-icon.expanded::after {
transform: translate(-50%, -40%) rotate(90deg);
}
/* 会员信息文本样式 */
.info-text {
font-size: 26rpx;
color: #333333;
line-height: 1.4;
white-space: nowrap;
}
/* 子项容器 */
.child-tree {
display: block;
}
</style>