uniapp 树状数据无限极 进行展示并选择

两个文件 demo.vue -- olylis-cascader.vue

提示:可以对照接口返回的参数名来修改,把value=id,label=name

demo.vue

html 复制代码
<template>
    <olylis-cascader :options="treeData" :value="selectedValue" @change="handleChange" :is-show-nav="false">
        <!-- 可自定义节点 -->
<!--        <template v-slot="{ data }">-->
<!--            <view>-->
<!--                {{ data.label }} : {{ data.value }}-->
<!--            </view>-->
<!--        </template>-->
    </olylis-cascader>
</template>

<script>
	//	第二个文件的地址,自己修改
    import olylisCascader from './olylis-cascader'

    export default {
        name: 'demo',
        components: {olylisCascader},
        data() {
            return {
                selectedValue: [],
                treeData: [
                    {
                        value: 1,
                        label: '一级 1',
                        children: [{
                            value: 11,
                            label: '二级 1-1',
                            children: [{
                                value: 111,
                                label: '三级 1-1-1'
                            }]
                        }],
                    }, {
                        value: 2,
                        label: '一级 2',
                        children: [{
                            value: 21,
                            label: '二级 2-1',
                            children: [{
                                value: 211,
                                label: '三级 2-1-1'
                            }]
                        }, {
                            value: 22,
                            label: '二级 2-2',
                            children: [{
                                value: 221,
                                label: '三级 2-2-1'
                            }]
                        }]
                    }, {
                        value: 3,
                        label: '一级 3',
                        children: [{
                            value: 31,
                            label: '二级 3-1',
                            children: [{
                                value: 311,
                                label: '三级 3-1-1'
                            }]
                        }, {
                            value: 32,
                            label: '二级 3-2',
                            children: [{
                                value: 321,
                                label: '三级 3-2-1'
                            }]
                        }]
                    }
                ]
            }
        },
        //现在这里写死,可以自己加个接口换数据
        methods: {
        	// 每次点击都会返回点击的内容
            handleChange(selectedValue, clickItem) {
                console.log('handleChange', selectedValue, clickItem)
                this.selectedValue = selectedValue
            }
        }
    }
</script>

<style scoped>

</style>

olylis-cascader.vue

这里我标下可能需要替换参数名的地方,如果是需要id,name 之类的

html代码应该都能看懂,知道那些替换,我重点是下面的方法里是标注下

html 复制代码
<template>
	<view ref="cascaderRef" class="cascader">
		<view v-if="isShowNav" class="bread-crumb clearfix">
			<view class="bread-crumb-root">当前:</view>                                   
			<view class="bread-crumb-item" v-for="(item, index) in breadCrumbList" :key="item.value" >
				<text class="bread-crumb-text" @click="clickNav(item, index)">{{item.label}}</text>
				<view v-if="index < breadCrumbList.length - 1" class="bread-crumb-icon">></view>
			</view>
		</view>
		<view class="cascader-content">
			<scroll-view scroll-x scroll-with-animation :scroll-left="scrollLeft" style="height:100%;">
				<view class="options-row clearfix" :style="rowStyle">
						<view class="options-column" v-for="(opitons, columnIndex) in optionsList" :key="columnIndex" :style="columnStyle">
						<scroll-view scroll-y style="height:100%">
							<view class="options-item" v-for="item in opitons" :class="{'active': selectedValue[columnIndex] === item.value}" :key="item.value" @click="clickItem(item, columnIndex)">
								<slot :data="item">{{item.label}}</slot>
							</view>
						</scroll-view>
					</view>
				</view>
			</scroll-view>
		</view>
	</view>
</template>

<script>
	function getStyleString (styleObject) {
		return Object.keys(styleObject).map(propName => (propName + ':' + styleObject[propName] + ';')).join('')
	}
	
	export default {
		name: 'cascader',
		props: {
			columnWidth: {
				type: Number,
				default: null
			},
			value: {
				type: Array,
				default() {return []}
			},
			options: {
				type: Array,
				default() {return []}
			},
			isShowNav: {
				type: Boolean,
				default: true
			}
		},
		data() {
			return {
				WIDTH: 300,
				COLUMN_WIDTH: 150,
				selectedValue: [],
				optionsList: []
			}
		},
		computed: {
			breadCrumbList() {                                                                    // id
				return this.selectedValue.map((item, i) => this.optionsList[i].find(option => option.value === item))
			},
			rowStyle() {
				return getStyleString({
					width: this.COLUMN_WIDTH * (Math.max(2, this.optionsList.length)) + 'px'
				})
			},
			columnStyle() {
				return getStyleString({
					width: this.COLUMN_WIDTH + 'px'
				})
			},
			scrollLeft() {
				return Math.max(0, this.COLUMN_WIDTH * (this.optionsList.length - 2))
			}
		},
		watch: {
			value(val) {
				this.handleValue(val)
			},
			options(val) {
				this.handleValue(this.value)
			}
		},
		created() {
			this.handleValue(this.value)
		},
		mounted() {
			this.init()
		},
		methods: {
			init() {
				const query = uni.createSelectorQuery().in(this);
				query.select('.cascader').boundingClientRect(data => {
					this.WIDTH = data.width ? data.width : 150
					this.COLUMN_WIDTH = this.WIDTH / 2
				}).exec();
			},
			handleValue(val) {
				this.selectedValue = []
				this.optionsList = this.getOptionsList(val, this.options)
				this.selectedValue = val
			},
			getOptionsList(values, options, currentList = []) {
				if (!options || options.length === 0) return currentList
				currentList.push(options)
				if (values.length === 0) return currentList
				                                    // id
				const next = options.find(item => item.value === values[0])
				const nextValue = values.slice(1)
				const nextOptions = next.children
				return this.getOptionsList(nextValue, nextOptions, currentList)
			},
			clickNav(item, index) {
				this.clickItem(item, index)
			},
			clickItem(item, columnIndex) {
				const selectedValue = this.selectedValue.slice(0, columnIndex)
				const optionsList = this.optionsList.slice(0, columnIndex + 1)
				                                    // id
				selectedValue.splice(columnIndex, 1, item.value)
				this.selectedValue = selectedValue
				if (item.children) optionsList.splice(columnIndex + 1, 1, item.children)
				this.optionsList = optionsList
				this.$emit('change', selectedValue, item)
			}
		}
	}
</script>

<style lang="scss" scoped>
	.clearfix::after {
		content: "";
		display: block;
		height: 0;
		clear: both;
		visibility: hidden;
	}

	.cascader {
		height: 100%;
		
		.bread-crumb {
			height: 30px;
			line-height: 30px;
			border-bottom: 1px solid #d8d8d8;
			padding: 0 10px;
			font-size: 12px;
			
			.bread-crumb-root {
				float: left;
			}
			
			.bread-crumb-item {
				float: left;
			}
			
			.bread-crumb-text {
				color: #0083FF;
			}
			
			.bread-crumb-icon {
				display: inline-block;
				padding: 0 5px;
			}
		}
		
		.cascader-content {
			height: calc(100% - 30px);
		}
		
		.options-row {
			height: 100%;
		}
		
		.options-column {
			float: left;
			height: 100%;
			
			box-sizing: border-box;
			
			&:not(:last-child) {
				border-right: 1px solid #d8d8d8;
			}
		}
		
		.options-item {
			padding: 10px 10px;
			
			&.active {
				color: #ff6600;
			}
		}
	}
</style>
相关推荐
kyriewen3 分钟前
看了微软几万人用AI编程的数据——效率涨24%的代价没人提
前端·ai编程·claude
2601_963771375 分钟前
How to Scale Your WordPress Store Traffic in 2026
前端·php·plugin
亿元程序员14 分钟前
老板说我的3D箭头游戏用来做试玩太普通了,没人想玩,让我变点花样...
前端
李伟_Li慢慢1 小时前
01-threejs架构原理-课程简介
前端·three.js
_瑞2 小时前
深入理解 iOS 渲染原理
前端·ios
IT_陈寒2 小时前
SpringBoot自动配置失灵?你可能忘了这个关键注解
前端·人工智能·后端
iCOD3R3 小时前
Skill - kill-ai-slop 解决“AI 味”样式
前端·css·ai编程
shuaijie05183 小时前
强制修改调用接口的api地址。
javascript·vue.js·ecmascript
JerrySir3 小时前
恶意 npm 包只活了 17 分钟:技术面试里,为什么“升级依赖”还不算止血?
javascript·安全
皮音3 小时前
Skill 在项目中的实践 —— 从 Agent 困境到 Skill 工程化
前端