zy-smile

vue3项目自己封装的电梯导航组件,快速的实现页面滚动导航

一、实现思路

电梯导航主要是要实现两个功能点:

1. 点击导航滚动页面到指定位置
2. 滚动到页面的位置实现导航的动态更新


使用技术:

  1. 实现1功能使用的js的scrollInfoView语法,让指定元素调用这个方法可以滚动到视图区
  2. 2功能的实现用到了js的IntersectionObserver这个api,通过监听目标元素滚动到视图区的时机,然后实现自己的功能,具体用法可以到MDN上查看。
  

预览地址: static-mp-7dd8d74a-436d-4c1e-a81d-218c2904f2ae.next.bspapp.com/index.htmlh…

二、组件封装

<template>
	<ul
		class="nav-list"
		:style="{
			width: width + 'px',
			...position,
		}"
	>
		<li
			:class="['nav-list-item', activeIndex == index + 1 ? 'active' : '']"
			v-for="(item, index) in list"
			:key="index"
			@click="changeHandle(index)"
		>
			{{ item.label }}
		</li>
	</ul>
</template>

<script setup>
import { reactive, ref, onMounted, toRefs } from "vue"

const props = defineProps({
	position: {
		type: Object,
		default: {
			left: "20px",
			top: "20px",
		},
	},
	width: {
		type: Number,
		default: 120,
	},
	activeColor: {
		type: String,
		default: "#00b393",
	},
	list: {
		type: Array,
		default: [{}],
	},
})
const { list } = toRefs(props)

const activeIndex = ref(1)

function changeHandle(index) {
	activeIndex.value = index + 1
	// 让对应的元素滚动到视图区
	document.getElementById(list.value[index].elId)?.scrollIntoView({
		behavior: "smooth",
	})
}

function changeActive(els) {
	console.log(els)
	if (els[0].isIntersecting) {
		let index = list.value.findIndex(
			(item) => item.elId == els[0].target.id
		)
		if (index != -1) {
			activeIndex.value = index + 1
		}
	}
}
onMounted(() => {
	let observer = new IntersectionObserver(changeActive, {
		root: null,
		threshold: 0.1,
	})

	list.value.map((item) => {
		let el = document.getElementById(item.elId)
		el && observer.observe(el)
	})
})
</script>

<style lang="less" scoped>
.nav-list {
	position: fixed;
	background-color: #fff;
	box-shadow: 0 4px 12px 0 rgba(0, 0, 0, 0.12);
	padding: 10px 0;
	border-radius: 10px;
	.nav-list-item {
		padding: 10px;
		text-align: center;
		background-color: #fff;
		font-size: 16px;
		color: #333;
		cursor: pointer;
		border-radius: 3px;
		list-style: none;
		transition: all 0.2s ease;
		&.active {
			background-color: v-bind(activeColor);
			color: #fff;
		}
	}
}
</style>

三、组件使用

<script setup>
import { reactive } from "vue"
import NavList from "./components/navList.vue"

const navList = reactive([
	{
		label: "一层",
		elId: "el1",
	},
	{
		label: "二层",
		elId: "el2",
	},
	{
		label: "三层",
		elId: "el3",
	},
	{
		label: "四层",
		elId: "el4",
	},
	{
		label: "五层",
		elId: "el5",
	},
])
</script>

<template>
	<NavList :list="navList" :position="{ bottom: '20px', right: '20px' }" />

	<div id="el1" class="el-item">元素一</div>
	<div id="el2" class="el-item">元素2</div>
	<div id="el3" class="el-item">元素3</div>
	<div id="el4" class="el-item">元素4</div>
	<div id="el5" class="el-item">元素5</div>
</template>

<style scoped>
.el-item {
	height: 800px;
	font-size: 30px;
}
</style>

posted on 2023-03-14 15:40  指尖de跃动  阅读(0)  评论(0)    收藏  举报  来源

导航