el-steps步骤条结合锚点实现页面滚动定位
需求描述:给页面加个导航定位条,页面滚动到某个模块时,右侧步骤条跟着滚动,相反之,点击导航步骤条的某个模块,页面可定位到相应模块
实现效果如图:(因为公司项目不便于录制gif视频)
element中的步骤条没有任何点击事件,只是起到一个展示的作用,由于其它页面也有用到,便封装成了一个公共的组件
step中的代码:
<template>
<div class="step">
<div style="height: 180px; position: relative">
<el-steps direction="vertical" :active="current">
<el-step
:title="item.stepTitle"
v-for="(item, index) in stepInfo"
:key="index"
icon="el-icon-success"
>
</el-step>
</el-steps>
<!-- steps绑定不上任何点击事件,给了相应数据的span便签覆盖上,可以绑定点击事件 -->
<span
class="stepIndex"
v-for="(itemId, indexID) in stepInfo"
:key="itemId.stepId"
@click="jumpPage(itemId.stepId)"
:class="'step' + indexID"
></span>
</div>
</div>
</template>
<script>
import { mount } from "@vue/test-utils";
export default {
name: "common-step",
props: {
// stepInfo是每一个步骤的信息,格式如下(stepID是每个模块的类名以便获取dom)
// stepInfo: [
// {
// stepTitle: "基本信息",
// stepId: "baseinfo",
// },
// {
// stepTitle: "配置规则",
// stepId: "ruleinfo",
// },
// {
// stepTitle: "生成任务列表",
// stepId: "taskinfo",
// },
// ],
stepInfo: {
type: Array,
default: () => [],
},
// 当前步骤条的滚动位置
current: {
type: Number,
default: () => 1
}
},
data () {
return {
};
},
methods: {
jumpPage (domId) {
// 当前窗口正中心位置到指定dom位置的距离
//页面滚动了的距离
let height =
window.pageYOffset ||
document.documentElement.scrollTop ||
document.body.scrollTop;
//指定dom到页面顶端的距离
let dom = document.getElementById(domId);
let domHeight = dom.offsetTop;
// //滚动距离计算
let distance = Number(height) - Number(domHeight);
// //判断上滚还是下滚
if (distance < 0) {
//向下滚动
distance = Math.abs(distance);
this.$emit("scrollBy", { top: distance, behavior: 'smooth' });
} else if (distance == 0) {
//页面不滚动
this.$emit("scrollBy", { top: 0, behavior: 'smooth' });
} else {
//向上滚动
distance = -distance;
this.$emit("scrollBy", { top: distance, behavior: 'smooth' });
}
},
},
};
</script>
<style lang="scss" scoped>
.step {
position: fixed;
right: 3%;
font-size: 14px;
}
.stepIndex {
position: absolute;
z-index: 3;
width: 100%;
height: 28px;
}
.step0 {
top: 0;
}
.step1 {
top: 76px;
}
.step2 {
top: 152px;
}
::v-deep .el-step__head.is-wait {
color: #303133;
border-color: #303133;
}
::v-deep .el-step__title.is-wait {
color: #303133;
font-weight: bold;
font-size: 14px;
}
::v-deep .is-process,
::v-deep .is-finish {
font-size: 14px;
}
::v-deep .el-icon-success {
font-size: 16px !important;
}
</style>
父组件中使用
这里的current是控制步骤条滚动的,我放到了父组件里面,因为我这里要监听到父组件页面的滚动任何实现current的增减
父组件里面mounted和beforedestroyed中监听滚动
mounted () {
// 获取滚动部分的dom元素
const dom_html = this.$refs.scrolldom.$refs.wrap;
dom_html.addEventListener("scroll", this.getScrollId);
},
beforedestroyed () {
const dom_html = this.$refs.scrolldom.$refs.wrap;
dom_html.removeEventListener("scroll", this.getScrollId);
},
// dom滚动监听事件
getScrollId () {
this.current = 0;
const dom_one = document.getElementById("baseinfo").offsetTop;
const dom_two = document.getElementById("ruleinfo").offsetTop;
const dom_three = document.getElementById("taskinfo").offsetTop;
const sroll_top = this.$refs.scrolldom.$refs.wrap.scrollTop;
//目前导航只有三个,就用了最笨的if判断来写了
if (sroll_top < dom_two) {
this.current = 1;
} else if (sroll_top === dom_two || sroll_top < dom_three) {
this.current = 2;
} else {
this.current = 3;
}
},
// 获取步骤条点击事件定位到相应模块
scrollBy (params) {
const dom_html = this.$refs.scrolldom.$refs.wrap;
this.$nextTick(() => {
dom_html.scrollTop = params.top;
});
},
至此效果已经实现了