Files
tuniao-ui/vipPage/home/tuniao/tuniao.vue
T
2026-03-19 10:47:37 +08:00

640 lines
20 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>
<view class="template-tuniao tn-safe-area-inset-bottom">
<!-- 顶部自定义导航 -->
<!-- <tn-nav-bar fixed alpha customBack>
<view slot="back" class='tn-custom-nav-bar__back'
@click="goBack">
<text class='icon tn-icon-left'></text>
<text class='icon tn-icon-home-capsule-fill'></text>
</view>
</tn-nav-bar> -->
<!-- 顶部自定义导航 -->
<tn-nav-bar fixed :isBack="false" :bottomShadow="false" :backgroundColor="navBarBackgroundColor">
<view id="navbar" class="custom-nav tn-flex tn-flex-col-center tn-flex-row-left" :style="[navBarStyle]">
<!-- 图标logo -->
<view class="custom-nav__back">
<view class="logo-pic" style="background-image:url('https://resource.tuniaokj.com/images/logo/logo.jpg')">
<view class="logo-image">
</view>
</view>
<!-- <view class="tn-icon-left"></view> -->
</view>
<!-- 搜索框 -->
<view class="custom-nav__search tn-flex tn-flex-col-center tn-flex-row-center">
<view class="custom-nav__search__box tn-flex tn-flex-col-center tn-flex-row-left tn-color-gray--dark tn-bg-gray--light">
<view class="custom-nav__search__icon tn-icon-search"></view>
<view class="custom-nav__search__text tn-padding-left-xs">好想搜点什么</view>
</view>
</view>
</view>
</tn-nav-bar>
<view class="tn-margin-top-sm" :style="{paddingTop: vuex_custom_bar_height + 'px'}">
<view id="page_tips" class="tn-flex tn-flex-row-between">
<view class="justify-content-item tn-margin tn-text-bold tn-text-xxl">
Hi早午晚都好吖
</view>
<view class="justify-content-item tn-margin tn-text-bold tn-text-xxl">
<text class="tn-icon-share-triangle"></text>
</view>
</view>
<view class="tn-margin-left tn-margin-right tn-margin-top-sm">
<tn-swiper :list="banner" :height="320" :effect3d="false" mode="round"></tn-swiper>
</view>
<view class="tn-flex tn-flex-row-between tn-margin-top-xl">
<view class="justify-content-item tn-margin tn-text-bold tn-text-xxl">
热门项目
</view>
<view class="justify-content-item tn-margin tn-text-lg tn-color-gray--disabled">
<text class="tn-padding-xs">全部</text>
<text class="tn-icon-topics"></text>
</view>
</view>
<view class="tn-flex tn-margin-left tn-margin-right tn-margin-top-sm">
<view class="tn-flex-2">
<view class="image-pic tn-margin-right" style="background-image:url('https://resource.tuniaokj.com/images/shop/cup2.jpg')">
<view class="image-tuniao1">
</view>
</view>
</view>
<view class="tn-flex-1">
<view class="image-pic" style="background-image:url('https://resource.tuniaokj.com/images/shop/phonecase1.jpg')">
<view class="image-tuniao2">
</view>
</view>
<view class="image-pic tn-margin-top" style="background-image:url('https://resource.tuniaokj.com/images/shop/banner1.jpg')">
<view class="image-tuniao2">
</view>
</view>
</view>
</view>
<view class="tn-flex tn-flex-row-between tn-margin-top">
<view class="justify-content-item tn-margin tn-text-bold tn-text-xxl">
业务范围
</view>
<!-- <view class="justify-content-item tn-margin tn-text-xxl tn-color-gray--disabled">
<text class="tn-padding-xs">全部</text>
<text class="tn-icon-topics"></text>
</view> -->
</view>
<view class="tn-info__container tn-flex tn-flex-wrap tn-flex-col-center tn-flex-row-between tn-margin-left tn-margin-right">
<block v-for="(item, index) in tuniaoData" :key="index">
<view class="tn-info__item tn-flex tn-flex-direction-row tn-flex-col-center tn-flex-row-between tn-color-white" :class="[`tn-bg-${item.color}`]">
<view class="tn-info__item__left tn-flex tn-flex-direction-row tn-flex-col-center tn-flex-row-left">
<!-- <view class="tn-info__item__left--icon tn-flex tn-flex-col-center tn-flex-row-center" :class="[`tn-bg-${item.color}--light tn-color-${item.color}`]">
<view :class="[`tn-icon-${item.icon}`]"></view>
</view> -->
<view class="tn-info__item__left__content">
<view class="tn-info__item__left__content--title tn-text-xxl">{{ item.title }}</view>
<view class="tn-info__item__left__content--data tn-padding-top-xs">
{{ item.value }}
<text class="tn-icon-right tn-padding-left-xs"></text>
</view>
</view>
</view>
<view class="tn-info__item__right">
<view class="tn-info__item__right--icon">
<view :class="[`tn-icon-${item.icon}`]"></view>
</view>
</view>
</view>
</block>
</view>
</view>
<view class="bg-tabbar-shadow"></view>
<view class="tabbar__placeholder"></view>
<!-- 底部导航栏 -->
<view class="tabbar">
<view class="tabbar__bg" :style="[wrapStyle]"></view>
<view class="tabbar__list">
<block v-for="(item, index) in tabbar" :key="index">
<view :id="`tabbar_item_${index}`" class="tabbar__item" :class="[{'tabbar__item--active': index === currentTabbarIndex}]" @click="changeTabbar(index)">
<view class="tabbar__item__icon" :class="[item.icon]"></view>
<view class="tabbar__item__text">{{ item.name }}</view>
</view>
</block>
</view>
<!-- <view class="tabbar__select-active-bg" :class="[showActiceBg ? 'tabbar__select-active-bg--show' : 'tabbar__select-active-bg--hide']" :style="[activeBgStyle]"></view> -->
<view class="tabbar__select-active-bg" :animation="activeBgAnimation"></view>
</view>
<!-- 回到首页悬浮按钮-->
<nav-index-button></nav-index-button>
</view>
</template>
<script>
import template_page_mixin from '@/libs/mixin/template_page_mixin.js'
import NavIndexButton from '@/libs/components/nav-index-button.vue'
export default {
name: 'TemplateCourse',
mixins: [template_page_mixin],
components: { NavIndexButton },
data(){
return {
banner: [{
image: 'https://resource.tuniaokj.com/images/swiper/tnbanner1.jpg'
}, {
image: 'https://resource.tuniaokj.com/images/swiper/tnbanner2.jpg'
}, {
image: 'https://resource.tuniaokj.com/images/swiper/tnbanner3.jpg'
}, {
image: 'https://resource.tuniaokj.com/images/swiper/tnbanner4.jpg'
}],
tuniaoData: [
{
title: 'UI设计',
icon: 'image-text-fill',
color: 'red',
value: '前往咨询'
},
{
title: '小程序',
icon: 'data-fill',
color: 'orange',
value: '前往咨询'
},
{
title: '网站开发',
icon: 'statistics-fill',
color: 'purple',
value: '前往咨询'
},
{
title: '其他业务',
icon: 'bankcard-fill',
color: 'blue',
value: '前往咨询'
}
],
wrapMaskPositionLeft: 0,
activeBgPositionLeft: 0,
showActiceBg: false,
prevTabbarIndex: 0,
currentTabbarIndex: 0,
tabbarRectInfo: [],
tabbar: [
{ name: '首页', icon: 'tn-icon-home' },
{ name: '圈子', icon: 'tn-icon-discover' },
{ name: '数据', icon: 'tn-icon-data' },
{ name: '我的', icon: 'tn-icon-my' }
],
navBarRectInfo: {},
navBarChangebaseLineHeight: 0,
navBarStyle: {
opacity: 1,
display: 'flex'
},
navBarBackgroundColor: 'rgba(255, 255, 255, 1)',
activeBgAnimation: {}
}
},
computed: {
wrapStyle() {
return {
'-webkit-mask-position': `${this.wrapMaskPositionLeft}px -1px, 100%`
}
},
activeBgStyle() {
return {
'left': `${this.activeBgPositionLeft}px`
}
}
},
onReady() {
this.$nextTick(() => {
this.getTabbarItemInfo()
this.initNavBarRectInfo()
})
},
onPageScroll() {
this.updateNavBarRectInfo()
},
methods: {
// 初始化导航栏信息
async initNavBarRectInfo() {
const navBarRectInfo = await this._tGetRect('#navbar')
const pageTipsRectInfo = await this._tGetRect('#page_tips')
// console.log(navBarRectInfo, pageTipsRectInfo);
if (!(navBarRectInfo?.top) || !(pageTipsRectInfo?.top)) {
setTimeout(() => {
this.initNavBarRectInfo()
}, 10)
return
}
this.navBarRectInfo = {
top: navBarRectInfo.top
}
this.navBarChangebaseLineHeight = pageTipsRectInfo.top - navBarRectInfo.top
},
// 更新导航栏信息
updateNavBarRectInfo() {
this._tGetRect('#page_tips').then((res) => {
const top = res?.top || 0
if (!top) {
return
}
const differHeight = top - this.navBarRectInfo.top
const opacity = differHeight / this.navBarChangebaseLineHeight
if (opacity < 0) {
this.navBarStyle.opacity = 0
this.navBarStyle.display = 'none'
this.navBarBackgroundColor = `rgba(255, 255, 255, 0)`
} else {
this.navBarStyle.opacity = opacity
this.navBarStyle.display = 'flex'
this.navBarBackgroundColor = `rgba(255, 255, 255, ${opacity})`
}
// console.log(top, differHeight, opacity);
})
},
// 获取底部元素的位置
getTabbarItemInfo() {
const view = uni.createSelectorQuery().in(this)
for(let i = 0; i < this.tabbar.length; i++) {
view.select('#tabbar_item_' + i).boundingClientRect()
}
view.exec(res => {
if (!res.length) {
setTimeout(() => {
this.getTabbarItemInfo()
}, 10)
return
}
// 将信息存入数组中
res.map((item) => {
this.tabbarRectInfo.push({
left: item.left,
width: item.width
})
})
this.updateHollowsPosition()
this.updateActiveBgPosition(true)
// console.log(this.tabbarRectInfo)
})
},
// 更新凹陷位置
updateHollowsPosition() {
const { width, left } = this.tabbarRectInfo[this.currentTabbarIndex]
// 计算掩模图片的宽高比
// const imageRatio = 200 / 92
// 计算定高的宽比
const imageFixedHeightWidthRatioValue = 300 * (uni.upx2px(64) / 92)
this.wrapMaskPositionLeft = left - ((imageFixedHeightWidthRatioValue - width) / 2)
// console.log(imageFixedHeightWidthRatioValue, this.wrapMaskPositionLeft);
},
// 更新激活时背景的位置
updateActiveBgPosition(init = false) {
const { width, left } = this.tabbarRectInfo[this.currentTabbarIndex]
const oldActiveBgPositionLeft = this.activeBgPositionLeft
this.activeBgPositionLeft = left + ((width - uni.upx2px(100)) / 2)
// console.log(oldActiveBgPositionLeft, this.activeBgPositionLeft);
// if (!init) {
// this.showActiceBg = false
// setTimeout(() => {
// this.showActiceBg = true
// }, 150)
// } else {
// this.showActiceBg = true
// }
if (!init) {
const animation = uni.createAnimation({
duration: 200,
timingFunction: "ease-out"
})
animation.top(uni.upx2px(50)).left(oldActiveBgPositionLeft + ((this.activeBgPositionLeft - oldActiveBgPositionLeft) / 2)).scale(0.5).step()
animation.left(this.activeBgPositionLeft).top(uni.upx2px(-54)).scale(1).step()
this.activeBgAnimation = animation.export()
} else {
const animation = uni.createAnimation({
duration: 100,
timingFunction: "ease-out"
})
animation.left(this.activeBgPositionLeft).top(uni.upx2px(-54)).step()
this.activeBgAnimation = animation.export()
}
},
// 修改当前选中的tabbar
changeTabbar(index) {
if (this.currentTabbarIndex === index) return
this.prevTabbarIndex = this.currentTabbarIndex
this.currentTabbarIndex = index
this.$nextTick(() => {
this.updateHollowsPosition()
this.updateActiveBgPosition()
})
}
}
}
</script>
<style lang="scss" scoped>
@import '@/static/css/templatePage/custom_nav_bar.scss';
.template-tuniao {
// background-color: #FBFBFB;
}
/* 底部tabbar假阴影 start*/
.bg-tabbar-shadow{
background-image: repeating-linear-gradient(to top, rgba(0,0,0,0.1) 10rpx, #FFFFFF , #FFFFFF);
position: fixed;
bottom: 0;
height: 450rpx;
width: 100vw;
z-index: -1;
}
/* 自定义导航栏内容 start */
.custom-nav {
height: 100%;
&__back {
margin: auto 5rpx;
font-size: 40rpx;
margin-right: 10rpx;
margin-left: 30rpx;
flex-basis: 5%;
}
&__search {
flex-basis: 60%;
width: 100%;
height: 100%;
&__box {
width: 100%;
height: 70%;
padding: 10rpx 0;
margin: 0 30rpx;
border-radius: 60rpx 60rpx 0 60rpx;
font-size: 24rpx;
}
&__icon {
padding-right: 10rpx;
margin-left: 20rpx;
font-size: 30rpx;
}
&__text {
color: #AAAAAA;
}
}
}
.logo-image{
width: 65rpx;
height: 65rpx;
position: relative;
}
.logo-pic{
background-size: cover;
background-repeat:no-repeat;
// background-attachment:fixed;
background-position:top;
border-radius: 50%;
}
/* 自定义导航栏内容 end */
/* 热门图片 start*/
.image-tuniao1{
padding: 164rpx 0rpx;
font-size: 40rpx;
font-weight: 300;
position: relative;
}
.image-tuniao2{
padding: 75rpx 0rpx;
font-size: 40rpx;
font-weight: 300;
position: relative;
}
.image-tuniao3{
padding: 90rpx 0rpx;
font-size: 40rpx;
font-weight: 300;
position: relative;
}
.image-pic{
background-size: cover;
background-repeat:no-repeat;
// background-attachment:fixed;
background-position:top;
border-radius: 10rpx;
}
/* 业务展示 start */
.tn-info {
&__container {
margin-top: 10rpx;
margin-bottom: 50rpx;
}
&__item {
width: 48%;
margin: 15rpx 0rpx;
padding: 40rpx 30rpx;
border-radius: 15rpx;
position: relative;
z-index: 1;
&::after {
content: " ";
position: absolute;
z-index: -1;
width: 100%;
height: 100%;
left: 0;
bottom: 0;
border-radius: inherit;
opacity: 1;
transform: scale(1, 1);
background-size: 100% 100%;
background-image: url(https://resource.tuniaokj.com/images/cool_bg_image/3.png);
}
&__left {
&--icon {
width: 80rpx;
height: 80rpx;
border-radius: 50%;
font-size: 40rpx;
margin-right: 20rpx;
position: relative;
z-index: 1;
&::after {
content: " ";
position: absolute;
z-index: -1;
width: 100%;
height: 100%;
left: 0;
bottom: 0;
border-radius: inherit;
opacity: 1;
transform: scale(1, 1);
background-size: 100% 100%;
background-image: url(https://resource.tuniaokj.com/images/cool_bg_image/icon_bg5.png);
}
}
&__content {
font-size: 30rpx;
&--data {
margin-top: 5rpx;
font-weight: bold;
}
}
}
&__right {
&--icon {
position: absolute;
right: 0rpx;
top: 50rpx;
font-size: 100rpx;
width: 108rpx;
height: 108rpx;
text-align: center;
line-height: 60rpx;
opacity: 0.15;
}
}
}
}
/* 业务展示 end */
/* 底部导航 statr */
.tabbar {
width: 100%;
height: calc(110rpx + env(safe-area-inset-bottom));
position: fixed;
bottom: 0;
left: 0;
right: 0;
background-color: transparent;
z-index: 998;
&__bg {
position: absolute;
width: 100%;
height: 100%;
bottom: 0;
left: 0;
background-color: #FFFFFF;
-webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 200 61.5'%3E%3Cpath d='M100 0H0c32.9 0 49.3 61.5 100 61.5S167.1 0 200 0H100z'/%3E%3C/svg%3E"), linear-gradient(#000, #000);
-webkit-mask-size: auto 64rpx, cover;
-webkit-mask-repeat: no-repeat;
-webkit-mask-composite: xor; /*只显示不重合的地方, chorem 、safari 支持*/
z-index: 998;
transition: 0.5s;
}
&__list {
position: absolute;
z-index: 999;
top: 0;
left: 0;
right: 0;
bottom: 0;
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: space-between;
}
&__item {
height: 100%;
width: 100%;
flex: 1;
text-align: center;
font-size: 28rpx;
position: relative;
&--active {
.tabbar__item__icon {
top: -30rpx;
}
.tabbar__item__text {
opacity: 1;
}
}
&__icon {
font-size: 56rpx;
position: absolute;
left: 0;
right: 0;
top: 20rpx;
transition: 0.5s;
}
&__text {
position: absolute;
left: 0;
right: 0;
bottom: calc(10rpx + env(safe-area-inset-bottom));
transition: 0.5s;
opacity: 0;
}
}
&__select-active-bg {
position: absolute;
width: 100rpx;
height: 100rpx;
border-radius: 50%;
background-color: #FFFFFF;
// transition: 0.5s;
z-index: -1;
// box-shadow: 0rpx 0rpx 50rpx 0rpx rgba(0, 0, 0, 0.05);
// box-shadow: inset 0rpx 0rpx 50rpx 0rpx rgba(0, 0, 0, 0.05);
box-shadow: 0rpx 10rpx 30rpx rgba(70,23,129, 0.07),
0rpx -8rpx 40rpx rgba(255, 255, 255, 0.07),
inset 0rpx -10rpx 10rpx rgba(70,23,129, 0.07),
inset 0rpx 10rpx 20rpx rgba(255, 255, 255, 1);
// transition: box-shadow .2s ease-out;
&--hide {
top: calc(110rpx + 50rpx);
}
&--show {
top: -54rpx;
}
}
&__placeholder {
height: calc(110rpx + env(safe-area-inset-bottom));
// display: initial;
}
}
/* 底部导航 end */
</style>