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;
}