Super easy-to-use carousel plugin vue-awesome-swiper@3, two-way control to realize custom pager and front and rear indicators. Solve the bug of confusion and instability when dynamically obtaining data
- 1. Requirements, demo renderings
-
- 1. Requirement description
- 2. Demo renderings
- 2. vue-awesome-swiper
-
- 1. Official website address and component installation
- 2. Detailed explanation of ideas
- 3. Demo code
-
- 1.html
- 2.js
- 3. css
- 4. Solve the bug of disordered and unstable components when dynamically obtaining data
1. Requirements, demo renderings
1. Requirement description
- Nest a link list in an iframe to automatically play in carousel. The menu name of the link is placed at the bottom, click to jump to the specified page.
- Due to the large number of links, the pagination indicator needs to center the currently clicked button and hide other redundant buttons.
2. Demo renderings
2. vue-awesome-swiper
I accidentally discovered the vue-awesome-swiper
treasure carousel plug-in. It is really easy to use, has powerful functions, and is very flexible in customization.
1. Official website address, component installation
Swiper official website Chinese document address: https://www.swiper.com.cn/api/index.html
Component installation
The version I use is [email protected]
, which is suitable for vue2. For vue3, use a higher version. So be sure to pay attention to the version you install.
npm install [email protected] --save
2. Detailed explanation of ideas
- Because you want to customize the pagination, at first consider using the
pagination
attribute of swiper, and use therenderBullet
method to customize the pagination. The results are certainly feasible. - But because I wanted to hide the redundant pager indicator points, I used
dynamicBullets
+dynamicMainBullets
to set the dynamic indicator points. However, the result is not ideal, because when rendering for the first time, there will be no indicator point on the left. As shown in the picture:
- I want the effect of Figure 2 to always be the same, so the idea of using
pagination
to customize the paginator is a bit unworkable. (Maybe therenderCustom
method is feasible, but I don’t want to think about it too complicated, because the following method is faster) - After seeing the thumbnail two-way control demo on the official website, it suddenly became clear that what I wanted was that effect.
- Final idea: Implement two swipers, one as a content swiper and one as a custom pager swiper. The two swipers can be set to control each other.
3. demo code
1, html
<template> <div class="page-container"> <!-- iframe carousel page --> <div> <!-- Page Rotator --> <swiper ref="pageSwiper" :options="pageSwiperOptions"> <swiper-slide v-for="(item, index) in menuList" :key="index"> <iframe :src="item.url" width="100%" frameborder="0" border="0" class="iframe"></iframe> </swiper-slide> </swiper> <!-- menu carousel --> <swiper ref="navSwiper" :options="navSwiperOptions" class="nav-swiper"> <swiper-slide v-for="(item, index) in menuList" :key="index" class="menu-item"> <span>{<!-- -->{item.title}}</span> <div class="active-img"></div> </swiper-slide> </swiper> <!-- Forward and back buttons --> <div class="btn-nav btn-nav-prev"></div> <div class="btn-nav btn-nav-next"></div> </div> </div> </template>
2, js
<script> import 'swiper/dist/css/swiper.css' import {<!-- --> swiper, swiperSlide } from 'vue-awesome-swiper' export default {<!-- --> name: "Home", components: {<!-- --> swiper, swiperSlide }, data() {<!-- --> return {<!-- --> //menu list menuList: [ {<!-- --> title: 'Menu 1', url: 'https://www.baidu.com' }, {<!-- --> title: 'Menu 2', url: 'https://www.baidu.com' }, {<!-- --> title: 'Menu 3', url: 'https://www.baidu.com' }, {<!-- --> title: 'Menu 4', url: 'https://www.baidu.com' }, {<!-- --> title: 'Menu 5', url: 'https://www.baidu.com' }, {<!-- --> title: 'Menu 6', url: 'https://www.baidu.com' }, {<!-- --> title: 'Menu 7', url: 'https://www.baidu.com' }, {<!-- --> title: 'Menu 8', url: 'https://www.baidu.com' }, {<!-- --> title: 'Menu 9', url: 'https://www.baidu.com' }, {<!-- --> title: 'Menu 10', url: 'https://www.baidu.com' }, {<!-- --> title: 'Menu 11', url: 'https://www.baidu.com' }, {<!-- --> title: 'Menu 12', url: 'https://www.baidu.com' } ], // Page carousel configuration items pageSwiperOptions: {<!-- --> // Automatically switch autoplay: {<!-- --> // dwell time delay: 30000, // After the user operates swiper, whether to disable autoplay disableOnInteraction: false, }, // loop loop: true, // The loopedSlides of the two swipers must be the same loopedSlides: 5, //Forward and back buttons navigation: {<!-- --> nextEl: '.btn-nav-next', prevEl: '.btn-nav-prev', }, }, //Menu carousel configuration items navSwiperOptions: {<!-- --> // loop loop: true, // The loopedSlides of the two swipers must be the same loopedSlides: 5, //Set the distance between slides (unit px) spaceBetween: 25, // Center the slide. When set to true, the current active slide will be centered instead of left by default. centeredSlides: true, //Set the number of slides that the slider container can display at the same time slidesPerView: 7, // Touch scale. The ratio of touch distance to slide distance. touchRatio: 0.2, // If set to true, clicking the slide will transition to this slide. slideToClickedSlide: true } } }, mounted() {<!-- --> // Set up two carousels to control each other this.$nextTick(() => {<!-- --> const pageSwiper = this.$refs.pageSwiper.swiper const navSwiper = this.$refs.navSwiper.swiper pageSwiper.controller.control = navSwiper navSwiper.controller.control = pageSwiper }) } }; </script>
3, css
<style rel="stylesheet/scss" lang="scss"> .page-container {<!-- --> min-height: 100vh; } /*Carousel*/ .swiper-slide{<!-- --> background-color: #cadeff; } .iframe {<!-- --> display: block; height: calc(100vh - 80px); } /*Bottom menu paginator style*/ .menu-item{<!-- --> color: #1353ff; height: 50px; line-height: 50px; text-align: center; white-space: nowrap; border-radius: 10px; font-size: 16px; cursor: pointer; transition-duration: 0.3s; position: relative; & amp;:hover {<!-- --> transform: scale(1.1); } .active-img{<!-- --> visibility: hidden; width: 130%; height: 120px; position: absolute; left: -15%; bottom: -58px; background-image: url("../assets/images/active.png"); background-size: 100% 100%; } } .nav-swiper{<!-- --> width: 70%; padding: 0 10px; .swiper-wrapper{<!-- --> padding: 15px 0; } /*Menu hit style*/ .swiper-slide-active{<!-- --> color: #fff; background-color: #257cf4 !important; .active-img{<!-- --> visibility: visible; } } } /*forward and backward indicators*/ .btn-nav{<!-- --> width: 76px; height: 28px; background-size: 100% 100%; background-repeat: no-repeat; cursor: pointer; transition-duration: 0.3s; position: fixed; bottom: 26px; z-index: 99; & amp;:hover {<!-- --> transform: scale(1.1); } & amp;:active {<!-- --> transform: scale(0.9); } & amp;.btn-nav-prev{<!-- --> background-image: url("../assets/images/btn-prev.png"); left: 30px; } & amp;.btn-nav-next{<!-- --> background-image: url("../assets/images/btn-next.png"); right: 30px; } } </style>
4. Solve the bug of component disorder and instability when dynamically obtaining data
If your swiper content is static and does not need to dynamically obtain data from the backend interface, then the above steps are over.
However, if the swiper content is dynamically obtained from the backend
data, there may be disordered and unstable components. (Originally full of confidence, I stepped on the muddy pit as soon as I released it…)
The solution is as follows:
1. On the swiper component, add
v-if
to let the swiper component start rendering after getting the data
2. After js gets the data asynchronously, set up two carousels to control each other
The modified code is as follows:
html:
<template> <div class="page-container"> <!-- iframe carousel page --> <div> <!-- Page carousel --> <swiper v-if="menuList. length>0" ref="pageSwiper" :options="pageSwiperOptions"> <swiper-slide v-for="(item, index) in menuList" :key="index"> <iframe :src="item.url" width="100%" frameborder="0" border="0" class="iframe"></iframe> </swiper-slide> </swiper> <!-- Menu carousel --> <swiper v-if="menuList. length>0" ref="navSwiper" :options="navSwiperOptions" class="nav-swiper"> <swiper-slide v-for="(item, index) in menuList" :key="index" class="menu-item"> <span>{<!-- -->{item.title}}</span> <div class="active-img"></div> </swiper-slide> </swiper> <!-- Forward and back buttons --> <div class="btn-nav btn-nav-prev"></div> <div class="btn-nav btn-nav-next"></div> </div> </div> </template>
js:
<script> import 'swiper/dist/css/swiper.css' import {<!-- --> swiper, swiperSlide } from 'vue-awesome-swiper' export default {<!-- --> name: "Home", components: {<!-- --> swiper, swiperSlide }, data() {<!-- --> return {<!-- --> //menu list menuList: [], // Page carousel configuration items pageSwiperOptions: {<!-- --> // Automatically switch autoplay: {<!-- --> // dwell time delay: 30000, // Whether to disable autoplay after the user operates the swiper disableOnInteraction: false, }, // loop loop: true, // The loopedSlides of the two swipers must be the same loopedSlides: 5, //Forward and back buttons navigation: {<!-- --> nextEl: '.btn-nav-next', prevEl: '.btn-nav-prev', }, }, //Menu carousel configuration items navSwiperOptions: {<!-- --> // loop loop: true, // The loopedSlides of the two swipers must be the same loopedSlides: 5, //Set the distance between slides (unit px) spaceBetween: 25, // Center the slide. When set to true, the current active slide will be centered instead of the default left. centeredSlides: true, // Set the number of slides that the slider container can display at the same time slidesPerView: 7, // Touch scale. The ratio of touch distance to slide distance. touchRatio: 0.2, // If set to true, clicking the slide will transition to this slide slideToClickedSlide: true } } }, created() {<!-- --> this. getList(); }, methods: {<!-- --> getList(){<!-- --> let that = this; getScreenMenu().then(res=>{<!-- --> this.menuList = res.data; // Set up two carousels to control each other this.$nextTick(() => {<!-- --> const pageSwiper = this.$refs.pageSwiper.swiper const navSwiper = this.$refs.navSwiper.swiper pageSwiper.controller.control = navSwiper navSwiper.controller.control = pageSwiper }) }) } } }; </script>
In the case of dynamically obtaining data, the rendering effect and static data rendering effect will be exactly the same~~~