299 lines
8.8 KiB
Vue
299 lines
8.8 KiB
Vue
<template>
|
||
<div class="h5-container">
|
||
<!-- 主要内容区域 -->
|
||
<div ref="mainContent" class="main" @scroll="handleScroll">
|
||
<transition :name="transitionName" mode="out-in">
|
||
<router-view></router-view>
|
||
</transition>
|
||
</div>
|
||
<div style="height: 1.4rem;"></div>
|
||
|
||
<!-- 返回顶部按钮 -->
|
||
<transition name="fade-scale">
|
||
<div
|
||
v-show="showBackToTop"
|
||
class="back-to-top"
|
||
@click="scrollToTop"
|
||
>
|
||
<div class="back-to-top-icon">
|
||
<svg viewBox="0 0 24 24" fill="none">
|
||
<path d="M12 5L12 19M12 5L6 11M12 5L18 11"
|
||
stroke="currentColor"
|
||
stroke-width="2"
|
||
stroke-linecap="round"
|
||
stroke-linejoin="round"/>
|
||
</svg>
|
||
</div>
|
||
<div class="back-to-top-text">回顶部</div>
|
||
</div>
|
||
</transition>
|
||
|
||
<!-- 底部导航栏 -->
|
||
<div class="tabBar">
|
||
<!-- 首页 -->
|
||
<div
|
||
class="tabBar-item"
|
||
:class="{ active: activeTab === 'index' }"
|
||
@click="switchTab('index')"
|
||
>
|
||
<div class="item-img">
|
||
<transition name="icon-bounce" mode="out-in">
|
||
<img
|
||
:key="activeTab === 'index'"
|
||
:src="activeTab === 'index' ? require('./images/tabBar/homeColor.png') : require('./images/tabBar/home.png')"
|
||
alt="首页"
|
||
/>
|
||
</transition>
|
||
</div>
|
||
<div class="item-text">
|
||
<transition name="text-slide" mode="out-in">
|
||
<span :key="activeTab === 'index'">首页</span>
|
||
</transition>
|
||
</div>
|
||
<div class="active-indicator" v-if="activeTab === 'index'"></div>
|
||
</div>
|
||
|
||
<!-- 云 -->
|
||
<div
|
||
class="tabBar-item"
|
||
:class="{ active: activeTab === 'cloud' }"
|
||
@click="switchTab('cloud')"
|
||
>
|
||
<div class="item-img">
|
||
<transition name="icon-bounce" mode="out-in">
|
||
<img
|
||
:key="activeTab === 'cloud'"
|
||
:src="activeTab === 'cloud' ? require('./images/tabBar/cloudColor.png') : require('./images/tabBar/cloud.png')"
|
||
alt="云"
|
||
/>
|
||
</transition>
|
||
</div>
|
||
<div class="item-text">
|
||
<transition name="text-slide" mode="out-in">
|
||
<span :key="activeTab === 'cloud'">云</span>
|
||
</transition>
|
||
</div>
|
||
<div class="active-indicator" v-if="activeTab === 'cloud'"></div>
|
||
</div>
|
||
|
||
<!-- 算 -->
|
||
<div
|
||
class="tabBar-item"
|
||
:class="{ active: activeTab === 'calculate' }"
|
||
@click="switchTab('calculate')"
|
||
>
|
||
<div class="item-img">
|
||
<transition name="icon-bounce" mode="out-in">
|
||
<img
|
||
:key="activeTab === 'calculate'"
|
||
:src="activeTab === 'calculate' ? require('./images/tabBar/calculateColor.png') : require('./images/tabBar/calculate.png')"
|
||
alt="算"
|
||
/>
|
||
</transition>
|
||
</div>
|
||
<div class="item-text">
|
||
<transition name="text-slide" mode="out-in">
|
||
<span :key="activeTab === 'calculate'">算</span>
|
||
</transition>
|
||
</div>
|
||
<div class="active-indicator" v-if="activeTab === 'calculate'"></div>
|
||
</div>
|
||
|
||
<!-- 网 -->
|
||
<div
|
||
class="tabBar-item"
|
||
:class="{ active: activeTab === 'net' }"
|
||
@click="switchTab('net')"
|
||
>
|
||
<div class="item-img">
|
||
<transition name="icon-bounce" mode="out-in">
|
||
<img
|
||
:key="activeTab === 'net'"
|
||
:src="activeTab === 'net' ? require('./images/tabBar/netColor.png') : require('./images/tabBar/net.png')"
|
||
alt="网"
|
||
/>
|
||
</transition>
|
||
</div>
|
||
<div class="item-text">
|
||
<transition name="text-slide" mode="out-in">
|
||
<span :key="activeTab === 'net'">网</span>
|
||
</transition>
|
||
</div>
|
||
<div class="active-indicator" v-if="activeTab === 'net'"></div>
|
||
</div>
|
||
|
||
<!-- 用 -->
|
||
<div
|
||
class="tabBar-item"
|
||
:class="{ active: activeTab === 'use' }"
|
||
@click="switchTab('use')"
|
||
>
|
||
<div class="item-img">
|
||
<transition name="icon-bounce" mode="out-in">
|
||
<img
|
||
:key="activeTab === 'use'"
|
||
:src="activeTab === 'use' ? require('./images/tabBar/userColor.png') : require('./images/tabBar/user.png')"
|
||
alt="用"
|
||
/>
|
||
</transition>
|
||
</div>
|
||
<div class="item-text">
|
||
<transition name="text-slide" mode="out-in">
|
||
<span :key="activeTab === 'use'">用</span>
|
||
</transition>
|
||
</div>
|
||
<div class="active-indicator" v-if="activeTab === 'use'"></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<script>
|
||
import './media.js'
|
||
export default {
|
||
name: 'H5HomePage',
|
||
data() {
|
||
return {
|
||
activeTab: 'index', // 当前激活的标签
|
||
tabList: [
|
||
{ id: 'index', name: '首页', path: '/h5HomePage/index' },
|
||
{ id: 'cloud', name: '云', path: '/h5HomePage/cloud' },
|
||
{ id: 'calculate', name: '算', path: '/h5HomePage/calculate' },
|
||
{ id: 'net', name: '网', path: '/h5HomePage/net' },
|
||
{ id: 'use', name: '用', path: '/h5HomePage/use' }
|
||
],
|
||
showBackToTop: false, // 是否显示返回顶部按钮
|
||
scrollThreshold: 200, // 滚动多少距离后显示按钮(可根据需要调整)
|
||
transitionName: 'fade', // 页面切换动画名称
|
||
isSwitching: false, // 是否正在切换
|
||
};
|
||
},
|
||
watch: {
|
||
// 监听路由变化,更新激活的标签
|
||
'$route'(to) {
|
||
this.updateActiveTab(to.path);
|
||
}
|
||
},
|
||
mounted() {
|
||
// 初始化时根据当前路由设置激活状态
|
||
this.updateActiveTab(this.$route.path);
|
||
},
|
||
methods: {
|
||
/**
|
||
* 切换标签页
|
||
* @param {string} tabId - 标签ID
|
||
*/
|
||
switchTab(tabId) {
|
||
// 如果正在切换或点击的是当前已激活的标签,不进行操作
|
||
if (this.isSwitching || this.activeTab === tabId) return;
|
||
|
||
// 设置正在切换状态
|
||
this.isSwitching = true;
|
||
|
||
// 更新激活状态
|
||
this.activeTab = tabId;
|
||
|
||
// 根据tabId跳转到对应的路由
|
||
const tab = this.tabList.find(item => item.id === tabId);
|
||
if (tab) {
|
||
// 添加点击反馈动画
|
||
this.animateTabClick(tabId);
|
||
|
||
// 延迟路由跳转,让动画先执行
|
||
setTimeout(() => {
|
||
this.$router.push(tab.path);
|
||
// 重置切换状态
|
||
setTimeout(() => {
|
||
this.isSwitching = false;
|
||
}, 300);
|
||
}, 150);
|
||
} else {
|
||
this.isSwitching = false;
|
||
}
|
||
},
|
||
|
||
/**
|
||
* 执行Tab点击动画
|
||
* @param {string} tabId - 标签ID
|
||
*/
|
||
animateTabClick(tabId) {
|
||
// 获取点击的tab元素
|
||
const tabIndex = this.tabList.findIndex(item => item.id === tabId);
|
||
const tabs = document.querySelectorAll('.tabBar-item');
|
||
|
||
if (tabs[tabIndex]) {
|
||
// 添加点击动画类
|
||
tabs[tabIndex].classList.add('click-animation');
|
||
|
||
// 动画结束后移除类
|
||
setTimeout(() => {
|
||
tabs[tabIndex].classList.remove('click-animation');
|
||
}, 300);
|
||
}
|
||
},
|
||
|
||
/**
|
||
* 根据路由路径更新激活的标签
|
||
* @param {string} path - 当前路由路径
|
||
*/
|
||
updateActiveTab(path) {
|
||
// 从路径中提取tabId
|
||
const pathParts = path.split('/');
|
||
const tabId = pathParts[pathParts.length - 1];
|
||
|
||
// 如果提取的tabId在tabList中存在,则更新activeTab
|
||
if (this.tabList.some(item => item.id === tabId)) {
|
||
this.activeTab = tabId;
|
||
}
|
||
},
|
||
|
||
/**
|
||
* 处理滚动事件
|
||
*/
|
||
handleScroll() {
|
||
if (this.$refs.mainContent) {
|
||
const scrollTop = this.$refs.mainContent.scrollTop;
|
||
// 当滚动距离超过阈值时显示返回顶部按钮
|
||
this.showBackToTop = scrollTop > this.scrollThreshold;
|
||
}
|
||
},
|
||
|
||
/**
|
||
* 滚动到顶部
|
||
*/
|
||
scrollToTop() {
|
||
if (this.$refs.mainContent) {
|
||
// 添加点击反馈效果
|
||
const btn = document.querySelector('.back-to-top');
|
||
if (btn) {
|
||
btn.classList.add('clicked');
|
||
setTimeout(() => {
|
||
btn.classList.remove('clicked');
|
||
}, 300);
|
||
}
|
||
|
||
this.$refs.mainContent.scrollTo({
|
||
top: 0,
|
||
behavior: 'smooth' // 平滑滚动
|
||
});
|
||
}
|
||
}
|
||
}
|
||
};
|
||
function adapter() {
|
||
//获取布局视口宽度,因为开启了理想视口,布局视口=设备横向独立像素值
|
||
const dpWidth = document.documentElement.clientWidth
|
||
//计算根字体大小
|
||
const rootFonstSize = (dpWidth * 100) / 750
|
||
//设置根字体大小
|
||
document.documentElement.style.fontSize = rootFonstSize + 'px'
|
||
}
|
||
adapter()
|
||
window.onresize = adapter()
|
||
|
||
</script>
|
||
|
||
<style lang="less" scoped>
|
||
@import url('./less/home/index.less');
|
||
</style>
|