mand-mobile中的 滚动视图+头部悬停

前言

在业务代码中,我们经常会遇见这样的需求,头部有一个导航,页面上滑过程中,头部导航会吸附到固定区域,并且其显示的内容会随着滚动范围的变化而变化。


头部悬停.png

mand-mobile的引入

这里我们使用vue-cli创建项目,创建完毕后在cmd中输入:

npm install mand-mobile --save

为了简单叙述,我们使用全量引入,在main.js中加入:

import mandMobile from 'mand-mobile'
import 'mand-mobile/lib/mand-mobile.css'
Vue.use(mandMobile)

stylus的引入

由于样式使用的是stylus预处理器,因此我们要引入stylus,在cmd中输入:

cnpm install stylus --save
cnpm install stylus-loader css-loader style-loader --save-dev

代码思路

先对这个需求进行分析,显然,头部导航的内容和滚动是进行联动的,因此要判断当前滚动的范围属于哪一个区域。下面通过视图对思路进行一个分析:


图解.png

首先,我们需要得到每一个scroll-view-category容器,放到一个blocks数组中。然后计算其offsetTopoffsetBottom,将其存入dimensions数组中。在滚动时,只需要判断当前的scrollY在哪一个容器的高度范围内即可。

代码(有注释)

<template>
  <div class="md-example-child md-example-child-scroll-view md-example-child-scroll-view-4">
    <md-scroll-view
      ref="scrollView"
      :scrolling-x="false"
      @scroll="$_onScroll"
    >
      <div
        v-for="i in category"
        :key="i"
        class="scroll-view-category"
      >
        <p class="scroll-view-category-title">{{ i }}</p>
        <div
          v-for="j in list"
          :key="j"
          class="scroll-view-list"
        >
          <p class="scroll-view-item">{{`${i} - ${j}`}}</p>
        </div>
      </div>
    </md-scroll-view>
    <p v-if="activeBlockIndex > -1" class="scroll-view-striky-title">{{ category[activeBlockIndex] }}</p>
  </div>
</template>

<script>
import {ScrollView} from 'mand-mobile'

export default {
  name: 'stickyTitle',
  components: {
    [ScrollView.name]: ScrollView,
  },
  data() {
    return {
      category: [
        '2020-06-08 周一',
        '2020-06-05 周五',
        '2020-06-04 周四',
      ],
      list: [
        '我是2020-06-08的内容',
        '我是2020-06-05的内容',
        '我是2020-06-04的内容',
      ],
      dimensions: [],
      scrollY: 0,
    }
  },
  computed: {
    activeBlockIndex() {
      let activeIndex = -1
      this.dimensions.forEach((dimension, index) => {
        // dimension[0]: offset  &&  dimension[1]: offsetBottom
        if (this.scrollY >= dimension[0] && this.scrollY <= dimension[1]) {
          // activeIndex = index + 1
          activeIndex = index
        }
      })
      return activeIndex
    },
  },
  mounted() {
    // 如果内容发生变化,需重新初始化block和scroller
    this.$_initScrollBlock()
    // this.$refs.scrollView.reflowScroller()
  },
  methods: {
    $_initScrollBlock() {
      const blocks = this.$el.querySelectorAll('.scroll-view-category')
      let offset = 0
      // blocks.forEach((block, index) => {
      // 先把blocks转换成真正的数组,再执行blocks.slice
      Array.prototype.slice.call(blocks).forEach((block, index) => {
        // 计算每一个'.scroll-view-category'的高度
        const innerHeight = block.clientHeight
        // this.$set(Object, key, value)
        // 给每一个'.scroll-view-category'添加一个offsetTop和一个offsetBottom,方便后期进行判断
        this.$set(this.dimensions, index, [offset, offset + innerHeight])
        offset += innerHeight
      })
    },
    $_onScroll({scrollTop}) {
      this.scrollY = scrollTop
    },
  },
}

</script>

<style lang="stylus" scoped>
.md-example-child-scroll-view-4
  position relative
  height 800px
  background #FFF
  .scroll-view-striky-title
    position absolute
    top 0
    left 0
    right 0
    z-index 2
  .scroll-view-category-title, .scroll-view-striky-title
    padding 10px 0
    text-align center
    font-size 32px
    font-family DINAlternate-Bold
    background-color #f0f0f0
  .scroll-view-item
    padding 30px 0
    text-align center
    font-size 32px
    border-bottom .5px solid #efefef
</style>
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。