feat(mdAnchor):页面滚动时对应锚点标签跟随高亮;点击锚点标签平滑滚动

This commit is contained in:
sight 2021-12-30 23:20:47 +08:00
parent 0b09de219e
commit 52beb5e9b7

View File

@ -2,29 +2,30 @@
<aside :class="classAside"> <aside :class="classAside">
<div class="lay-aside-top"> <div class="lay-aside-top">
<lay-button <lay-button
@click="handlerBtnClick()"
type="primary" type="primary"
size="xs" size="xs"
:class="classAsideBtn" :class="classAsideBtn"
@click="handlerBtnClick()"
> >
<lay-icon :type="iconType" size="40"> </lay-icon> <lay-icon :type="iconType" size="40"> </lay-icon>
</lay-button> </lay-button>
</div> </div>
<lay-scroll <lay-scroll
class="layui-side-scroll-bar layui-side-scroll::-webkit-scrollbar" > class="layui-side-scroll-bar layui-side-scroll::-webkit-scrollbar"
>
<ul> <ul>
<li <li
v-for="(item, index) in anchorsComput" v-for="(anchor, index) in anchorList"
:key="index" :key="index"
class="lay-aside-list" class="lay-aside-list"
:class="{ active: index === curridx }" :class="{ active: index === activeIndex }"
@click="curridx = index" @click.prevent="handlerListItemClick(index, anchor)"
> >
<a <a
:href="`#${item}`" :href="`#${anchor}`"
class="lay-aside-link" class="lay-aside-link"
:class="{ active: index === curridx }" :class="{ active: index === activeIndex }"
>{{ item }}</a >{{ anchor }}</a
> >
</li> </li>
</ul> </ul>
@ -32,21 +33,25 @@
</aside> </aside>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { computed, ref } from "vue"; import { computed, onMounted, ref, shallowRef } from "vue";
const props = defineProps<{ const props = defineProps<{
anchors?: Array<string> | string; anchors?: Array<string> | string;
currIndex: number; currIndex: number;
show: boolean | string; show: boolean;
}>(); }>();
let curridx = ref(props.currIndex); let activeIndex = ref<number>(0);
const show = ref(props.show); const show = ref<boolean>(props.show);
const iconType = ref("layui-icon-right"); const iconType = ref<string>("layui-icon-right");
const anchor = props.anchors; const anchors: string | string[] | undefined = props.anchors;
/**滚动条高度 */
const scrollTop = ref<number>(0);
/**要监听的滚动元素 */
const scrollRefEl = shallowRef<HTMLElement | undefined>(undefined);
const anchorsComput = computed(() => { const anchorList = computed(() => {
return typeof anchor === "string" ? anchor?.split(",") : anchor; return typeof anchors === "string" ? anchors?.split(",") : anchors;
}); });
const classAside = computed(() => [ const classAside = computed(() => [
@ -63,10 +68,68 @@ const handlerBtnClick = () => {
show.value = !show.value; show.value = !show.value;
iconType.value = show.value ? "layui-icon-right" : "layui-icon-left"; iconType.value = show.value ? "layui-icon-right" : "layui-icon-left";
}; };
const handlerListItemClick = (index: number, id: string) => {
activeIndex.value = index;
scrollToTitle(id);
};
const handlerScroll = () => {
// 90 activeIndex
scrollTop.value = getScrollTop(scrollRefEl.value) + 90;
anchorList.value?.forEach((item, index) => {
const elOffsetTop = document.getElementById(item)?.offsetTop;
if (elOffsetTop) {
if (index === 0 && scrollTop.value < elOffsetTop) {
activeIndex.value = 0;
} else if (scrollTop.value >= elOffsetTop) {
activeIndex.value = index;
}
}
});
}
onMounted(() => {
// TODO hooks
scrollRefEl.value = document.querySelector(".layui-body");
if (!scrollRefEl.value) throw new Error("");
scrollRefEl.value.scrollTop = 0;
scrollRefEl.value?.addEventListener("scroll", throttle(handlerScroll, 500));
});
/**获取滚动高度 */
const getScrollTop = (el: HTMLElement | undefined): number => {
return el
? el.scrollTop
: window.pageYOffset ||
document.documentElement.scrollTop ||
document.body.scrollTop ||
0;
}
/**平滑滚动 */
const scrollToTitle = (id: string): void =>{
document.getElementById(id)?.scrollIntoView({
behavior: "smooth",
block: "start",
inline: "nearest",
});
}
const throttle = (func: Function, wait: number) => {
var timer: any = null;
return (...args: any) => {
if (!timer) {
timer = setTimeout(() => {
timer = null;
func.apply(this, args);
}, wait);
}
};
};
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>
.layui-side-scroll-bar{ .layui-side-scroll-bar {
overflow-y: scroll; overflow-y: scroll;
max-width: 156px; max-width: 156px;
} }
.layui-side-scroll::-webkit-scrollbar { .layui-side-scroll::-webkit-scrollbar {
@ -155,7 +218,7 @@ const handlerBtnClick = () => {
} }
} }
.lay-aside-collapse-btn-collapse { .lay-aside-collapse-btn-collapse {
right:0px; right: 0px;
} }
@media screen and (max-width: 768px) { @media screen and (max-width: 768px) {
@ -171,8 +234,8 @@ const handlerBtnClick = () => {
.lay-aside-list { .lay-aside-list {
max-width: 68px; max-width: 68px;
} }
.layui-side-scroll-bar{ .layui-side-scroll-bar {
max-width: 68px; max-width: 68px;
} }
} }
</style> </style>