锚点与页面滚动事件解决方案(H5、小程序)

H5

具体效果如下图,实现效果就是点击上面的标题跳转到相对应区域,滚动到对应区域时候吸顶的标题栏高亮

页面结构

//吸顶的标题栏采用vant组件
<van-sticky scroll="handleStick">
        <div class="combo-detail-warp">
          <div class="detail-item" v-for="(item, index) in arrDetail"
            :class="currentIndex == index ? 'detail-item-active' : ''" @click="setScrollTop(item.key, index)">
            {
    
    {
    
     item.title }}
          </div>
        </div>
      </van-sticky>

//富文本区域
    <div class="rich-wrap">
      <div v-for="(item, index) in arrDetail" class="detail-info" :id="item.key">
        <div class="detail-info-title">
          <div class="line"></div>
          <div>{
    
    {
    
     item.title }}</div>
          <div class="line"></div>
        </div>
        <div class="z-rich-text">
          <div class="rich-box" v-html="item.img"></div>
        </div>
      </div>
    </div>

js逻辑处理

//首先自定义标题栏
data(){
    
    
	return{
    
    
		arrDetail: [
        {
    
     title: "商品详情", img: "0", key: "productDetail" },
        {
    
     title: "项目", img: "1", key: "project" },
        {
    
     title: "预约须知", img: "2", key: "bookInformation" },
      ]
	}
}

//接口数据赋值
this.arrDetail[0].img = getWriteTextMini(data.goodsDetail);
this.arrDetail[1].img = getWriteTextMini(data.goodsSpecification);
this.arrDetail[2].img = getWriteTextMini(data.goodsService);
//在vue中监听滚动事件注册
mounted() {
    
    
    window.addEventListener("scroll", this.onPageScroll); 
    // 监听滚动事件,然后用onPageScroll这个方法进行相应的处理
  },
  
//点击标题栏的锚点事件
//点击跳转商品详情富文本区域
    setScrollTop(key, index) {
    
    
      // this.currentIndex = index;
      //采用key值作为富文本区域的id值,当点击相对应的标题时候,就跳转到相应区域
      let PageId = document.querySelector(`#${
      
      key}`);
      // 打印出对应页面与窗口的距离
      // widow 根据浏览器滚动条,如果你是要在某个盒子里面产生滑动,记得修改
      window.scrollTo({
    
    
        top: PageId.offsetTop,
        behavior: "smooth",
      });
    },
  
 //页面滚动事件
 //滚动监听
    onPageScroll() {
    
    
      //多种方式获取窗口滚动高度
      let scrollTop =
        window.pageYOffset ||
        document.documentElement.scrollTop ||
        document.body.scrollTop;
      //分别获取各个区域窗口高度
      let productDetail = document.querySelector("#productDetail");
      let project = document.querySelector("#project");
      let bookInformation = document.querySelector("#bookInformation");
      //当当前窗口滚动高度小于第二个内容区域时候,第一个标题高亮
      if (scrollTop < project.offsetTop) {
    
    
        this.currentIndex = 0;
      } else if (
        scrollTop < bookInformation.offsetTop &&
        scrollTop >= project.offsetTop
      ) {
    
    
        this.currentIndex = 1; //当当前窗口滚动高度小于第三个内容区域大于第二个时候,第二个标题高亮
      } else if (scrollTop >= bookInformation.offsetTop) {
    
    
        this.currentIndex = 2; //当当前窗口滚动高度大于第三个内容区域第三个标题高亮
      }
    },
//最后,页面卸载时候注销滚动监听事件
destroyed() {
    
    
    // 离开该页面需要移除这个监听的事件,不然会报错
    window.removeEventListener("scroll", this.onPageScroll);
  },

小程序

页面结构

//一样的,采用的vant吸顶组件
<van-sticky scroll="handleStick">
      <view class="combo-detail-warp">
        <view class="detail-item {
    
    {currentIndex==index?'detail-item-active':''}}" wx:for="{
    
    {arrDetail}}" wx:key="index" bindtap="setScrollTop" data-hash="{
    
    {item.key}}" data-index="{
    
    {index}}">
          {
    
    {
    
    item.title}}
        </view>
      </view>
    </van-sticky>

//富文本区域
<view class="rich-wrap">
    <view wx:for="{
    
    {arrDetail}}" wx:key="index" class="detail-info" id="{
    
    {item.key}}">
      <view class="detail-info-title">
        <view class="line"></view>
        <view>{
    
    {
    
    item.title}}</view>
        <view class="line"></view>
      </view>
      <view class="z-rich-text">
        <rich-text nodes="{
    
    {item.img}}" class="rich-box"></rich-text>
      </view>
    </view>
  </view>

js逻辑

data:{
    
    
	 arrDetail: [
            {
    
    title: '商品详情', img: '0', key: 'productDetail',},
            {
    
    title: '项目', img: '1', key: 'project',},
            {
    
    title: '预约须知', img: '2', key: 'bookInformation',},
        ],
}
//接口获取到数据赋值
arrDetail: [
	{
    
    title: '商品详情', img: getWriteTextMini(data.goodsDetail), key: 'productDetail',},
	{
    
    title: '规格参数', img: getWriteTextMini(data.goodsSpecification), key: 'project',},
	{
    
    title: '服务', img: getWriteTextMini(data.goodsService), key: 'bookInformation',},
]

 //点击标题滚动
 //小程序中,wx.createSelectorQuery()获取到的是一个数组
    setScrollTop(e) {
    
    
        let nav = e.currentTarget.dataset.index;
        const query = wx.createSelectorQuery();
        query.select('#first').boundingClientRect();
        query.select('#productDetail').boundingClientRect();
        query.select('#project').boundingClientRect();
        query.select('#bookInformation').boundingClientRect();
        query.selectViewport().scrollOffset();
        query.exec((res) => {
    
    
            if (nav === 0) {
    
    
                wx.pageScrollTo({
    
    
                    scrollTop: res[0].height - 52,
                    //52为根据实际情况的修正高度值,非必要
                });
            } else if (nav === 1) {
    
    
                wx.pageScrollTo({
    
    
                    scrollTop: res[0].height + res[1].height - 52
                });
            } else if (nav === 2) {
    
    
                wx.pageScrollTo({
    
    
                    scrollTop: res[0].height + res[1].height + res[2].height - 52
                });
            }
        });
    },

//滚动监听
    onPageScroll(e) {
    
    
        const query = wx.createSelectorQuery();
        query.select('#first').boundingClientRect();
        query.select('#productDetail').boundingClientRect();
        query.select('#project').boundingClientRect();
        query.select('#bookInformation').boundingClientRect();
        query.exec((res) => {
    
    
            if (res[1].top <= 52 && res[2].top > 53) {
    
    
                this.setData({
    
    
                    currentIndex: 0
                });
            } else if (res[2].top <= 53 && res[3].top >53) {
    
    
                this.setData({
    
    
                    currentIndex: 1
                });
            } else if (res[3].top <= 53) {
    
    
                this.setData({
    
    
                    currentIndex: 2
                });
            }
        });
    },

富文本处理函数

/**
 * 富文本重写
 * @param {String|Number} richText 富文本
 */
export function getWriteTextMini(richText) {
    
    
    if (richText) {
    
    
        richText = richText.replace(/blob:/gi, '');
        //删除空的style属性,避免因为和已有的style属性冲突导致不显示
        richText = richText.replace(/style=""/gi, '');
        richText = richText.replace(/<img/gi, '\<img class="w-img"');
        //视频
        richText = richText.replace(/<video/gi, '\<video class="w-video"');
    }
    return richText;
}

猜你喜欢

转载自blog.csdn.net/qq_45659769/article/details/126163995