Plugin de carrossel super fácil de usar vue-awesome-swiper@3, controle bidirecional para realizar pagers personalizados e indicadores dianteiros e traseiros. Resolva o problema de confusão ao obter dados dinamicamente.

Plugin de carrossel super fácil de usar vue-awesome-swiper@3, controle bidirecional para realizar pagers personalizados e indicadores dianteiros e traseiros. Resolva o bug da confusão e instabilidade ao obter dados dinamicamente

1. Requisitos e renderizações de demonstração

1. Descrição dos requisitos

  1. Aninhe uma lista de links em um iframe para reproduzir automaticamente no carrossel. O nome do menu do link é colocado na parte inferior, clique para ir para a página especificada.
  2. Devido ao grande número de links, o indicador de paginação precisa centralizar o botão atualmente clicado e ocultar outros botões redundantes.

2. Renderizações de demonstração

Adicione uma descrição da imagem

二、vue-awesome-swiper

Eu acidentalmente descobri vue-awesome-swipereste plug-in de carrossel de tesouros, é realmente fácil de usar, poderoso e muito flexível na personalização.

1. Endereço do site oficial, instalação de componentes

Endereço do documento chinês do site oficial da Swiper: https://www.swiper.com.cn/api/index.html

Instalação de componentes
A versão que uso é [email protected]para vue2. Vue3 precisa usar uma versão superior. Portanto, preste atenção à versão instalada.


npm install vue-awesome-swiper@3.1.3 --save

2. Ideias detalhadas

  1. Como você deseja personalizar o pager, primeiro considere usar paginationas propriedades de swiper e use renderBulleto método para personalizar o pager. O resultado é certamente factível.
  2. Mas como quero ocultar o ponteiro do pager redundante, usei dynamicBullets+ dynamicMainBulletspara definir o ponteiro dinâmico. Mas o resultado não é o ideal, pois quando for renderizado pela primeira vez, não haverá nenhum ponto indicador à esquerda. como mostra a imagem:figura 1
    Figura II
  3. Quero sempre ter o efeito da Figura 2, então paginationa ideia de usar um pager customizado é um pouco impraticável. (Talvez renderCustomo método seja viável, mas não quero pensar muito complicado, porque o método a seguir é mais rápido)
  4. Depois de ver a demonstração do controle bidirecional em miniatura no site oficial, de repente me dei conta de que esse efeito era o que eu queria.
  5. Idéia final : implementar dois swipers, um como swiper de conteúdo e outro como swiper de pager personalizado. Os dois swipers podem ser configurados para controlar um ao outro.

3. código de demonstração

1.HTML

<template>
  <div class="page-container">
    <!-- iframe轮播页面 -->
    <div>
      <!-- 页面轮播器 -->
      <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>
      <!-- 菜单轮播器 -->
      <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>
      <!-- 前进后退按钮 -->
      <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 {
    
    
      	// 菜单列表
        menuList: [
          {
    
    
            title: '菜单1',
            url: 'https://www.baidu.com'
          },
          {
    
    
            title: '菜单2',
            url: 'https://www.baidu.com'
          },
          {
    
    
            title: '菜单3',
            url: 'https://www.baidu.com'
          },
          {
    
    
            title: '菜单4',
            url: 'https://www.baidu.com'
          },
          {
    
    
            title: '菜单5',
            url: 'https://www.baidu.com'
          },
          {
    
    
            title: '菜单6',
            url: 'https://www.baidu.com'
          },
          {
    
    
            title: '菜单7',
            url: 'https://www.baidu.com'
          },
          {
    
    
            title: '菜单8',
            url: 'https://www.baidu.com'
          },
          {
    
    
            title: '菜单9',
            url: 'https://www.baidu.com'
          },
          {
    
    
            title: '菜单10',
            url: 'https://www.baidu.com'
          },
          {
    
    
            title: '菜单11',
            url: 'https://www.baidu.com'
          },
          {
    
    
            title: '菜单12',
            url: 'https://www.baidu.com'
          }
        ],
        // 页面轮播器配置项
        pageSwiperOptions: {
    
    
          // 自动切换
          autoplay: {
    
    
            // 停留时间
            delay: 30000,
            // 用户操作swiper之后,是否禁止autoplay
            disableOnInteraction: false,
          },
          // 环路
          loop: true,
          // 两个swiper的loopedSlides要相同
          loopedSlides: 5,
          // 前进后退按钮
          navigation: {
    
    
            nextEl: '.btn-nav-next',
            prevEl: '.btn-nav-prev',
          },
        },
        // 菜单轮播器配置项
        navSwiperOptions: {
    
    
          // 环路
          loop: true,
          // 两个swiper的loopedSlides要相同
          loopedSlides: 5,
          // 在slide之间设置距离(单位px)
          spaceBetween: 25,
          // 居中幻灯片。设定为true时,当前的active slide 会居中,而不是默认状态下的居左。
          centeredSlides: true,
          // 设置slider容器能够同时显示的slides数量
          slidesPerView: 7,
          // 触摸比例。触摸距离与slide滑动距离的比率。
          touchRatio: 0.2,
          // 设置为true则点击slide会过渡到这个slide
          slideToClickedSlide: true
        }
      }
    },
    mounted() {
    
    
      // 设置两个轮播器相互控制
      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;
  }
  /*轮播*/
  .swiper-slide{
    
    
    background-color: #cadeff;
  }
  .iframe {
    
    
    display: block;
    height: calc(100vh - 80px);
  }
  /*底部菜单分页器样式*/
  .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;
    &: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;
    }
    /*菜单命中样式*/
    .swiper-slide-active{
    
    
      color: #fff;
      background-color: #257cf4 !important;
      .active-img{
    
    
        visibility: visible;
      }
    }
  }
  /*前进后退指示器*/
  .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;
    &:hover {
    
    
      transform: scale(1.1);
    }
    &:active {
    
    
      transform: scale(0.9);
    }
    &.btn-nav-prev{
    
    
      background-image: url("../assets/images/btn-prev.png");
      left: 30px;
    }
    &.btn-nav-next{
    
    
      background-image: url("../assets/images/btn-next.png");
      right: 30px;
    }
  }
</style>

4. Resolva o bug de componentes desordenados e instáveis ​​ao obter dados dinamicamente

Se o conteúdo do seu swiper for estático e não precisar obter dados dinamicamente da interface de back-end, as etapas acima serão concluídas.

No entanto, se o conteúdo do swiper for dados escravos 后端动态获取, os componentes poderão ficar desordenados e instáveis. (Originalmente cheio de confiança, pisei no poço lamacento assim que o soltei...)

A solução é a seguinte:

1. No componente swiper, adicione-o v-ifpara que o componente swiper comece a renderizar após obter os dados.
2. Depois que js obtiver os dados de forma assíncrona, configure dois carrosséis para controlar um ao outro

O código modificado é o seguinte:
html:

<template>
  <div class="page-container">
    <!-- iframe轮播页面 -->
    <div>
      <!-- 页面轮播器 -->
      <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>
      <!-- 菜单轮播器 -->
      <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>
      <!-- 前进后退按钮 -->
      <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 {
    
    
      	// 菜单列表
        menuList: [],
        // 页面轮播器配置项
        pageSwiperOptions: {
    
    
          // 自动切换
          autoplay: {
    
    
            // 停留时间
            delay: 30000,
            // 用户操作swiper之后,是否禁止autoplay
            disableOnInteraction: false,
          },
          // 环路
          loop: true,
          // 两个swiper的loopedSlides要相同
          loopedSlides: 5,
          // 前进后退按钮
          navigation: {
    
    
            nextEl: '.btn-nav-next',
            prevEl: '.btn-nav-prev',
          },
        },
        // 菜单轮播器配置项
        navSwiperOptions: {
    
    
          // 环路
          loop: true,
          // 两个swiper的loopedSlides要相同
          loopedSlides: 5,
          // 在slide之间设置距离(单位px)
          spaceBetween: 25,
          // 居中幻灯片。设定为true时,当前的active slide 会居中,而不是默认状态下的居左。
          centeredSlides: true,
          // 设置slider容器能够同时显示的slides数量
          slidesPerView: 7,
          // 触摸比例。触摸距离与slide滑动距离的比率。
          touchRatio: 0.2,
          // 设置为true则点击slide会过渡到这个slide
          slideToClickedSlide: true
        }
      }
    },
    created() {
    
    
      this.getList();
    },
    methods: {
    
    
      getList(){
    
    
        let that = this;
        getScreenMenu().then(res=>{
    
    
          this.menuList = res.data;
          // 设置两个轮播器互相控制
          this.$nextTick(() => {
    
    
            const pageSwiper = this.$refs.pageSwiper.swiper
            const navSwiper = this.$refs.navSwiper.swiper
            pageSwiper.controller.control = navSwiper
            navSwiper.controller.control = pageSwiper
          })
        })
      }
    }
  };
</script>

No caso de obtenção de dados dinamicamente, o efeito de renderização e o efeito de renderização de dados estáticos serão exatamente os mesmos ~~~

Acho que você gosta

Origin blog.csdn.net/qq_38118138/article/details/132447661
Recomendado
Clasificación