<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>01.滚动</title>
<script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.13/vue.js"></script>
<style>
* {
margin: 0;
padding: 0;
}
#app>.contain {
width: 500px;
height: 200px;
border: 1px solid #ccc;
margin: 100px auto;
display: flex;
flex-direction: column;
}
#app>.contain>.tab-title-wrap {
display: flex;
height: 30px;
align-items: center;
justify-content: space-around;
border-bottom: 1px solid #000;
}
#app>.contain>.tab-title-wrap>h3 {
flex: 1;
text-align: center;
cursor: pointer;
}
#app>.contain>.tab-title-wrap>.acitve {
background-color: aqua;
color: orangered;
}
#app>.contain>.tab-content {
flex: 1;
overflow-y: auto;
position: relative;
}
#app>.contain>.tab-content>.item {
display: flex;
align-items: center;
justify-content: space-around;
font-size: 30px;
}
#app>.contain>.tab-content>.item:nth-child(odd) {
background-color: aquamarine;
}
</style>
</head>
<body>
<div id="app">
<div class="contain">
<div class="tab-title-wrap">
<h3 v-for="(tab, idx) in tabs" :name="tab.name" :id="tab.name" :class="{acitve: idx === curIdx}"
@click="clickHandler(idx)">{{tab.title}}</h3>
</div>
<div class="tab-content" ref="content" @scroll="scroll">
<div class="item" v-for="(tab, idx) in tabs" ref="tab" :name="tab.name" :id="tab.name"
:style="{height: tab.height + 'px'}">{{tab.title}}</div>
</div>
</div>
</div>
<script>
function getDir(dom) {
const dir = dom.scrollTop > (dom.preScrollTop || 0) ? 'up' : 'down';
dom.preScrollTop = dom.scrollTop;
return dir;
}
new Vue({
el: '#app',
data() {
return {
tabs: [
{ title: 'HTML', name: 'html', height: 250 },
{ title: 'CSS', name: 'css', height: 40 },
{ title: 'JS', name: 'javascript', height: 60 },
{ title: 'Vue', name: 'vue', height: 200 },
{ title: 'React', name: 'react', height: 300 },
{ title: 'Angular', name: 'angular', height: 260 },
],
curIdx: 0,
isScroll: false,
isClick: false,
num: 1,
obj: {}
};
},
methods: {
clickHandler(idx) {
if (this.isScroll) return;
this.isClick = true;
this.isScroll = true;
const target = this.$refs.tab[idx].offsetTop;
const content = this.$refs.content;
let start = content.scrollTop;
let step = (target - start) / 10;
const scorll = () => {
if (Math.abs(target - content.scrollTop) <= Math.abs(step)) {
content.scrollTop = target;
this.curIdx = idx;
this.isScroll = false;
this.isClick = false;
return;
}
content.scrollTop += step;
requestAnimationFrame(scorll)
}
scorll()
},
scroll(e) {
if (!this.isClick) {
const tab = this.$refs.tab[this.curIdx];
const tabHeight = tab.offsetHeight;
const content = this.$refs.content;
const dir = getDir(e.target);
// 向上滚动,如果tab底边在容器的顶边的上方,则它离开了容器,展示下一个tab
if (dir === 'up') {
if (content.getBoundingClientRect().top - tab.getBoundingClientRect().top >= tab.offsetHeight / 2) {
if (this.curIdx < this.tabs.length - 1) {
this.curIdx++;
}
}
}else {
if (tab.getBoundingClientRect().bottom - content.getBoundingClientRect().bottom >= tab.offsetHeight / 2) {
this.curIdx--;
}
}
}
}
},
})
</script>
</body>
</html>
使用vue实现锚点定位特效
于 2023-01-13 17:11:23 首次发布