zoukankan      html  css  js  c++  java
  • 用Vue来实现音乐播放器(10):Scroll组件的抽象和应用

    了解better-scroll什么时候是需要refresh计算的??通常我们遇到的better-scroll不能滚动的问题的根源是什么??better-scroll的渲染原理是:根据初始化的时机  或者调用refresh()的时机的那个时候的scroll的父元素的高度和子元素的高度之差去做一个计算  计算出他可以滚动的位置  所以我们去实例化或者refresh这个scroll的时候  一定要保证  这个dom是已经渲染好的 我们能正确计算到高度的

    如果我们有数据变化以及dom变化的场景的时候  我们一定要去让better-scroll重新refresh()  然后我们封装了scroll组件之后  我们就不用在外部掉获取到数据之后 再this.$refs.scroll.refresh()  我们只需要把数据传递给scroll  scroll就能监听到数据变化  scroll组件就能自己计算高度

    <template>
        <div class="recommend">
            <scroll class="recommend-content">
                <!-- //scroll插件作用于他的第一个子元素 -->
                <!-- 局部轮播的父级 -->
                <div>
    
                <div class="slider-wrapper" v-if="recommend.length">  //这里也是为了在初始化实例和refresh()之前确保dom已经渲染好了
                    <slider>
                        <!-- 填写插槽 -->
                        <div v-for="(item,index) in recommend" :key="index">
                            <a :href="item.linkUrl">
                                <img :src="item.picUrl">
                            </a>
                        </div>
                    </slider>
                </div>
                <div class="recommend-list">
                    <h1 class="list-title">热门歌单推荐</h1>
                    <div class="mod-playlist">
                    <ul class="playlist-list">
                        <li v-for="(item,index) in discList" :key="index" class="playlist-item">
                            <div class="playlist-item-box">
                                <div class="playlist-cover mod-cover">
                                    <a href="#">
                                        <img :src="item.imgurl" class="pic">
                                    </a>
                                </div>
                                <h4 class="playlist-title">
                                    <span class="playlist-title-txt">{{item.dissname}}</span>
                                </h4>
                                <div class="playlist-author">
                                    <a href="#">{{item.creator.name}}</a>
                                </div>
                            
                            </div>
                            
    
                        </li>
                    </ul>
                    </div>
                </div>
    
                </div>
            </scroll>
        </div>
    </template>
    <script>
    
        import Scroll from '../../base/scroll/scroll.vue'
        import Slider from '../../base/slider/slider.vue'
        import {getRecommend,getDiscList} from '../../api/recommend.js'
        import { ERR_OK } from '../../api/config.js'
    
    export default {
        data(){//为了将实例里面的轮播图数据与dom相关  要有一个data()方法
            return {
                recommend:[],
                discList:[]
            }
    
        },
        created(){//一般在这个生命钩子里面加载数据
            this._getRecommend(),
            this._getDiscList()
        },
        methods:{
            _getRecommend(){
                getRecommend().then((res)=>{//这个res就是我们抓取到的数据对象
                    if(res.code===ERR_OK){
                        // console.log(res.data.slider)
                        this.recommend=res.data.slider
                    }
                })
    
            },
            _getDiscList(){
                getDiscList().then((res)=>{
                    if(res.code===ERR_OK){
                        // console.log(res.data.list)
                        this.discList=res.data.list
                    }
                })
            },
        },
            
        components:{
            Slider,Scroll
        }
    }
    <template>
        <div ref="wrapper">
            <slot></slot>
        </div>
    </template>
    
    <script>
    
    //将better-scroll相关都放在这里  可以实现代码的复用
    
    import BScroll from 'better-scroll'
    
    export default {
        props: {
            probeType: {
                type: Number,
                default: 1
            },
            click: {
                type: Boolean,
                default: true
            },
            data: {//因为我们是滚动的  所以数据会改变  需要一个数组来监听发生的数据变化  从而可以refresh()scroll之后 重新计算滚动的高度
                type:Array,
                default:null 
            }
        },
    
     
    //vue在mounted()这个生命周期钩子里面加载dom到页面上 一般在这个钩子里面还可以初始化插件 以及操作dom
    
    //要写个定时器,,因为一般数据的请求是异步的 那么异步的数据请求和同样也是异步的mounted()的顺序是什么呢? 
    //可能是mounted()先执行 那么就会在数据更新之前将dom挂载了 这样会产生虚拟dom 
    //所以我们要保证dom的挂载是在数据更新之后 所以使用setTimeout() 或者是this.$nextTick
    //可以用nextTick 将回调延迟到下次dom更新循环之后执行 在修改数据之后立即使用它,然后等待dom更新 //浏览器渲染一般是17ms 这里延迟到20ms 
    
    mounted(){
      setTimeout(()=>{
        this._initScroll(); 
    
    //better-scroll的渲染原理是 
    
    //根据初始化的时机  或者调用refresh()的时机的那个时候的scroll的父元素的高度和子元素的高度之差去做一个计算  
    //计算出他可以滚动的位置  所以我们去实例化或者refresh这个scroll的时候  一定要保证  这个dom是已经渲染好的 我们能正确计算到高度的
    //所以我们在这里一定要保证我们能计算到正确的高度  因此我们要判断一下  此时dom有没有渲染好  在recommend.vue组件中确认 
        },20)
        },
        methods:{
            _initScroll(){
                //在这里先判断一下this.$refs.wrapper是不是undefined
                //如果是undefined 那么BScroll类由于第一个参数为undefined会报错
                if(!this.$refs.wrapper){
                    return
                }
                this.scroll=new BScroll(this.$refs.wrapper,{
                    probeType:this.probeType,
                    click:this.click
                })
            },
            enable(){
                this.scroll&&this.scroll.enable()
            },
            disable(){
                this.scroll&&this.scroll.disable()
            },
            refresh(){
                this.scroll&&this.scroll.refresh()
            }
        },
        //监控data的变化  如果data变化了 刷新scroll
        watch:{
            data(){
                setTimeout(()=>{
                    //这里也是操作dom 只要涉及到操作dom就需要延迟
                    this.refresh()
                },20)
            }
        }
    }
    </script>
    
    <style lang="stylus" scoped>
    
    </style>

    完成以上这些操作 scroll组件已经初始化了  但是并不能滚动 这是因为  我们初始化这个scroll插件的时机是在scroll.vue组件中的mounted()里面初始化到的  然而我的scroll插件里面的数据是动态渲染拿到的 也就是一个异步操作  即mounted()挂载的前提是 也可以说是实例化或者是refresh()这个插件的前提是   动态获取到数据之后  将dom撑开了之后 能够计算到滚动的高度差之后  在挂载到页面 然后此时我们重新计算scroll 然后调用this.refresh()

    才能让scroll正确的滚动

    那么我们在recommend.vue中就要确保一下有数据  或者是直接父传子一个data属性  如果recommend.vue中的数据变化了  就会触发scroll.vue中的高度改变

    <template>
        <div class="recommend">
            <!-- 这里的data可以看成是父传子的属性 即<scroll>组件中的props属性下的data
                当这里的data改变了的话 scroll组件的data也会改变 因为监听(watch)了data 所以data改变之后就会刷新scroll
                即重新计算滚动的高度等等
                如果这里先没有传一个data过去 那么我们可能在初始化scroll组件里面的时候可能拿不到数据 如果没有数据
                那么scroll组件可能认为不需要滚动
            -->
            
            <scroll class="recommend-content" :data="discList" ref="scroll">
                <!-- //scroll插件作用于他的第一个子元素 -->
                <!-- 局部轮播的父级 -->
                <div>
    
                <!-- 注意这里要写当轮播图的数据都拿到了之后  即slider.vue组件里面的mounted()方法能执行成功之后
                    执行下面操作
                 -->
    
                <!-- 因为我们的recommend是通过异步拿到的 可能会有延时 但是如果不加上v-if的话 我们可能在没有拿到数据的情况下就
                    把插槽插入进去了 那么slider.vue里面的mounted()也就执行了
                -->
                <div class="slider-wrapper" v-if="recommend.length">
                    <slider>
                        <!-- 填写插槽 -->
                        <div v-for="(item,index) in recommend" :key="index">
                            <a :href="item.linkUrl">
                                <img :src="item.picUrl" @load="loadImage" class="needsclick">
                            </a>
                        </div>
                    </slider>
                </div>
                <div class="recommend-list">
                    <h1 class="list-title">热门歌单推荐</h1>
                    <div class="mod-playlist">
                    <ul class="playlist-list">
                        <li v-for="(item,index) in discList" :key="index" class="playlist-item">
                            <div class="playlist-item-box">
                                <div class="playlist-cover mod-cover">
                                    <a href="#">
                                        <img v-lazy="item.imgurl" class="pic">
                                    </a>
                                </div>
                                <h4 class="playlist-title">
                                    <span class="playlist-title-txt">{{item.dissname}}</span>
                                </h4>
                                <div class="playlist-author">
                                    <a href="#">{{item.creator.name}}</a>
                                </div>
                            
                            </div>
                            
    
                        </li>
                    </ul>
                    </div>
                </div>
    
                </div>
            </scroll>
        </div>
    </template>
  • 相关阅读:
    jQuery 选择器
    http statusCode(状态码)含义
    JS实现拖拽效果
    Sql Service中的分页
    SQL Server中一些不常见的查询
    游标的基本写法
    doT.js
    关于GridView中控件的问题
    Sql Server创建函数
    ASP.NET中Ajax的用法
  • 原文地址:https://www.cnblogs.com/catbrother/p/9180900.html
Copyright © 2011-2022 走看看