一. 跨页面锚点跳转(Vue2)
- 首页
跳转到
搜索页
1.1 首页
- 通过路由跳转
query:{
id:id
}
handleClick(){
this.$router.push({
path:'/search',
query:this.query
})
}
1.2 搜索页
- 处理
<template>
<div>
<div class="industry_area">
<div class="industry_single" v-for="(menu, index) in industryList" :key="index"
@click="handleClick(menu.id)">
<div :id="`id${menu.id}`" class="industry_title "
:class="activeIndustryId == menu.id ? 'industry_active' : ''">
{{
menu.dictValue
}}
</div>
<div :id="`id${menuChild.id}`" class="industry_child"
:class="activeIndustryId == menuChild.id ? 'industry_active' : ''" v-if="menu.children.length > 0"
v-for="(menuChild, index) in menu.children" :key="index" @click.stop="handleClick(menuChild.id, 2)">
<span>{{ menuChild.dictValue }}</span>
</div>
</div>
</div>
</div>
</template>
<script>
import { getTree} from '@/api/xxx'
export default {
data() {
return {
industryList: [],
activeIndustryId :'' // 当前选中项
}
},
mounted() {
this.fetchData()
},
methods: {
/**
* 获取行业列表数据
*/
fetchData() {
getTree('industry').then(res => {
this.industryList = res.data
if (res.code == 200 && this.activeIndustryId != "") {
this.$nextTick(() => {
this.anchorScrollIntoTarget()
})
}
})
},
/**
* 根据行业id获取文档列表
* @param {Int} id
*/
handleClick(id, level) {
this.activeIndustryId = id
this.$emit('handleClickSearch', id, level)
},
/**
* 锚点跳转
*/
anchorScrollIntoTarget() {
document.querySelector(`#id${this.activeIndustryId}`).scrollIntoView({
behavior: 'smooth',
block: 'center'
})
}
}
}
</script>
二. 本页面跳转(Vue3)
- 需求:选中哪个,哪个居中显示
- 效果:
- 实现
<template>
<div class="tab" >
<div v-for="(item, index) in tabList" :id="'tab-' + index" :key="index" :ref="setRef" class="tab-item"
:class="{ active: activeIndex === index }" @click="changeTab(index)">
{{ item }}
</div>
</div>
</template>
<script>
const tabList = ref([
'标签1',
'标签2',
'标签3',
'标签4',
'标签5',
'标签6',
'标签7',
'标签8'
])
const activeIndex = ref(0)
// 设置锚点
const eleRefs = ref([])
const setRef = (el) => {
if (el) {
eleRefs.value.push(el)
}
}
// 切换tab
const changeTab = index => {
anchor(index)
}
// 锚点定位
const anchor = index => {
activeIndex.value = index
if (eleRefs.value[index]) {
eleRefs.value[index].scrollIntoView({
block: 'center',
inline: 'center',
behavior: 'smooth' // 平滑滚动到目标位置
})
}
}
</script>
<style lang="scss" scoped>
.tab {
width: 750px;
height: 114px;
display: flex;
align-items: center;
overflow-x: auto;
/* 水平方向超出时显示滚动条 */
white-space: nowrap;
/* 保持内容在一行显示 */
scrollbar-width: none;
/* 隐藏滚动条 */
-ms-overflow-style: none;
background-image: url('@/assets/images/BI/indexbg2.png');
background-repeat: no-repeat;
background-size: 100% 100%;
/* IE 10+ */
.tab-item {
height: 74px;
font-size: 32px;
background: rgba(4, 106, 249, 1);
display: flex;
align-items: center;
justify-content: center;
margin-left: 20px;
border: 1px solid rgba(255, 255, 255, 0.4);
border-radius: 40px;
color: #fff;
padding: 16px 15px;
}
.active {
background: #fff;
color: black;
font-weight: 500;
}
}
</style>
三. 回到顶部(Vue3)
3.1 document.body.scrollTo(无滚动条)
-
需求:“顶部”图标固定在页面右下方,点击“顶部”即可返回顶部
-
效果
-
实现
<template>
<div class="container">
<div>内容区域</div>
// 回到顶部
<div class="back-to-top">
<a class="top" @click="scrollToTop">
<span>
<van-icon name="arrow-up" class="i" />
顶部
</span>
</a>
</div>
</div>
</template>
<script setup>
// 回到顶部
const scrollToTop = () => {
// 因为没有滚动条所以此种方法不生效
// window.scrollTo({
// top: 0,
// behavior: 'smooth'
// });
document.body.scrollTo({
top: 0,
behavior: 'smooth'
})
}
</script>
<style>
.container{
height: 100%; // height不能固定,例如 height:100vh,否则会失效
}
// 返回顶部
.back-to-top {
position: fixed;
right: 0.2rem;
bottom: 1.5rem;
width: 1.2rem;
z-index: 990;
}
.back-to-top .top {
margin: 0 auto;
width: 1rem;
height: 1rem;
background: #fff;
box-shadow: 0 0.04rem 0.16rem 0 rgba(0, 0, 0, 0.18);
display: flex;
justify-content: center;
align-items: center;
border-radius: 2rem;
text-align: center;
font-size: 0.22rem;
}
.back-to-top .top .i {
display: block;
font-size: 0.34rem;
}
.back-to-top:hover {
transform: scale(1.1);
}
</style>
3.2 id + a标签 + ref(无滚动条)
- 实现
<template>
<div id="content" ref="outerDom" class="container">
<div ref="containerTitle" class="top-title mt26">不跟随区域</div>
// 固定跟随区域
<div class="tab-nav">
<div class="tab ">
<div v-for="(item, index) in tabList" :id="'tab-' + index" :key="index" :ref="setRef" class="tab-item"
:class="{ active: activeIndex === index }" @click="changeTab(index)">
{{ item }}
</div>
</div>
<div class="statTime mt1-1">
时间
</div>
</div>
<component :is="tabComponents[activeIndex]" @changeActivityPreview="changeActivityPreview">
</component>
<div class="back-to-top">
<a ref="#content" class="top" @click="scrollToTop">
<span>
<van-icon name="arrow-up" class="i" />
顶部
</span>
</a>
</div>
</div>
</template>
<script setup>
import { reactive, ref } from 'vue'
import tab1 from './components/tab1.vue'
import tab2 from './components/tab2.vue'
import tab3 from './components/tab3.vue'
import tab4 from './components/tab4.vue'
import tab5 from './components/tab5.vue'
import tab6 from './components/tab6.vue'
import tab7 from './components/tab7.vue'
import tab8 from './components/tab8.vue'
const tabList = ref([
'tab1',
'tab2',
'tab3',
'tab4',
'tab5',
'tab6',
'tab7',
'tab8'
])
const tabComponents = markRaw({
0: tab1,
1: tab2,
2: tab3,
3: tab4,
4: tab5,
5: tab6,
6: tab7,
7: tab8
})
const activeIndex = ref(0)
// 设置锚点
const eleRefs = ref([])
const outerDom = ref(null)
const setRef = (el) => {
if (el) {
eleRefs.value.push(el)
}
}
// 回到顶部
const scrollToTop = () => {
const scrollStep = () => {
if (outerDom.value.scrollTop > 0) {
outerDom.value.scrollTop -= Math.min(outerDom.value.scrollTop / 20, 20);
requestAnimationFrame(scrollStep);
}
};
scrollStep();
}
// 切换tab
const changeTab = index => {
anchor(index)
}
const changeActivityPreview = name => {
const type = tabList.value.findIndex(e => {
return e.includes(name)
})
anchor(type)
}
// 锚点定位
const anchor = index => {
activeIndex.value = index
if (eleRefs.value[index]) {
eleRefs.value[index].scrollIntoView({
block: 'center',
inline: 'center',
behavior: 'smooth' // 平滑滚动到目标位置
})
}
}
</script>
<style lang="scss" scoped>
.container {
max-height: 100vh;
position: relative;
overflow: auto;
}
// 返回顶部
.back-to-top {
position: fixed;
right: 0.2rem;
bottom: 1.5rem;
width: 1.2rem;
z-index: 990;
}
.back-to-top .top {
margin: 0 auto;
width: 1rem;
height: 1rem;
background: #fff;
box-shadow: 0 0.04rem 0.16rem 0 rgba(0, 0, 0, 0.18);
display: flex;
justify-content: center;
align-items: center;
border-radius: 2rem;
text-align: center;
font-size: 0.22rem;
}
.back-to-top .top .i {
display: block;
font-size: 0.34rem;
}
.back-to-top:hover {
transform: scale(1.1);
}
.homebg {
width: 100%;
height: 310px;
background-image: url('@/assets/images/BI/indexbg.png');
background-repeat: no-repeat;
background-size: 100% 100%;
padding-top: 88px;
}
.top-title {
height: 176px;
background-image: url('@/assets/images/BI/indexbg1.png');
background-repeat: no-repeat;
background-size: 100% 100%;
display: flex;
align-items: center;
justify-content: center;
font-size: 36px;
font-weight: 500;
color: rgba(255, 255, 255, 1);
}
.tab {
width: 750px;
height: 114px;
display: flex;
align-items: center;
overflow-x: auto;
/* 水平方向超出时显示滚动条 */
white-space: nowrap;
/* 保持内容在一行显示 */
scrollbar-width: none;
/* 隐藏滚动条 */
-ms-overflow-style: none;
background-image: url('@/assets/images/BI/indexbg2.png');
background-repeat: no-repeat;
background-size: 100% 100%;
/* IE 10+ */
.tab-item {
height: 74px;
font-size: 32px;
background: rgba(4, 106, 249, 1);
display: flex;
align-items: center;
justify-content: center;
margin-left: 20px;
border: 1px solid rgba(255, 255, 255, 0.4);
border-radius: 40px;
color: #fff;
padding: 16px 15px;
}
.active {
background: #fff;
color: black;
font-weight: 500;
}
}
</style>
- 代码解释
Template:
(1)包含一个 div 元素,其 id 为 content,并且使用 ref 绑定到 outerDom。 包含一个回到顶部的按钮,点击时触发
(2)scrollToTop 方法。
Script:
(1)导入 ref 从 vue 和 VantIcon 从 vant。 定义 outerDom 为一个响应式引用,用于引用外部 DOM 元素。 定义
(2)scrollToTop 方法,使用 requestAnimationFrame 和递归调用来逐步减少 scrollTop 的值,直到
(3)scrollTop 为 0,实现平滑滚动效果。
Style:
(1)定义 .back-to-top 的样式,包括位置、背景颜色、边框等。
- 工作原理
scrollToTop 方法中,scrollStep 函数递归调用自身,每次减少 scrollTop 的值,直到 scrollTop 为
0。 Math.min(outerDom.value.scrollTop / 5, 5) 确保每次滚动的距离不会太大,从而实现平滑滚动效果。
使用 requestAnimationFrame 来优化性能,避免在每次滚动时都执行大量计算。