大家好,我是大澈!
本文约3100+字,整篇阅读大约需要5分钟。
本文主要内容分三部分,第一部分是需求分析,第二部分是实现步骤,第三部分是问题详解。
如果您只需要解决问题,请阅读第一、二部分即可。
如果您有更多时间,进一步学习问题相关知识点,请阅读至第三部分。
实现级联菜单效果,点击一级菜单某一项,就会加载出对应的二级菜单内容,点击二级菜单某一项,就会加载出对应的三级菜单内容,以此类推,最后一级为五级菜单。
对于加载而言,必须是懒加载效果,即点击菜单某一项时,才会真正去请求加载对应的下一级菜单内容。
对于菜单最后一级内容,要插入一个输入框,在输入框内,用户可以任意输入版本号,并且要求输入框不可被选中。
当然,我们的正题是数据的懒加载,级联菜单中插入不可被选中的输入框实现算是附加内容了。
在项目中,我们使用数据的懒加载,会有如下好处:
了解了这些好处之后,再就是要了解数据懒加载的应用场景。
这部分比较有用,所以多叙述一些。
数据懒加载在以下场景中特别有用:
上述场景在此部分只做简单描述,如果你有空余时间,各个场景具体代码实例请见第三部分总结。
我们这次的需求实现,就是符合第1条场景。
当选中某一级时,动态加载该级下的选项。
通过lazy开启动态加载,并通过lazyload方法来设置加载数据源。
模板代码:
<template><!-- 级联面板 --><el-cascader-panel :props="props"></el-cascader-panel></template>
逻辑代码:
<script setup>// 级联面板配置项const props = reactive({// 开启懒加载lazy: true,// 懒加载加载数据源方法async lazyLoad(node, resolve) {const { level } = node;// 已经有数据了,不需要重复请求了if (node.children && node.children.length > 0) return;// 模拟掉接口setTimeout(() => {let result;switch (level) {case 0: // 一级目录result = [{value: "0",label: "行内转账-手机号",children: []},{value: "1",label: "行内转账-银行账号",children: []},{value: "2",label: "汇款到当地银行",children: []},{value: "3",label: "汇款到钱包",children: []},{value: "4",label: "转账到CUPD",children: []}];break;case 1: //二级目录// 省略此处代码...break;case 2: //三级目录// 省略此处代码...break;case 3: //四级目录// 省略此处代码...break;case 4: // 五级目录result = [{value: "最低系统版本",label: "最低系统版本要求"},{value: "0",label: "不启用"},{value: "1",label: "内测"},{value: "2",label: "上线"}];// 设置五级菜单为叶子节点,无子节点result.forEach((item) => {item.leaf = level >= 4;});break;default:result = [];break;}resolve(result);}, 1000);}});</script>
通过插槽和条件判断,在级联面板中插入输入框,其中data.label为节点对象的名称。
通过@click.stop阻止事件冒泡、宽度为父元素的100%、以及清除级联面板组件一些默认样式,实现了输入框不可被选中的效果。
模版代码:
<template><!-- 级联面板 --><el-cascader-panel :props="props"><template #default="{ data }"><!-- 输入框节点对象 --><div v-if="data.label == '最低系统版本要求'" @click.stop style="width: 100%"><div>{{ data.label }}</div><div class="searchText"><el-input v-model="searchText" :placeholder="'最低系统版本要求'"></el-input></div></div><div v-else><div>{{ data.label }}</div></div></template></el-cascader-panel></template>
样式代码:
<style lang="scss" scope>.el-cascader-panel.is-bordered {border: none;}.el-cascader-menu:last-child .el-cascader-node:nth-of-type(1):has(.searchText) {margin-bottom: 30px;padding: 0;&:hover,&:focus {background: #fff;}}.el-cascader-menu__list {padding: 20px 0;}</style>
长列表或分页数据懒加载:
<template><div><ul><li v-for="item in items" :key="item.id">{{ item.name }}</li><li v-if="loading">Loading...</li></ul></div></template><script>export default {data() {return {items: [],loading: false,};},mounted() {this.loadMore(); // 初始加载window.addEventListener('scroll', this.handleScroll);},methods: {loadMore() {this.loading true;// 模拟异步加载数据setTimeout(() => {const newItems = /* 请求新数据 */;this.items = this.items.concat(newItems);this.loading = false;}, 1000);},handleScroll() {const scrollPosition = window.innerHeight + window.pageYOffset;const contentHeight = document.documentElement.scrollHeight;if (scrollPosition >= contentHeight && !this.loading) {this.loadMore(); // 滚动到底部时加载更多数据}},},beforeDestroy() {window.removeEventListener('scroll', this.handleScroll);},};</script>
图片懒加载:
<template><div><img :src="placeholder" ref="image" style="display: none;"></div></template><script>export {data() {return {placeholder: require('@/assets/placeholder.png'), // 占位图};},mounted() {window.addEventListener('scroll', this.handleScroll);},methods: {handleScroll() {const imageElement = this.$refs.image;const rect = imageElement.getBoundingClientRect();if (rect.top < window.innerHeight) {const src = /* 获取图片真实地址 */;imageElement.src = src; // 加载图片window.removeEventListener('scroll', this.handleScroll); // 图片加载后移除滚动监听}},},beforeDestroy() {window.removeEventListener('scroll', this.handle);},};</script>
条件性数据懒加载:
<template><div><button @click="showData = true">显示数据</button><div v-if="showData"><!-- 显示数据的组件或内容 --></div></div></template><script>export default {data() {return {showData: false,};},};</script>
路由懒加载(基于 Vue Router):
const Home = () => import('./components/Home.vue');const About = () => import('./components/About.vue');const Contact = () => import('./components/Contact.vue');const routes = [{ path: '/home', component: Home },{ path: '/about', component: About },{ path: '/contact', component: Contact },];const router = new VueRouter({routes,});
异步加载模块(基于 import() 动态导入语法):
<template><div><button @click="loadModule">加载模块</button><div v-if="moduleLoaded"><!-- 显示已加载的模块 --></div></div></template><script>export default {data() {return {moduleLoaded: false,};},methods: {loadModule() {import('./path/to/module.js').then((module) => {// 模块加载成功this.moduleLoaded = true;}).catch((error) => {console.error(error);});},},};</script>
本文链接:http://www.28at.com/showinfo-26-57846-0.htmlVue3问题:如何实现级联菜单的数据懒加载?
声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。邮件:2376512515@qq.com