vue使用Swiper做轮播图时,浏览器窗口变化,图片跟着变化实现

首先轮播图是这样的:

 很美好,都显示出来了,但是当我缩小浏览器窗口时:

 图片显示不全,即使我外面设置了等比例缩小,它里面的图片尺寸还是根据原来的尺寸不变化。

下面解决方法1:

HTML部分:

 <div ref="home_swiper" class="swiper-container">
      <div class="swiper-wrapper">
        <div class="swiper-slide" v-for="(item,index) in imgList">
          <div class="lb_home1"><img :src="imgList[index]"></div>
        </div>
        <!-- <div class="swiper-slide">
          <div class="lb_home2">2</div>
        </div>
        <div class="swiper-slide">
          <div class="lb_home3">3</div>
        </div> -->
      </div>
      <div class="swiper-scrollbar"></div>
    </div>

js部分,图片以数组方式传入

 data() {
        return {
          imgList: ["http://we-teach.humianyuan.cn/home1.png", "http://we-teach.humianyuan.cn/home2.png",
            "http://we-teach.humianyuan.cn/home3.png"
          ],
          Swiper: null,
        }

css部分:

 .lb_home1{
      /* 这里是一个技巧,设置高度为0,再设置padding-bottom百分比,
      此时高度就是父元素高度的百分比,用来设置自适应 */
      height: 0%;
       100%;
      padding-bottom: 50%;
      background-color: black;
    }
    /* 设置图片大小,100%,让图片都显示出来 */
    .lb_home1 img{
       100%;
      height: 100%;
    }

此时看一下结果:

 你以为没变化吗,其实已经改变了,只是因为没刷新,所以我自己上网找了别人说的什么几把玩意,说调一下update,resize一下,可是这些几把方法不适合我,没有用,swiper不会自动刷新,看了官方文档,用了它推荐的几把方法也不起效果。

最后一气之下,自己按了F5,

 达到了我想要的结果,那就自己实现刷新了,vue有个provide方法,可以实现reload注入,实现局部刷新。

在app.vue下

 实现该方法注册,那么在其他组件都可以用这个方法了,用之前必须注入

 然后实时监听窗口onresize,就可以刷新了,下面是全部代码:

APP.vue:

<template>
  <div id="app">
    <div v-show='this.$route.name=="Brief"?false:true'><Public_Nav></Public_Nav></div>
    <router-view v-if="isRouterAlive" />
  </div>
</template>
<script>
  import Public_Nav from 'components/content/nav/Public_Nav.vue'
  export default {
    name: 'App',
    //给全局注册一个reload,需要使用时就注入该方法
    provide(){
      return{
        reload:this.reload
      }
    },
    data() {
      return {isRouterAlive:true}
    },
   methods: {
     reload(){
       this.isRouterAlive = false;
       this.$nextTick(function(){
         this.isRouterAlive = true;
       })
     }
   },
    components:{
      Public_Nav
    }
  }
</script>
<style scoped>
  /* @import 'https://at.alicdn.com/t/font_2391663_8sx9tzlzzhl.css'; */
  /* #app{
    overflow: hidden;
  } */
</style>

自己封装的Swiper

<template>
    <div ref="home_swiper" class="swiper-container">
      <div class="swiper-wrapper">
        <div class="swiper-slide" v-for="(item,index) in imgList">
          <div class="lb_home1"><img :src="imgList[index]"></div>
        </div>
      </div>
      <div class="swiper-scrollbar"></div>
    </div>
  </template>
  <script>
    import Swiper from 'swiper'; //轮播
    export default {
      name: 'HomeSwiper',
      inject: ['reload'],
      data() {
        return {
          imgList: ["http://we-teach.humianyuan.cn/home1.png", "http://we-teach.humianyuan.cn/home2.png",
            "http://we-teach.humianyuan.cn/home3.png"
          ],
          Swiper: null,
        }
      },
      methods: {
        initMySwiper() {
          let mySwiper = this.Swiper = new Swiper(this.$refs.home_swiper, {
            // direction:'vertical',
            loop: true, // 循环模式选项
             window.innerWidth * 0.9 * 0.65,
            //分页器
            scrollbar: {
              el: '.swiper-scrollbar',
              draggable: true,
            },
            autoplay: {
              delay: 2000,
              disableOnInteraction: false, //用户触摸后静止关闭
            }
          })
        }
      },
      mounted() {
        this.initMySwiper();
        window.onresize = () => {
           this.reload()//窗口变化实时刷新
        }
      },
    }
  </script>
  <style>
    .lb_home1{
      /* 这里是一个技巧,设置高度为0,再设置padding-bottom百分比,
      此时高度就是父元素高度的百分比,用来设置自适应 */
      height: 0%;
       100%;
      padding-bottom: 50%;
      /* background-color: black; */
    }
    /* 设置图片大小,100%,让图片都显示出来 */
    .lb_home1 img{
       100%;
      height: 100%;
    }
</style>

测试结果:

 

 大功告成!

第二种方法设置样式还是要用到reload注入,只不过控制图片样式是通过背景图片方式:

<template>
    <div ref="home_swiper" class="swiper-container">
      <div class="swiper-wrapper">
        <div class="swiper-slide" >
          <div class="lb_home1"></div>
        </div>
        <div class="swiper-slide">
          <div class="lb_home2"></div>
        </div>
        <div class="swiper-slide">
          <div class="lb_home3"></div>
        </div> 
      </div>
      <div class="swiper-scrollbar"></div>
    </div>
  </template>
  <script>
    import Swiper from 'swiper'; //轮播
    export default {
      name: 'HomeSwiper',
      inject: ['reload'],
      data() {
        return {
          imgList: ["http://we-teach.humianyuan.cn/home1.png", "http://we-teach.humianyuan.cn/home2.png",
            "http://we-teach.humianyuan.cn/home3.png"
          ],
          Swiper: null,
        }
      },
      methods: {
        initMySwiper() {
          let mySwiper = this.Swiper = new Swiper(this.$refs.home_swiper, {
            // direction:'vertical',
            loop: true, // 循环模式选项
             window.innerWidth * 0.9 * 0.65,
            //分页器
            scrollbar: {
              el: '.swiper-scrollbar',
              draggable: true,
            },
            autoplay: {
              delay: 2000,
              disableOnInteraction: false, //用户触摸后静止关闭
            }
          })
        }
      },
      mounted() {
        this.initMySwiper();
        window.onresize = () => {
          this.reload()
        }
      },
    }
  </script>
  <style> .lb_home1 {
      height: 0%;
       100%;
      padding-bottom: 50%;
      background: url('http://we-teach.humianyuan.cn/home1.png') no-repeat;
      background-size: 100%;//让图片都显示出来
    }

    .lb_home2 {
      height: 0%;
       100%;
      padding-bottom: 50%;
      background: url('http://we-teach.humianyuan.cn/home2.png') no-repeat;
      background-size: 100%;
    }

    .lb_home3 {
      height: 0%;
       100%;
      padding-bottom: 50%;
      background: url('http://we-teach.humianyuan.cn/home3.png') no-repeat;
      background-size: 100%;
    } 
  </style>

 最后测试结果和上面一样,用都说好,就不展示了。

----------------------------------3月9日第二次更新--------------------------------

上面那种方法是通过mouted加window.resize进行实时监听刷新的,但是实际应用中我们要做的是局部刷新,所以需要在router-view加keepalive属性。

<keep-alive>
      <router-view  v-if="isRouterAlive" />
    </keep-alive>

一旦加上keepalive属性,mouted就不销毁了。原来的vue会在页面切换就销毁,然后重新执行渲染mounted,但是有时候我们需要记录我们之前在这个页面做的一些操作,比如点击了某样东西,这个东西变色了,加了keepalive之后,跳转到其它页面,再切回来,这个东西还是原来变色的那种样式。

但是keppAlive在带来方便的同时也带来了不会重复mounted,需要手动F5按刷新才有效,下面就是页面加了keepAlive属性后,轮播图不会刷新的样子,因为虽然有检测到窗口变化,但是由于keppAlive属性,reload函数不起作用。

 所以我们此时reload函数失去作用。

所以接下来我想出了第二个方法,就是在检测到窗口变化时实时初始化Swiper,例如下面:

 window.onresize=()=>{
          this.initMySwiper()//自己封装的初始化函数,窗口变化时就初始化
        }

缩小窗口后,得到的是想要的结果:

 但是随之而来的另一个问题是,监听窗口变化这个window.resize这个函数会在窗口发生变化时触发执行,有时候还触发了不止一次,那么重复初始化Swiper之后,它会创建多个实例对象,且不会销毁,看起来切换轮播图的大小虽然没变,但是速度变得是原来的几倍,因为实例化了很多个对象,多个对象在不同时间执行,串在一起时就像开高铁一样快得惊人。

所以有了问题,我们就得解决问题,解决方案那就是:

(1)在创建新的Swiper实例化对象之前先判断上一个是否销毁;

(2)在销毁对象时,判断是否为当前的Swiper实例化对象。

翻译为更加形象一点就是:吃面包的故事。

每天起床第一件事就是吃面包和买面包:

(1)吃面包:判断今天吃的面包是否是今天买的?

(2)买面包:判断昨天的面包吃了没有?

总结起来就是,今天面包今天买,今天吃。每天要吃的面包,每天买,每天吃完。

所以翻译代码为:

 data() {
        return {
          Swiper: null,//保存当前的Swiper
          isReload: false,
          oldSwiper:null//要销毁的Swiper
        }
      },
      methods: {
        initMySwiper() {
          let mySwiper;
            return mySwiper = this.Swiper = new Swiper(this.$refs.home_swiper, {
              // direction:'vertical',
              loop: true, // 循环模式选项
               window.innerWidth * 0.9 * 0.65,//可以修改宽度
              //分页器
              scrollbar: {
                el: '.swiper-scrollbar',
                draggable: true,
              },
              autoplay: {
                delay: 2000,
                disableOnInteraction: false, //用户触摸后静止关闭
              }
            })
        }
      },
      mounted() {
       this.oldSwiper = this.initMySwiper();//初始化时,把刚刚实例化产生的Swiper保存在oldSwiper中
       console.log("新老swiper:"+(this.oldSwiper==this.Swiper))
        window.onresize = () => {
          console.log("新老swiper:"+(this.oldSwiper==this.Swiper))
          //销毁的是否为当前对象
          if(this.oldSwiper==this.Swiper){
            this.Swiper.destroy();
            console.log("destroy");
            this.Swiper = null;//摧毁Swiper之后赋值空
          } 
          //判断上一个对象是否销毁了,销毁了才能创建新对象,计时器加不加都可以
          setTimeout(() => {
            if(this.Swiper==null){
              this.oldSwiper=this.initMySwiper(); 
            console.log("初始化swiper")
            }
          }, 10);
           
            console.log("resize")
        }
      console.log("mounted")
      },
      
    }
  </script>

 ---------------------------3月10日第三次更新------------------------------------

上面那种方案是组件处于keepalive情况下的,但是有一个问题,就是mouted函数只会触发一次了,因为保持了keepalive属性;当我们退出页面重进后,窗口实时监听就会失效,此时我们应该把监听窗口变化的函数写在activated

穷则独善其身,达则兼济天下……
原文地址:https://www.cnblogs.com/hmy-666/p/14496859.html