kboss/f/web-kboss/src/views/H5/index.vue
2025-12-16 17:49:20 +08:00

299 lines
8.8 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<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>