美文网首页我爱编程
「Vue」点击滚动页面与$nextTick问题解决

「Vue」点击滚动页面与$nextTick问题解决

作者: HughDong | 来源:发表于2018-05-13 22:17 被阅读0次

    这一篇主要讲述今天使用Vue点击滚动的实现
    以及Vue在页面渲染未完成时滚动偏移的问题

    页面结构

    添加滚动前页面的基本结构



    点击标题时触发绑定样式.table-display,当前点击显示的表格为display:table;其他详情表格为display:none;
    监听点击事件触发方法修改标识,控制样式的绑定。

    <template>
        <!-- 略 -->
            <style>
                .table-display {display: table;}
            </style>
            <ul>
                <li v-for="(item,index) in detailsList">
                    <div class="text-wrap">
                        <a class="title-list" @click="showDetails(index)" ref="listshow">
                            {{item.title}}
                          </a>
                    </div>
                    <table class="table b-table table-striped" v-bind:class="{'table-display':showIndex==index}">
                        <!-- 略 -->
                    </table>
                </li>
            </ul>
        <!-- 略 -->
    </template>
    <script>
      export default{
        data(){
          return {
            showIndex: null,
          }
        },
        methods: {
          showDetails: function (index) {
            if (this.showIndex == index) {
              this.showIndex = null
            } else {
              this.showIndex = index
            }
          },
        }
      }
    </script>
    

    实现思路

    使用 vue注册子组件 来捕获点击的当前元素

    <!-- 略 -->
      <a class="title-list" @click="showDetails(index)" ref="listshow">{{item.title}}</a>
    <!-- 略 -->
    <script>
      // ...
      methods: {
        showDetails: function (index) {
          console.log(this.$refs.listshow[index])
        },
      }
      // ...
    </script>
    

    使用 js 的 scrollTo 方法来实现滚动到元素

    // element:获取到的要滚动到顶部的元素
    window.scrollTo({"behavior": "smooth", "top": element.offsetTop})
    

    将滚动事件直接添加到方法中去后出现滚动偏移的问题
    !](https://img.haomeiwen.com/i12008559/965f1b2ad7df6c38.gif?imageMogr2/auto-orient/strip)
    查找问题的过程就此略过,得到的结论是:

    在上一个 table 样式 {display:none} 与新的 table 样式 {display:table} 重新渲染完成之前
    scrollTo() 事件就用错误 offsetTop 属性来计算滚动的位置了。
    那么我们需要在渲染完成后再开始滚动。

    使用 setTimeOut() 来测试结果是可行的

    showDetails: function (index) {
      if (this.showIndex == index) {
        this.showIndex = null
      } else {
        this.showIndex = index
      }
      setTimeout(()=>{
        window.scrollTo({"behavior": "smooth", "top": this.$refs.listshow[index].offsetTop})
      },0)
    },
    

    查到 Vue 官方提供了回调方法 $nextTick
    作用是将回调延迟到下次 DOM 更新循环之后执行。在修改数据之后立即使用它,然后等待 DOM 更新。
    修改后的方法如下

    showDetails: function (index) {
      if (this.showIndex == index) {
        this.showIndex = null
      } else {
        this.showIndex = index
      }
      this.$nextTick(function () {
        window.scrollTo({"behavior": "smooth", "top": this.$refs.listshow[index].offsetTop})
      })
    },
    

    最终实现效果


    一些题外话

    在找问题的过程中一度想把 JQuery 和 Vue 混用,但总归感觉不是滋味。
    @哔哔肾一句话点醒了我:附出处

    DOM就是一盘菜,用刀叉用筷子勺子都一样吃。

    相关文章

      网友评论

        本文标题:「Vue」点击滚动页面与$nextTick问题解决

        本文链接:https://www.haomeiwen.com/subject/dmjrdftx.html