vue2写法
<template>
<div style="height: 20000px">
<div style="height: 300px; width: 100%; background-color: lightpink"></div>
<div class="nav" :class="{ 'fix-nav': navBarFixed }">
<div class="outside">
<div
class="inside"
:class="{ active: inside1 }"
@click="clickPan('content1')"
>
<span>内容1导航</span>
</div>
<div
class="inside"
:class="{ active: inside2 }"
@click="clickPan('content2')"
>
<span>内容2导航</span>
</div>
</div>
</div>
<div class="content1" id="content1">
<div
style="
height: 300px;
width: 100%;
background-color: lightyellow;
padding-top: 30px;
text-align: center;
"
>
这是一块内容1
</div>
</div>
<div class="content2" id="content2">
<div
style="
height: 300px;
width: 100%;
background-color: lightblue;
padding-top: 30px;
text-align: center;
"
>
这是一块内容2
</div>
</div>
</div>
</template>
<script>
export default {
data () {
return {
inside1: true,
inside2: false,
navBarFixed: false
}
},
mounted () {
window.addEventListener('scroll', this.watchScroll)
},
beforeDestroy () {
window.removeEventListener('scroll', this.watchScroll)
},
methods: {
clickPan (position) {
// document.getElementById(position).scrollIntoView({
// behavior: "smooth",
// block: "start"
// });
const targetElem = document.getElementById(position)
let targetElemPosition = targetElem.offsetTop - 72
if (this.navBarFixed === false && position === 'content1') {
targetElemPosition = targetElemPosition - 1
}
if (this.navBarFixed === false && position === 'content2') {
targetElemPosition = targetElemPosition - 72
}
let scrollTop =
window.pageYOffset ||
document.documentElement.scrollTop ||
document.body.scrollTop
const step = function () {
const distance = targetElemPosition - scrollTop
scrollTop = scrollTop + distance / 4
if (Math.abs(distance) < 1) {
window.scrollTo(0, targetElemPosition)
} else {
window.scrollTo(0, scrollTop)
setTimeout(step, 30)
}
}
step()
},
watchScroll () {
const scrollTop =
window.pageYOffset ||
document.documentElement.scrollTop ||
document.body.scrollTop
const offsetTop = document.querySelector('.content1').offsetTop - 72
if (scrollTop >= offsetTop) {
this.navBarFixed = true
} else {
this.navBarFixed = false
}
if (scrollTop < document.querySelector('.content2').offsetTop - 72) {
this.inside1 = true
this.inside2 = false
} else {
this.inside2 = true
this.inside1 = false
}
}
}
}
</script>
<style lang="scss" scoped>
.outside {
margin: auto;
width: 400px;
height: 100%;
span {
position: relative;
}
.inside {
line-height: 70px;
text-align: center;
margin: auto;
width: 200px;
height: 100%;
float: left;
cursor: pointer;
span::before {
content: "";
position: absolute;
height: 3px;
top: 47.5px;
background: #3054eb;
width: 100%;
opacity: 0;
transition: all 0.8s ease;
}
}
.active {
color: #1890ff;
span::before {
opacity: 1;
}
}
.inside:hover {
color: #1890ff;
}
}
.fix-nav {
position: fixed;
z-index: 1;
top: 0;
height: 70px;
width: 100%;
font-size: 1.3em;
background-color: white;
border-bottom: 2px solid #f2f2f2;
}
.nav {
height: 70px;
width: 100%;
font-size: 1.3em;
background-color: white;
border-bottom: 2px solid #f2f2f2;
}
</style>
vue3写法
<template>
<div style="height: 200px">
<div style="height: 500px; width: 100%; background-color: lightpink"></div>
<div class="nav" :class="{ 'fix-nav': navBarFixed }">
<div class="outside" v-for="(item, index) in navdata" :key="index">
<div class="inside" :class="{ active: inside }" @click="clickPan(item.content)">
<span>{{ item.navname }}</span>
</div>
<!-- <div class="inside" :class="{ active: inside2 }" @click="clickPan('content2')">
<span>内容2导航</span>
</div> -->
</div>
</div>
<div >
<div class="content1" id="content1">
<div style="
height: 300px;
width: 100%;
background-color: lightyellow;
padding-top: 30px;
text-align: center;
">
这是一块内容1
</div>
</div>
<div class="content2" id="content2">
<div style="
height: 300px;
width: 100%;
background-color: lightblue;
padding-top: 30px;
text-align: center;
">
这是一块内容2
</div>
</div>
<div class="content3" id="content3">
<div style="
height: 300px;
width: 100%;
background-color: yellowgreen;
padding-top: 30px;
text-align: center;
">
这是一块内容3
</div>
</div>
<div id="content4">
<div style="
height: 300px;
width: 100%;
background-color: pink;
padding-top: 30px;
text-align: center;
">
这是一块内容4
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted, onUnmounted, reactive } from 'vue';
// let inside = ref(true);
// let inside2 = ref(false);
let navBarFixed = ref(false);
// let scrollTop = ref(0);
const navdata = reactive([{
navname: 'name1',
navcontent: '11111',
content:'content1',
}, {
navname: 'name2',
navcontent: '2',
content:'content2',
},
{
navname: 'name3',
navcontent: '3',
content:'content3',
},
{
navname: 'name4',
navcontent: '444',
content:'content4',
},])
onMounted(() => {
window.addEventListener("scroll", watchScroll);
});
onUnmounted(() => {
window.removeEventListener("scroll", watchScroll);
});
const clickPan = (position: any) => {
const targetElem = document.getElementById(position);
let targetElemPosition = targetElem.offsetTop - 72;
if (!navBarFixed.value && position === 'content1') {
targetElemPosition = targetElemPosition - 1;
}
if (!navBarFixed.value && position === 'content2') {
targetElemPosition = targetElemPosition - 72;
}
console.log('targetElemPosition',targetElemPosition)
let scrollTop =
window.pageYOffset ||
document.documentElement.scrollTop ||
document.body.scrollTop;
const step = function () {
let distance = targetElemPosition - scrollTop;
scrollTop = scrollTop + distance / 4;
console.log('scrollTop',scrollTop,'distance',distance)
if (Math.abs(distance) < 1) {
window.scrollTo(0, targetElemPosition);
} else {
window.scrollTo(0, scrollTop);
setTimeout(step, 30);
}
};
step();
};
// 是否固定导航
const watchScroll = () => {
var scrollTop =
window.pageYOffset ||
document.documentElement.scrollTop ||
document.body.scrollTop;
var offsetTop = document.querySelector(".content1").offsetTop - 72;
if (scrollTop >= offsetTop) {
navBarFixed.value = true;
} else {
navBarFixed.value = false;
}
// if (scrollTop < document.querySelector(".content2").offsetTop - 72) {
// inside.value = true;
// } else {
// inside.value = false;
// }
}
</script>
<style lang="scss" scoped>
.outside {
display: flex;
justify-content: space-evenly;
margin: auto;
// width: 400px;
height: 100%;
span {
position: relative;
}
.inside {
line-height: 70px;
text-align: center;
margin: auto;
// width: 200px;
height: 100%;
float: left;
cursor: pointer;
span::before {
content: '';
position: absolute;
height: 3px;
top: 47.5px;
background: #3054eb;
width: 100%;
opacity: 0;
transition: all 0.8s ease;
}
}
.active {
color: #1890ff;
span::before {
opacity: 1;
}
}
.inside:hover {
color: #1890ff;
}
}
.fix-nav {
position: fixed;
z-index: 1;
top: 0;
height: 70px;
width: 100%;
font-size: 1.3em;
background-color: white;
border-bottom: 2px solid #f2f2f2;
}
.nav {
display: flex;
justify-content: space-evenly;
height: 70px;
width: 100%;
font-size: 1.3em;
background-color: white;
border-bottom: 2px solid #f2f2f2;
}
</style>