Используйте Vue-Awesome-Swiper для достижения эффекта вращающейся карусели и эффекта панорамной карусели.

Vue.js
Используйте Vue-Awesome-Swiper для достижения эффекта вращающейся карусели и эффекта панорамной карусели.

добиться эффекта

  • Наложение поворота

    旋转叠加效果

  • Сковорода

    旋转叠加效果效果

Некоторое время назад я сделал гибридное приложение. Дизайн пользовательского интерфейса требует, чтобы отображение определенной страницы достигало эффекта скользящей карусели. Выбранная карточка контента отображается в центре, а предыдущая карточка контента и следующий контент отображаются в конце обратная сторона выбранной карты в два раза больше.и с размытием по Гауссу и т.д. . Самое обидное, что эффект скольжения надо крутить и накладывать один за другим. (Осень!

В то время я использовал страницу, реализованную vue-cli-3 + ant-design-vue.Я обнаружил, что есть готовые компоненты Carousel, доступные в ant-design-vue.Из-за срочного графика я использовал это для реализовать первую версию временно.Специальные эффекты не имеют других наворотов на дисплее. Приняв первую версию, я обнаружил, что в ant-design-vue действительно много ям. . Карусель также очень негладкая на мобильной стороне. Это всегда особенно плохой опыт. На последнем дыхании все стили были написаны мной, все компоненты инкапсулированы мной, а ant-design-vue полностью удален из проекта.

Карусельная карта думает о хорошей штуке Swiper, и теперь есть vue-версия, но нет специальной документации vue-версии, и относительно мало элементов можно найти. В отчаянии я прогрыз документ Swiper4, проделал яростную операцию и нашел лючок. Потребности удовлетворены. Я просто разобрался, написал простенькое демо и записал, если оно может вам помочь, то будет лучше всего~

1. Сначала представьте Vue-Awesome-Swiper

Есть два способа представить Vue-Awesome-Swiper: один — это глобальное введение, а другой — введение компонентов. Если вам нужно использовать эту вещь только в одном месте в вашем проекте, вы можете импортировать ее на страницу, которую вы используете.Если вам это нужно в нескольких местах, то импортируйте ее глобально.

  • Импортировать глобально:
// main.js
import VueAwesomeSwiper from 'vue-awesome-swiper'
import 'swiper/dist/css/swiper.css'

Vue.use(VueAwesomeSwiper, /* { default global options } */)
  • Представлено в компоненте:
// xxx.vue
<script>
import 'swiper/dist/css/swiper.css'
import { swiper, swiperSlide } from 'vue-awesome-swiper'

export default {
  components: {
    swiper,
    swiperSlide
  }
}
</script>

2. Используйте на странице

<template>
  <div class="swiper-content">
    <swiper ref="mySwiper" :options="swiperOption" class="show-swiper">
      <template v-for="(item, index) in list">
        <swiper-slide :key="index">
          <div class="swiper-item">
            <span>{{ item }}</span>
          </div>
        </swiper-slide>
      </template>
    </swiper>
  </div>
</template>

js-часть

  • Наложение поворота
<script>
import { mapState } from 'vuex'
import store from '@/store'
export default {
  data() {
    return {
      list: [1, 2, 3, 4, 5, 6],
      swiperOption: {
        // 设置slider容器能够同时显示的slides数量,默认为1, 'auto'则自动根据slides的宽度来设定数量
        slidesPerView: 'auto',
        /*
        * 开启这个参数来计算每个slide的progress(进度、进程)
        * 对于slide的progress属性,活动的那个为0,其他的依次减1
        */
        watchSlidesProgress: true,
        // 默认active slide居左,设置为true后居中
        centeredSlides: true,
        // 当你创建一个Swiper实例时是否立即初始化,这里我们手动初始化
        init: false,
        longSwipesRatio: 0.1,
        touchReleaseOnEdges: true,
        observer: true, // 修改swiper自己或子元素时,自动初始化swiper
        observeParents: true, // 修改swiper的父元素时,自动初始化swiper
        on: {
          progress: function() {
            for (let i = 0; i < this.slides.length; i++) {
              const slide = this.slides.eq(i) // 指定匹配元素集缩减值
              const slideProgress = this.slides[i].progress // 当前元素集的progress值

              let modify = 0 // 偏移权重
              if (parseInt(Math.abs(slideProgress)) > 0) {
                modify = Math.abs(slideProgress) * 0.2 // 不一定要0.2,可自行调整
              }
              const translate = slideProgress * modify * 500 + 'px' // 500是swiper-slide的宽度
              const scale = 1 - Math.abs(slideProgress) / 5 // 缩放权重值,随着progress由中向两边依次递减,可自行调整
              const zIndex = 99 - Math.abs(Math.round(10 * slideProgress))
              slide.transform(`translateX(${translate}) scale(${scale})`)
              slide.css('zIndex', zIndex)
              slide.css('opacity', 1) // 是否可见
              if (parseInt(Math.abs(slideProgress)) > 1) { // 设置了只有选中的元素以及他两遍的显示,其他隐藏
                slide.css('opacity', 0)
              }
            }
          },
          slideChange: function() {
            store.commit('SET_ACTIVE_INDEX', this.activeIndex)
          }
        }
      }
    }
  },
  computed: {
    swiper() {
      return this.$refs.mySwiper.swiper
    },
    ...mapState({
      activeItemIndex: state => state.activeIndex
    })
  },
  mounted() {
    this.initSwiper()
  },
  methods: {
    initSwiper() {
      this.$nextTick(async() => {
        await this.swiper.init() // 现在才初始化
        await this.swiper.slideTo(this.activeItemIndex)
      })
    }
  }
}
</script>
  • Сковорода
<script>
import { mapState } from 'vuex'
import store from '@/store'
export default {
  data() {
    return {
      list: [1, 2, 3, 4, 5, 6],
      swiperOption: {
        slidesPerView: 'auto',
        watchSlidesProgress: true,
        // 设定slide与左边框的预设偏移量(单位px)
        slidesOffsetBefore: 37,
        // 设置slide之间的距离(单位px)
        spaceBetween: 17,
        centeredSlides: true,
        init: false,
        longSwipesRatio: 0.1,
        touchReleaseOnEdges: true,
        observer: true, // 修改swiper自己或子元素时,自动初始化swiper
        observeParents: true, // 修改swiper的父元素时,自动初始化swiper
        on: {
          progress: function() {
            for (let i = 0; i < this.slides.length; i++) {
              const slide = this.slides.eq(i)
              const slideProgress = this.slides[i].progress

              const scale = 1 - Math.abs(slideProgress) / 5 // 缩放权重值,随着progress由中向两边依次递减,可自行调整
              slide.transform(`scale3d(${scale}, ${scale}, 1)`)
            }
          },
          slideChange: function() {
            store.commit('SET_ACTIVE_INDEX', this.activeIndex)
          }
        }
      }
    }
  },
  computed: {
    swiper() {
      return this.$refs.mySwiper.swiper
    },
    ...mapState({
      activeItemIndex: state => state.activeIndex
    })
  },
  mounted() {
    this.initSwiper()
  },
  methods: {
    initSwiper() {
      this.$nextTick(async() => {
        await this.swiper.init() // 现在才初始化
        await this.swiper.slideTo(this.activeItemIndex)
      })
    }
  }
}
</script>

В параметрах конфигурации я установил для init значение false, я хочу использовать данные интерфейса после монтирования проекта.this.swiper.init()Чтобы инициализировать компонент карусели, а затем я сохраняю индекс элемента активации в vuex, чтобы каждый раз, когда я возвращаюсь на эту страницу с другой страницы, я мог использоватьthis.swiper.slideTo(this.activeItemIndex)Чтобы контролировать, на какую карточку контента я хочу настроить таргетинг в первую очередь.

3. Инициализация стиля

.swiper-content {
  width: 100%;
  height: 100%;
  position: relative;
  overflow: hidden;
  margin: 0 auto;
  padding: 50px 0;

  .show-swiper {
    width: 100%;
    height: 100%;
    top: 0;
    left: 0;

    .swiper-slide {
      width: 500px;
      // 表示所有属性都有动作效果,过度时间为0.4s,以慢速开始和结束的过渡效果
      transition: all .4s cubic-bezier(.4, 0, .2, 1);
      
      .swiper-item {
        width: 100%;
        height: 500px;
        background: rgb(140, 172, 134);
        border-radius: 6px;
        color: orangered;
        font-size: 24px;
        line-height: 1.5;
        border: 1px solid orangered;
      }
    }
  }
}

потому чтоslidesPerView: 'auto', поэтому swiper-slide мы должны дать ему начальную ширину, чтобы он мог автоматически рассчитать ширину контейнера, а затем здесь я устанавливаю эффект анимацииtransition: all .4s cubic-bezier(.4, 0, .2, 1);Вы можете вносить изменения в соответствии с вашими потребностями

Это, наверное, содержание, оно очень простое? Я опубликую адрес исходного кода и клонирую его для справки, если это необходимо.Я использую в проекте vue-cli3, который можно настроить под себя.