swiper 指令方法轮播,组件方法轮播,updated方法三种方式区别 以及 this.$nextTick

本文探讨了在Vue.js中使用setTimeout模拟异步数据加载时实现轮播图的两种方法:一是将轮播初始化放在updated钩子中,但存在复用性和触发时机问题;二是通过在mounted钩子中创建自定义组件Swiper,提高复用性。另外,还介绍了使用指令的方式在Vue2和Vue3中实现轮播图,利用指令的生命周期更好地控制轮播图的创建和销毁。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

效果如图:

2.本例中使用 setTimeout 模拟异步获取数据,使用了 swiper组件

1.轮播初始化放在 updated 中,(弊端 :如果当前页面的状态不止 datalist 一个,其他状态更新时也会触发 new swiper,这个时候 new swiper 执行多次,就会出 bug)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet" href="./swiper-7.4.1/swiper/swiper-bundle.min.css">
    <script src="./vue.js"></script>
    <script src="./swiper-7.4.1/swiper/swiper-bundle.min.js"></script>
    <style>
        .swiper {
            width: 600px;
            height: 300px;
        } 
    </style>
</head>
<body>
    <div id="box">
        <div class="swiper">
            <div class="swiper-wrapper">
                <div class="swiper-slide" v-for = "items in datalist" :key="items">
                    <img :src="items">
                </div>
            </div>
        </div>
        <!-- 如果需要导航按钮 -->
        <div class="swiper-button-prev"></div>
        <div class="swiper-button-next"></div>
    </div>
    <script>      
        var vm = new Vue({
            el:'#box',
            data:{
                datalist:[]
            },
            mounted(){
                setTimeout(()=>{
                    this.datalist = [
                        'https://mall.s.maizuo.com/bb4e79ef1de07aab2f8ed91b7fd7e731.jpg',
                        'https://mall.s.maizuo.com/90b7581c565efdf1b3ed8127172d9c87.jpg',
                        'https://mall.s.maizuo.com/e753ab0a0709ff8a7048da1c714c5e06.jpg'
                    ]
                },2000)
            },
            updated(){
                new Swiper ('.swiper', {
                    loop: true, // 循环模式选项
                        // 如果需要前进后退按钮
                    navigation: {
                        nextEl: '.swiper-button-next',
                        prevEl: '.swiper-button-prev',
                    },
                    autoplay: {
                        delay: 1000,
                        disableOnInteraction: false,
                    },
                }) 
            }
        })
        /*
        这个方法的缺点:1 无法复用;2.如果当前页面的状态不止 datalist 一个,其他状态更新时也会触发 new swiper,这个时候
         new swiper 执行多次,就会出 bug
        */
    </script>
</body>
</html>

2.轮播初始化放在 mounted 中,用组件方式。提高 复用性。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet" href="./swiper-7.4.1/swiper/swiper-bundle.min.css">
    <script src="./vue.js"></script>
    <script src="./swiper-7.4.1/swiper/swiper-bundle.min.js"></script>
    <style>
        .swiper {
            width: 600px;
            height: 300px;
        } 
    </style>
</head>
<body>
    <div id="box">
        <!-- 一开始的 key = 0, 当 2s 后取到后端数据时, key 为数组长度, 进行 diff 算法
        对比发现前后两个 swiper 不一样(因为 diff 算法中 key 值对比),于是删除老的,重新创建新的 dom 结构。
        于是 mounted 触发两次,即第一次创建的 没有轮播内容 dom 和第二次取得数据后,两下对比发现
        第一次创建的 dom 不能复用,删除后重新创建新的 dom  -->
        <swiper :key= "datalist.length">  <!-- 这个方法是一样的 。<swiper v-if = "datalist.length"></swiper> -->
            <swiper-item v-for="items in datalist" :key="items">
                 <img :src="items">
            </swiper-item>
        </swiper>
    </div>
    <script>
        Vue.component("swiperItem",{
            template:`
            <div class="swiper-slide">
                <slot></slot>
            </div>
            `
        }),
        Vue.component("swiper",{
            template:`
            <div class="swiper">
                <div class="swiper-wrapper">
                    <slot></slot>
                </div>
            <div class="swiper-button-prev"></div>
            <div class="swiper-button-next"></div>
            </div>
            `,
            mounted(){
                console.log("mounted")
                new Swiper ('.swiper', {
                    loop: true, 
                    navigation: {
                        nextEl: '.swiper-button-next',
                        prevEl: '.swiper-button-prev',
                    },
                    autoplay: {
                        delay: 1000,
                        disableOnInteraction: false,
                    },
                }) 
            },
            destroyed(){
                console.log("destroy","第一次创建的 dom 结束了!")
            }
        })
        new Vue({
            el:'#box',
            data:{
                datalist:[]
            },
            mounted(){
                setTimeout(()=>{
                    this.datalist = [
                        'https://mall.s.maizuo.com/bb4e79ef1de07aab2f8ed91b7fd7e731.jpg',
                        'https://mall.s.maizuo.com/90b7581c565efdf1b3ed8127172d9c87.jpg',
                        'https://mall.s.maizuo.com/e753ab0a0709ff8a7048da1c714c5e06.jpg'
                    ]
                },2000)
            },
        })
    </script>
</body>
</html>

3.用指令的方式实现轮播,因为指令可以知道 dom 节点什么时候创建完成。(vue2)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet" href="./swiper-7.4.1/swiper/swiper-bundle.min.css">
    <script src="./vue.js"></script>
    <script src="./swiper-7.4.1/swiper/swiper-bundle.min.js"></script>
    <style>
        .swiper {
            width: 300px;
            height: 150px;
        } 
    </style>
</head>
<body>
    <div id="box">
        <div class="swiper">
            <div class="swiper-wrapper">
                <div class="swiper-slide" v-for = "(items,index) in datalist" :key="items" 
                    v-swiper="{
                        index:index,
                        length:datalist.length
                    }">
                    <img :src="items">
                </div>
            </div>
            <!-- 导航按钮 -->
            <div class="swiper-button-prev"></div>
            <div class="swiper-button-next"></div>
        </div>
    </div>
    <script>
        Vue.directive("swiper",{
            inserted(el,binding){
                console.log(this)
                console.log(el,binding)

                let { 
                    index,length
                } = binding.value

                if(index === length-1){
                    new Swiper ('.swiper', {
                        loop: true, // 循环模式选项
                            // 如果需要前进后退按钮
                        navigation: {
                            nextEl: '.swiper-button-next',
                            prevEl: '.swiper-button-prev',
                        },
                        autoplay: {
                            delay: 1000,
                            disableOnInteraction: false,
                        },
                    })
                }
            }
        })      
        var vm = new Vue({
            el:'#box',
            data:{
                datalist:[]
            },
            mounted(){
                setTimeout(()=>{
                    this.datalist = [
                        'https://mall.s.maizuo.com/bb4e79ef1de07aab2f8ed91b7fd7e731.jpg',
                        'https://mall.s.maizuo.com/90b7581c565efdf1b3ed8127172d9c87.jpg',
                        'https://mall.s.maizuo.com/e753ab0a0709ff8a7048da1c714c5e06.jpg'
                    ]
                },2000)
            }   
        })

    </script>
</body>
</html>

4.用指令的方式轮播(vue3)指令的生命周期 2中的 inserted 换成了 mounted。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet" href="./swiper-7.4.1/swiper/swiper-bundle.min.css">
    <script src="https://cdn.staticfile.org/vue/3.0.5/vue.global.js"></script>
    <script src="./swiper-7.4.1/swiper/swiper-bundle.min.js"></script>
    <style>
        .swiper {
            width: 300px;
            height: 150px;
        } 
    </style>
</head>
<body>
    <div id="box">
        <div class="swiper">
            <div class="swiper-wrapper">
                <div class="swiper-slide" v-for = "(items,index) in datalist" :key="items" 
                    v-swiper="{
                        index:index,
                        length:datalist.length
                    }">
                    <img :src="items">
                </div>
            </div>
            <!-- 导航按钮 -->
            <div class="swiper-button-prev"></div>
            <div class="swiper-button-next"></div>
        </div>
    </div>
    <script>
        var obj = {
            data(){
                return {
                    datalist:[]
                }
            },
            mounted(){
                setTimeout(()=>{
                    this.datalist = [
                        'https://mall.s.maizuo.com/bb4e79ef1de07aab2f8ed91b7fd7e731.jpg',
                        'https://mall.s.maizuo.com/90b7581c565efdf1b3ed8127172d9c87.jpg',
                        'https://mall.s.maizuo.com/e753ab0a0709ff8a7048da1c714c5e06.jpg'
                    ]
                },2000)
            }
        }
        var app = Vue.createApp(obj)
        app.directive("swiper",{
            mounted(el,binding){
                console.log(this)
                console.log(el,binding)

                let { 
                    index,length
                } = binding.value

                if(index === length-1){
                    new Swiper ('.swiper', {
                        loop: true, // 循环模式选项
                            // 如果需要前进后退按钮
                        navigation: {
                            nextEl: '.swiper-button-next',
                            prevEl: '.swiper-button-prev',
                        },
                        autoplay: {
                            delay: 1000,
                            disableOnInteraction: false,
                        },
                    })
                }
            }
        })
        app.mount('#box')
    </script>
</body>
</html>

5.用 nextTick,没有复用性。当前节点状态什么时候更新到dom 就会触发一次。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值