Vue3 problem: How to implement lazy loading of data in cascading menus?

A series of articles on front-end function issues, click above to collect↑

Preface

Hello everyone, I am Da Che!

This article is about 3100 + words, and it takes about 5 minutes to read the whole article.

The main content of this article is divided into three parts. The first part is demand analysis, the second part is implementation steps, and the third part is detailed explanation of the problem.

If you just need a problem solved, just read parts one and two.

If you have more time to learn more about the problem, please read to Part 3.

1. Requirements analysis

To achieve the cascading menu effect, click on an item in the first-level menu, and the corresponding second-level menu content will be loaded. Click on an item in the second-level menu, and the corresponding third-level menu content will be loaded, and so on. The last one Level is a five-level menu.

For loading, it must be a lazy loading effect, that is, when a menu item is clicked, the corresponding next-level menu content will actually be requested to be loaded.

For the last level of the menu, an input box should be inserted. In the input box, the user can enter any version number, and the input box must not be selected.

Of course, our main topic is lazy loading of data, and the implementation of inserting unselectable input boxes in the cascading menu is an additional content.

Picture

Picture

2. Implementation steps

2.1 Why use lazy loading of data

In the project, we use lazy loading of data, which will have the following benefits:

  • Improve user experience

  • Reduce initial load time

  • Reduce consumption of network resources

After understanding these benefits, you need to understand the application scenarios of lazy loading of data.

This part is more useful, so describe it in more detail.

Lazy loading of data is particularly useful in the following scenarios:

  • Long list or paginated data: When you have a list or paginated function that contains a large amount of data, you can use data lazy loading to delay the loading of list items or paginated data. New data is only loaded when the user scrolls to the visible range, thus improving initial load speed and responsiveness.

  • Images or media resources: For pages that contain a large number of images or media resources, you can use data lazy loading to delay loading of these resources. Images or media elements are loaded only when they enter the viewport, thereby reducing initial load time and consumption of network resources.

  • Conditional loading: When some data or components only need to be displayed or used under specific conditions, you can use data lazy loading. Dynamically load data or components based on conditions to avoid unnecessary loading and resource usage.

  • Lazy loading at the routing level: In Vue routing, lazy loading can be used to load routing components on demand. Components are loaded only when the user accesses a certain route, improving initial loading speed and route switching performance.

  • Asynchronous loading of modules: For large Vue projects, you can use data lazy loading to load modules asynchronously to reduce initial loading time. Split modules into small pieces and load them on demand when needed, improving application performance and maintainability.

The above scenarios are only briefly described in this section. If you have free time, please see the summary in Part 3 for specific code examples of each scenario.

Our requirement realization this time is to meet the 1 scenario.

2.2 Data lazy loading code example

When a level is selected, the options under that level are dynamically loaded.

Enable dynamic loading through lazy, and set the loading data source through the lazyload method.

  • The lazyload method has two parameters. The first parameter node is the currently clicked node, and the second resolve is the callback when the data loading is completed ( must be called).

  • node can deconstruct the level parameter, which starts counting from 0 and indicates the level of the currently clicked node.

  • Adding the leaf attribute to the data object is to indicate which level of object is the leaf node.

Template code:

<template>
  <!-- Cascading Panel -->
  <el-cascader-panel :props="props"></el-cascader-panel>
</template>

Logic code:

<script setup>
  // Cascading panel configuration items
  const props = reactive({
    // Enable lazy loading
    lazy: true,
    // Lazy loading data source method
    async lazyLoad(node, resolve) {
      const {level} = node;

      // There is already data, no need to repeat the request
      if (node.children & amp; & amp; node.children.length > 0) return;

      // Simulate the interface
      setTimeout(() => {
        let result;
        switch (level) {
          case 0: // first-level directory
            result = [
              {
                value: "0",
                label: "Intra-bank transfer-mobile phone number",
                children: []
              },
              {
                value: "1",
                label: "Intra-bank transfer-bank account number",
                children: []
              },
              {
                value: "2",
                label: "Remit money to local bank",
                children: []
              },
              {
                value: "3",
                label: "Remit money to wallet",
                children: []
              },
              {
                value: "4",
                label: "Transfer to CUPD",
                children: []
              }
            ];
            break;
          case 1: //Secondary directory
            // Omit the code here...
            
            break;
          case 2: //Third-level directory
            // Omit the code here...

            break;
          case 3: //fourth-level directory
            // Omit the code here...

            break;
          case 4: //Five-level directory
            result = [
              {
                value: "Minimum system version",
                label: "Minimum system version requirements"
              },
              {
                value: "0",
                label: "Disable"
              },
              {
                value: "1",
                label: "internal beta"
              },
              {
                value: "2",
                label: "online"
              }
            ];

            //Set the fifth-level menu as a leaf node with no child nodes
            result.forEach((item) => {
              item.leaf = level >= 4;
            });
            break;
          default:
            result = [];
            break;
        }

        resolve(result);
      }, 1000);
    }
  });
</script>

2.3 Example of inserting input box code

Through slot and condition judgment, insert an input box in the cascading panel, where data.label is the name of the node object.

By preventing event bubbling via @click.stop, setting the width to 100% of the parent element, and clearing some default styles of the cascading panel component, the input box cannot be selected. Effect.

Template code:

<template>
  <!-- Cascading Panel -->
  <el-cascader-panel :props="props">
        <template #default="{ data }">
          <!-- Input box node object -->
          <div v-if="data.label == 'Minimum system version requirement'" @click.stop style="width: 100%">
            <div>{<!-- -->{ data.label }}</div>
            <div class="searchText">
              <el-input v-model="searchText" :placeholder="'Minimum system version requirements'"></el-input>
            </div>
          </div>
          <div v-else>
            <div>{<!-- -->{ data.label }}</div>
          </div>
        </template>
      </el-cascader-panel>
</template>

Style code:

<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,
   & amp;:focus {
    background: #fff;
  }
}
.el-cascader-menu__list {
  padding: 20px 0;
}
</style>

3. Detailed explanation of the problem

3.1 List of parameters of CascaderProps configuration items

Picture

3.2 Summary of lazy loading code examples for each scenario

Lazy loading of long lists or paginated data:

<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(); // Initial loading
    window.addEventListener('scroll', this.handleScroll);
  },
  methods: {
    loadMore() {
      this.loading true;
      // Simulate asynchronous loading of data
      setTimeout(() => {
        const newItems = /* Request new data */;
        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 & amp; & amp; !this.loading) {
        this.loadMore(); // Load more data when scrolling to the bottom
      }
    },
  },
  beforeDestroy() {
    window.removeEventListener('scroll', this.handleScroll);
  },
};
</script>

Lazy loading of images:

<template>
 <div>
    <img :src="placeholder" ref="image" style="display: none;">
  </div>
</template>
<script>
export {
  data() {
    return {
      placeholder: require('@/assets/placeholder.png'), // Placeholder image
    };
  },
  mounted() {
    window.addEventListener('scroll', this.handleScroll);
  },
  methods: {
    handleScroll() {
      const imageElement = this.$refs.image;
      const rect = imageElement.getBoundingClientRect();
      if (rect.top < window.innerHeight) {
        const src = /* Get the real address of the image */;
        imageElement.src = src; //Load images
        window.removeEventListener('scroll', this.handleScroll); // Remove the scroll listener after the image is loaded
      }
    },
  },
  beforeDestroy() {
    window.removeEventListener('scroll', this.handle);
  },
};
</script>

Conditional data lazy loading:

<template>
  <div>
    <button @click="showData = true">Show data</button>
    <div v-if="showData">
      <!-- Component or content that displays data -->
    </div>
  </div>
</template>
<script>
export default {
  data() {
    return {
      showData: false,
    };
  },
};
</script>

Lazy loading of routes (based on 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,
});

Asynchronously load modules (based on import() dynamic import syntax):

<template>
  <div>
    <button @click="loadModule">Load module</button>
    <div v-if="moduleLoaded">
      <!-- Display loaded modules -->
    </div>
  </div>
</template>
<script>
export default {
  data() {
    return {
      moduleLoaded: false,
    };
  },
  methods: {
    loadModule() {
      import('./path/to/module.js')
        .then((module) => {
          //Module loaded successfully
          this.moduleLoaded = true;
        })
        .catch((error) => {
          console.error(error);
        });
    },
  },
};
</script>

Conclusion

The original intention of establishing this platform:

  • Create a Q&A platform that only contains front-end questions, allowing everyone to efficiently search and handle the same questions.

  • By continuously accumulating questions, we can practice logical thinking together and learn relevant knowledge points by the way.

  • When you encounter problems or issues that resonate with you, discuss them together, settle together, and grow together.

Thank you for following the WeChat public account: “Programmer Dache”, and then join the Q&A group, let us solve and implement all bugs together!

The knowledge points of the article match the official knowledge files, and you can further learn relevant knowledge. Vue entry skill tree Home page Overview 39638 people are learning the system