Vue3问题:如何实现级联菜单的数据懒加载?

news2024/11/27 15:50:06

前端功能问题系列文章,点击上方合集↑

序言

大家好,我是大澈!

本文约3100+字,整篇阅读大约需要5分钟。

本文主要内容分三部分,第一部分是需求分析,第二部分是实现步骤,第三部分是问题详解。

如果您只需要解决问题,请阅读第一、二部分即可。

如果您有更多时间,进一步学习问题相关知识点,请阅读至第三部分。

1. 需求分析

实现级联菜单效果,点击一级菜单某一项,就会加载出对应的二级菜单内容,点击二级菜单某一项,就会加载出对应的三级菜单内容,以此类推,最后一级为五级菜单。

对于加载而言,必须是懒加载效果,即点击菜单某一项时,才会真正去请求加载对应的下一级菜单内容。

对于菜单最后一级内容,要插入一个输入框,在输入框内,用户可以任意输入版本号,并且要求输入框不可被选中。

当然,我们的正题是数据的懒加载,级联菜单中插入不可被选中的输入框实现算是附加内容了。

图片

图片

2. 实现步骤

2.1 为什么要使用数据懒加载

在项目中,我们使用数据的懒加载,会有如下好处

  • 提升用户体验

  • 减少初始加载时间

  • 减轻网络资源的消耗

了解了这些好处之后,再就是要了解数据懒加载的应用场景。

这部分比较有用,所以多叙述一些。

数据懒加载在以下场景中特别有用:

  • 长列表或分页数据:当你有一个包含大量数据的列表或分页功能时,可以使用数据懒加载来延迟加载列表项或分页数据。只有当用户滚动到可见范围时才加载新的数据,从而提高初始加载速度和响应性能。

  • 图片或媒体资源:对于包含大量图片或媒体资源的页面,可以使用数据懒加载来延迟加载这些资源。只有当图片或媒体元素进入视口时才进行加载,从而减少初始加载时间和网络资源的消耗。

  • 条件性加载:当一些数据或组件只在特定条件下才需要显示或使用时,可以使用数据懒加载。根据条件动态加载数据或组件,避免不必要的加载和资源占用。

  • 路由级别的懒加载:在Vue的路由中,可以使用懒加载来按需加载路由组件。只有当用户访问某个路由时才进行组件的加载,提高初始加载速度和路由切换的性能。

  • 异步加载模块:对于大型的Vue项目,可以使用数据懒加载来异步加载模块,减少初始加载时间。将模块分割成小块,并在需要时按需加载,提高应用的性能和可维护性。

上述场景在此部分只做简单描述,如果你有空余时间,各个场景具体代码实例请见第三部分总结。

我们这次的需求实现,就是符合第1条场景。

2.2 数据懒加载代码实例

当选中某一级时,动态加载该级下的选项。

通过lazy开启动态加载,并通过lazyload方法来设置加载数据源。

  • lazyload方法有两个参数,第一个参数node为当前点击的节点,第二个resolve为数据加载完成的回调(必须调用)。

  • node可以解构出level参数,它从0开始计数,指明当前点击节点的层级。

  • 为数据对象添加leaf属性,是为了指明哪一级的对象是叶子节点。

模板代码:

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

2.3 插入输入框代码实例

通过插槽和条件判断,在级联面板中插入输入框,其中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>

3. 问题详解

3.1 关于CascaderProps配置项的参数一览

图片

3.2 懒加载各个场景代码实例总结

长列表或分页数据懒加载:

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

结语

建立这个平台的初衷:

  • 打造一个仅包含前端问题的问答平台,让大家高效搜索处理同样问题。

  • 通过不断积累问题,一起练习逻辑思维,并顺便学习相关的知识点。

  • 遇到难题,遇到有共鸣的问题,一起讨论,一起沉淀,一起成长。

感谢关注微信公众号:“程序员大澈”,然后加入问答群,让我们一起解决实现所有BUG!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1160542.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

太阳能技术相关

0 Preface/Foreword Energy Harvesting&#xff1a;猎能技术 太阳能光电/光伏&#xff1a;PhotoVoltaic 热电&#xff1a;Thermoelectric LoRa Alliance&#xff1a;支持物联网&#xff08;IoT&#xff09;低功耗广域网&#xff08;LPWAN&#xff09;开放LoRaWAN标准的全球…

如何提高滚柱导轨的精度?

滚柱导轨是一种高精度的传动零部件&#xff0c;起导向作用&#xff0c;如果滚柱导轨的精度受损&#xff0c;则无法达到预期的使用效果&#xff0c;那么&#xff0c;我们应该如何提高滚柱导轨的精度呢&#xff1f; 1、优化材料选型&#xff1a;选用高质量的材料作为制造导轨的原…

分析每月开销曲线图,合理记账助您掌控支出趋势!

亲爱的用户&#xff0c;您是否曾经为不知道自己每月开销的情况而感到困惑&#xff1f;现在&#xff0c;我们为您提供了一款智能记账工具&#xff0c;通过分析每月开销曲线图&#xff0c;帮助您合理记账&#xff0c;掌控支出趋势&#xff01; 首先&#xff0c;第一步&#xff0…

本地仓库转为git仓库推送到gitee

通常有两种获取 Git 项目仓库的方式&#xff1a; 方式一&#xff1a;将尚未进行版本控制的本地目录转换为 Git 仓库&#xff1b; 方式二&#xff1a;从其它服务器 克隆 一个已存在的 Git 仓库。 两种方式都会在你的本地机器上得到一个工作就绪的 Git 仓库。 方式一&#xff1a…

10.31同步异步清零,阻塞与非阻塞例子,ROM,RAM,边沿检测实现

同步与异步清零 就是当复位信号发生变化&#xff0c;从1到0时立刻进行复位&#xff0c;negedge触发模块&#xff0c;即可工作&#xff1b;但如果到0后一直没有发生变化&#xff0c;即保持为0&#xff0c;那么就是在不断的时钟上升沿触发电路&#xff0c;但是都会因为复位信号为…

学习c++的第二天

目录 数据类型 基本数据类型 typedef 声明 枚举类型 类型转换 变量类型 变量定义 变量声明 左值&#xff08;Lvalues&#xff09;和右值&#xff08;Rvalues&#xff09; 变量作用域 数据类型 基本数据类型 C 为程序员提供了种类丰富的内置数据类型和用户自定义的数…

影视企业有哪些方式将视频文件快速海外跨国传输国内?

影视行业是一个高度国际化的行业&#xff0c;影视企业在跨国合作、制作、发行等方面有着强烈的需求。然而&#xff0c;影视企业在跨国文件传输方面也面临着诸多的问题和难题。视频文件通常具有较大的文件大小、多样的文件格式、高要求的文件质量等特点&#xff0c;这些特点使得…

WSL安装Ubuntu

先安装wsl2 安装Ubuntu 打开windows商店&#xff0c;搜索对应版本的Ubuntu&#xff0c;点击获取进度跑完后&#xff0c;点击打开&#xff0c;就可以完成安装 删除Ubuntu版本 wsl --unregister Ubuntu-18.04安装位置迁移 正常情况下Ubuntu是被安装在C盘&#xff0c;我们需要…

Java架构师数学与经济管理

目录 1 导学2 最小生成树3 最短路径4 网络与最大流量5 线性规划6 动态规划6.1 伏格尔法7 博弈论7.1 状态转移矩阵7.2 排队论8 决策论8.1 决策树9 数学建模想学习架构师构建流程请跳转:Java架构师系统架构设计 1 导学

如何选择合适的进口跨境商城源码?揭秘电商平台的成功之道

了解进口跨境电商平台源码的重要性 在进口跨境电商行业的兴起中&#xff0c;选择合适的商城源码是创业者成功的关键之一。进口跨境商城源码可提供网站架构、功能模块、支付系统、物流管理等基础构建&#xff0c;帮助企业快速搭建属于自己的商城平台。然而&#xff0c;在众多商城…

C语言实现 1.在一个二维数组中形成 n 阶矩阵,2.去掉靠边元素,生成新的 n-2 阶矩阵;3.求矩阵主对角线下元素之和:4.以方阵形式输出数组。

矩阵形式&#xff1a; 1 1 1 1 1 2 1 1 1 1 3 2 1 1 1 4 3 2 1 1 5 4 3 2 1 完整代码&#xff1a; /*编写以下函数 1&#xff0e;在一个二维数组中形成如以下形式的 n 阶矩阵&#xff1a; 1 1 1 1 1 2 1 1 1 1 3 2 1 1 1 4 3 2 1 1 5 4 3 2 1 2&#xff0e;去掉…

选择绿色壁炉:环保温暖你的家

壁炉的绿色选择是我们现代生活中越来越重要的话题。不仅为了保暖&#xff0c;还要考虑对环境的影响。在选择壁炉时&#xff0c;有一些绿色、环保的选项可以考虑&#xff0c;而且它们也能提供温馨的家居氛围。 嵌入式酒精壁炉&#xff1a;生物乙醇是一种环保的燃料&#xff0c;它…

什么是自动化测试框架?常用的自动化测试框架有哪些?

无论是在自动化测试实践&#xff0c;还是日常交流中&#xff0c;经常听到一个词&#xff1a;框架。之前学习自动化测试的过程中&#xff0c;一直对“框架”这个词知其然不知其所以然。 最近看了很多自动化相关的资料&#xff0c;加上自己的一些实践&#xff0c;算是对“框架”…

【C++】 常对象与常函数

常函数&#xff1a; 成员函数后加const后我们称为这个函数为常函数常函数内不可以修改成员属性成员属性声明时加关键字mutable后&#xff0c;在常函数中依然可以修改 常对象&#xff1a; 声明对象前加const称该对象为常对象常对象只能调用常函数 一、this指针本质 this指针…

Vscode使用国内镜像源下载,秒下

镜像源 国内镜像地址&#xff1a;https://vscode.cdn.azure.cn 使用方法&#xff1a;很简单&#xff0c;只需要在官网选择自己需要的版本&#xff0c;点击下载&#xff0c;在下载的路径中将我们的镜像源替换上去即可 1.81.1版本下载链接 https://vscode.cdn.azure.cn/stable/…

【SpringMVC篇】5种类型参数传递json数据传参

&#x1f38a;专栏【SpringMVC】 &#x1f354;喜欢的诗句&#xff1a;天行健&#xff0c;君子以自强不息。 &#x1f386;音乐分享【如愿】 &#x1f384;欢迎并且感谢大家指出小吉的问题&#x1f970; 文章目录 &#x1f33a;普通参数&#x1f33a;POJO参数&#x1f33a;嵌套…

Elemen table布局错乱解决方案

示例 解决方案 方案一 <el-table ref"mainTable"></el-table>、、、// 接口请求触发重新布局方法this.$nextTick(() > {this.$refs.mainTable.doLayout();});方案二 <el-tablestyle"width: 100%;max-height:400px;overflow-y: auto;"&g…

麒麟操作系统安装oracle 19c报错问题汇总

麒麟操作系统版本: [roothis-dsg lib64]# uname -a Linux his-dsg 4.19.90-24.4.v2101.ky10.x86_64 #1 SMP Mon May 24 12:14:55 CST 2021 x86_64 x86_64 x86_64 GNU/Linux 安装之前,建议先配置好ORACLE的环境变量,再执行一下bash_profile环境变量 1.xstart无法打开报错x11拒…

使用ant design pro出现面包屑导航和标题消失的问题

前端时间&#xff0c;我用ant design pro搭建了一个后台权限管理的项目模板&#xff0c;里面用到了PageContainer组件&#xff0c;默认会显示面包屑导航和标题&#xff0c;如图所示 后来&#xff0c;我把这个项目模板用于另外一个项目的前端页面&#xff0c;把整个项目的文件夹…

【java】命令行,包

文件夹情况&#xff1a; HelloWorld.java package com.demo; public class HelloWorld{public static void print(){System.out.println("HelloWorld!");}public static void main(String[] args){print();} } import.java import com.demo.HelloWorld; public cla…