背景
前不久有个需求,上半部分是el-step步骤条,下半部分是一些文字说明,需要实现点击步骤条中某个步骤自定义定位到对应部分的文字说明,同时滚动内容区域的时候还要自动选中对应区域的步骤。element-ui-plus的有锚点这个组件,但是他的触发内容是三个div,我的是一个组件,所以当时就没用这个,直接就重写了。
实现:
在el-step上添加click事件
// 使用scroll来滚动到对应的内容区域
const scroll = (stepNumber: number) => {
// contentRef为对应的内容区域上的ref
const targetElement = contentRef.value[stepNumber];
if (targetElement) {
nextTick(() => {
targetElement.scrollIntoView({
behavior: 'smooth',
block: 'start',
});
});
}
};
使用html5的API - IntersectionObserver来实现监听滚动区域,然后给对应区域的step赋值。
在onmounted中调用方法去new IntersectionObserver();
onMounted(() => {
initObserver();
});
// 监听滚动
const initObserver = () => {
const observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
const index = contentRef.value.findIndex(
(el: any) => el === entry.target,
);
// activeStep就是el-steps上绑定的:active
if (index !== -1) {
activeStep.value = index;
}
}
});
},
// rootRef就是对应滚动内容的父容器的ref
{
root: rootRef.value, // 监听tip里的视口
threshold: 0.9, // 90%进入视图时才触发
},
);
contentRef.value.forEach((el: any) => observer.observe(el));
};
html结构
<div>
<el-steps :active="activeStep">
<el-step
v-for="(item, index) in steps"
:key="index"
:title="item.title"
@click.native="scroll(index)"
>
</el-step>
</el-steps>
</div>
<div ref="rootRef">
<div
v-for="(img, index) in imgs"
:key="index"
class="imgContainer"
ref="contentRef"
>
<img :src="img.src"/>
</div>
</div>