Super easy-to-use carousel plugin vue-awesome-swiper@3, two-way control to realize custom pager and front and rear indicators. Solve the problem of confusion when dynamically obtaining data.

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

  1. 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.
  2. 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

Please add image description

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

  1. Because you want to customize the pagination, at first consider using the pagination attribute of swiper, and use the renderBullet method to customize the pagination. The results are certainly feasible.
  2. 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: Picture 1
    Picture 2
  3. 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 the renderCustom method is feasible, but I don’t want to think about it too complicated, because the following method is faster)
  4. After seeing the thumbnail two-way control demo on the official website, it suddenly became clear that what I wanted was that effect.
  5. 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~~~