roamfuding-xcx/pages/index/index.vue
2026-03-16 10:00:58 +08:00

1873 lines
50 KiB
Vue
Raw Permalink 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="page">
<view class="fenlei-container fixed-container" :class="{'fade-in': fixedTabVisible && !isHiding, 'fade-out': isHiding}" v-show="fixedTabVisible || isAnimating">
<scroll-view class="fenlei-scroll" style="height: 400rpx;"
scroll-x="true"
:scroll-with-animation="true"
show-scrollbar="false">
<view class="serach">
<view class="touxiang">
<image style="width: 100%;height: 100%;border-radius: 50%;" src="https://api.ccttiot.com/21zwLDYqBJaa6b68ccc6ea37c67c785fa46193ba46c2.png" mode="aspectFill"></image>
</view>
<view class="shuru">
<input type="text" placeholder="搜索景区、酒店" disabled="true" @click="btnsousuo"/>
<image src="https://api.ccttiot.com/smartmeter/img/static/uAO3fdmrrHTzqbVx9hYd" mode=""></image>
</view>
</view>
<view class="fenlei" style="height: 360rpx;padding-top: 100rpx;gap: 16rpx;">
<view class="icon" @click="btnpage(1)">
<image src="https://api.ccttiot.com/smartmeter/img/static/uNvp27XBB0SGRJdwBatm" mode="">
</image>
</view> <!-- 导览 -->
<view class="icon" @click="btnpage(2)">
<image src="https://api.ccttiot.com/smartmeter/img/static/ujtaJ9yoGaSoU2y7d8o0" mode="">
</image> <!-- 攻略 -->
</view>
<view class="icon" @click="btnpage(3)">
<image src="https://api.ccttiot.com/smartmeter/img/static/uW4U5tAEwKWIF0xk6lD3" mode="">
</image> <!-- 住宿 -->
</view>
<view class="icon" @click="btnpage(4)">
<image src="https://api.ccttiot.com/smartmeter/img/static/upFUu8oBSir5xouB7iMV" mode="">
</image> <!-- 美食 -->
</view>
<view class="icon" @click="btnpage(5)">
<image src="https://api.ccttiot.com/smartmeter/img/static/uMOF8Waum001gWd4IQeh" mode="">
</image> <!-- 文化 -->
</view>
<view class="icon" @click="btnpage(6)">
<image src="https://api.ccttiot.com/smartmeter/img/static/uwj8jsmFgQn0Hqh7DsAI" mode="">
</image> <!-- 导游 -->
</view>
<view class="icon" @click="btnpage(7)">
<image src="https://api.ccttiot.com/smartmeter/img/static/uHuu33MlQ9uLbTESJkCB" mode="">
</image> <!-- 停车 -->
</view>
<view class="icon" @click="btnpage(8)">
<image src="https://api.ccttiot.com/smartmeter/img/static/utxraBecHOvUZBeWk9pb" mode="">
</image> <!-- 特产 -->
</view>
</view>
</scroll-view>
</view>
<!-- https://api.ccttiot.com/21zwLDYqBJaa6b68ccc6ea37c67c785fa46193ba46c2.png -->
<!-- <image v-if="!fixedTabVisible" src="https://api.ccttiot.com/smartmeter/img/static/uK1w7pSC1LqpVtZLz2Gc" class="topimg" mode=""></image> -->
<!-- 滚动部分内容 -->
<scroll-view class="bdbox"
scroll-y
@scroll="handleScroll"
@scrolltolower="handqixing"
:scroll-top="scrollTop">
<u-swiper class="topimg" :height="588" bg-color="#fff" :list="lists" @click="btnlb"></u-swiper>
<!-- 头部搜索 -->
<view class="serach">
<view class="touxiang">
<image style="width: 100%;height: 100%;border-radius: 50%;" src="https://api.ccttiot.com/21zwLDYqBJaa6b68ccc6ea37c67c785fa46193ba46c2.png" mode="aspectFill"></image>
</view>
<view class="shuru">
<input type="text" placeholder="搜索景区、酒店" disabled="true" @click="btnsousuo"/>
<image src="https://api.ccttiot.com/smartmeter/img/static/uAO3fdmrrHTzqbVx9hYd" mode=""></image>
</view>
</view>
<view class="fenlei-container" style="height: 320rpx;">
<scroll-view class="fenlei-scroll"
scroll-x="true"
:scroll-with-animation="true"
show-scrollbar="false">
<view class="gonggao" @click="btngg">
<image src="https://api.ccttiot.com/da9WHV7kufhA4c0a87936f08d8bf839b28e2f027fca6.png" mode=""></image>
<view class="gonggao-text-wrapper">
<view class="gonggao-text-content" :class="{ 'no-transition': noTransition }" :style="{ transform: `translateY(-${scrollIndex * 50}%)` }">
<text class="gonggao-text-item">{{formatGonggaoTitle(ggobj[0] && ggobj[0].title)}}</text>
<text class="gonggao-text-item">{{formatGonggaoTitle(ggobj[0] && ggobj[0].title)}}</text>
</view>
</view>
</view>
<view class="fenlei">
<view class="icon" @click="btnpage(1)" style="margin-top: 80rpx;">
<image src="https://api.ccttiot.com/smartmeter/img/static/uNvp27XBB0SGRJdwBatm" mode="">
</image>
</view><!-- 导览 -->
<view class="icon" @click="btnpage(2)" style="margin-top: 80rpx;">
<image src="https://api.ccttiot.com/smartmeter/img/static/ujtaJ9yoGaSoU2y7d8o0" mode="">
</image> <!-- 攻略 -->
</view>
<view class="icon" @click="btnpage(3)" style="margin-top: 80rpx;">
<image src="https://api.ccttiot.com/smartmeter/img/static/uW4U5tAEwKWIF0xk6lD3" mode="">
</image> <!-- 住宿 -->
</view>
<view class="icon" @click="btnpage(4)" style="margin-top: 80rpx;">
<image src="https://api.ccttiot.com/smartmeter/img/static/upFUu8oBSir5xouB7iMV" mode="">
</image> <!-- 美食 -->
</view>
<view class="icon" @click="btnpage(5)" style="margin-top: 80rpx;">
<image src="https://api.ccttiot.com/smartmeter/img/static/uMOF8Waum001gWd4IQeh" mode="">
</image> <!-- 文化 -->
</view>
<view class="icon" @click="btnpage(6)" style="margin-top: 80rpx;">
<image src="https://api.ccttiot.com/smartmeter/img/static/uwj8jsmFgQn0Hqh7DsAI" mode="">
</image> <!-- 导游 -->
</view>
<view class="icon" @click="btnpage(7)" style="margin-top: 80rpx;">
<image src="https://api.ccttiot.com/smartmeter/img/static/uHuu33MlQ9uLbTESJkCB" mode="">
</image> <!-- 停车 -->
</view>
<view class="icon" @click="btnpage(8)" style="margin-top: 80rpx;">
<image src="https://api.ccttiot.com/smartmeter/img/static/utxraBecHOvUZBeWk9pb" mode="">
</image> <!-- 特产 -->
</view>
</view>
</scroll-view>
</view>
<!-- 视频介绍 -->
<view class="videoxc">
<image src="https://api.ccttiot.com/smartmeter/img/static/uKX1Cv1H2ZjWi4y03xU4" mode=""></image>
<swiper class="swiper" :current="currentIndex" :indicator-dots="true" :autoplay="false" circular @change="onSwiperChange">
<swiper-item v-for="(item, idx) in video" :key="idx" @click="playVideo">
<view class="media-wrap">
<video
:id="'swiper-video-' + idx"
:src="item"
:muted="true"
:autoplay="idx === currentIndex"
:loop="true"
playsinline
webkit-playsinline
x5-playsinline
controls
objectFit="cover"
@play="handleVideoPlay(idx)"
@pause="handleVideoPause(idx)"
></video>
<!-- 播放按钮覆盖层,点击跳转到横屏播放 -->
<!-- <view class="play-overlay" v-if="!videoPlaying[idx]" @click="playVideo">
<view class="play-icon">
<text>▶</text>
</view>
</view> -->
</view>
</swiper-item>
</swiper>
</view>
<!-- 热门推荐 -->
<view class="remen">
<view class="rementitle">
<image src="https://api.ccttiot.com/smartmeter/img/static/uQfz6J8VHnar8K3BwFlD" mode=""></image>
</view>
<view class="rmtopimg" @click="btnremen">
<view class="rmltimg" v-if="hotAreaImages[0]">
<view class="rm-card" style="padding-left:0;">
<image style="border-radius: 16rpx;" :src="hotAreaImages[0] + '?imageView2/2/w/750/format/png'" mode="aspectFill"></image>
<view class="rm-bottom-mask">
<text class="name">{{ hotAreaNames[0] && hotAreaNames[0].length > 9 ? hotAreaNames[0].slice(0, 8) + '...' : hotAreaNames[0] }}</text>
<text class="jianjie">{{ hotAreaDescriptions[0] }}</text>
</view>
</view>
</view>
<view class="rmrtimg">
<view class="rm-card" v-if="hotAreaImages[1]">
<image style="border-radius: 16rpx;" :src="hotAreaImages[1] + '?imageView2/2/w/750/format/png'" mode="aspectFill">
</image>
<view class="rm-bottom-mask">
<text class="name">{{ hotAreaNames[1] && hotAreaNames[1].length > 9 ? hotAreaNames[1].slice(0, 8) + '...' : hotAreaNames[1] }}</text>
<text class="jianjie">{{ hotAreaDescriptions[1] }}</text>
</view>
</view>
<view class="rm-card" v-if="hotAreaImages[2]">
<image style="border-radius: 16rpx;" :src="hotAreaImages[2] + '?imageView2/2/w/750/format/png'" mode="aspectFill">
</image>
<view class="rm-bottom-mask">
<text class="name">{{ hotAreaNames[2] && hotAreaNames[2].length > 9 ? hotAreaNames[2].slice(0, 8) + '...' : hotAreaNames[2] }}</text>
<text class="jianjie">{{ hotAreaDescriptions[2] }}</text>
</view>
</view>
</view>
</view>
<view class="meishi" style="margin-top:30rpx;">
<view class="meishilt" @click="btnpage(4)">
<view class="meishitop">
<image class="dibiaoimg"
src="https://api.ccttiot.com/smartmeter/img/static/u1emV89uj8AQR1i5MfPs" mode="">
</image>
<image class="jiantou"
src="https://api.ccttiot.com/smartmeter/img/static/uxhocoNzXasArlGLa2j5" mode="">
</image>
</view>
<image class="daimg" v-if="dishImages[0]" :src="dishImages[0]"
mode="aspectFill"></image>
<view class="meishibot">
<image v-if="dishImages[1]" :src="dishImages[1] + '?imageView2/2/w/750/format/png'" mode="aspectFill">
</image>
<image v-if="dishImages[2]" :src="dishImages[2] + '?imageView2/2/w/750/format/png'" mode="aspectFill">
</image>
</view>
</view>
<view class="meishirt" @click="btnitem">
<view class="meishitop">
攻略推荐
<image class="jiantou"
src="https://api.ccttiot.com/smartmeter/img/static/uLbDD7xYvH9mgoM9yqXH" mode="">
</image>
</view>
<view class="mieshilist">
<view class="meishiitem" v-for="(item,index) in strategyList" :key="index">
<image :src="getFirstPhoto(item.photo)" mode="aspectFill" style="margin-right: 10rpx;"></image>
<view class="wz" style="width: 168rpx;">
<text class="tit" v-if="item.name">{{item.name.length > 7 ? item.name.slice(0,6) + '...' : item.name}}</text>
<text class="tits" style="display: block;width: 168rpx;" v-if="item.description">{{item.description.length > 15 ? item.description.slice(0,15) + '...' : item.description}}</text>
<!-- <text class="dz" v-if="item.areaAddress">{{item.areaAddress.length > 10 ? item.areaAddress.slice(0,9) + '...' : item.areaAddress}}</text> -->
</view>
</view>
</view>
</view>
</view>
</view>
<!-- 游玩推荐 @click="btnremen" -->
<view class="youwan">
<scroll-view class="ywtab" scroll-x="true" show-scrollbar="false" enhanced="true">
<view class="ywcontent">
<view class="ywitem" :class="{ 'active': selectedLocationValue === null }" @click="handleLocationClick(null)">
游玩推荐
</view>
<view class="ywitem" v-for="(item,index) in locationList" :key="index"
:class="{ 'active': selectedLocationValue === item.value }"
@click="handleLocationClick(item.value)">
{{ item.location }}
</view>
</view>
</scroll-view>
<view class="ywimg" v-if="recommendAreaHero && !loadingLocation" @click="btnyouwan(recommendAreaHero, 1)">
<image :src="recommendAreaHero.image + '?imageView2/2/w/750/format/png'" mode="aspectFill" class="img-fade-in"></image>
<view class="ywimg-text">
<text class="ywimg-text-inner">{{ recommendAreaHero.name }}</text>
</view>
</view>
<!-- 加载状态 -->
<view class="ywimg loading-placeholder" v-if="loadingLocation">
<view class="loading-skeleton"></view>
<view class="loading-text">加载中...</view>
</view>
<!-- 没有数据提示 -->
<view class="no-data-tip" v-if="!loadingLocation && !recommendAreaHero && recommendAreaCards.length === 0">
<view class="no-data-icon">📭</view>
<view class="no-data-text">该区域暂无推荐景区</view>
</view>
<view class="ywlist">
<view class="" v-for="(it, idx) in recommendAreaCards" :key="idx" @click="btnyouwan(it, 2)" v-show="!loadingLocation">
<image :src="it.image + '?imageView2/2/w/750/format/png'" mode="aspectFill" class="img-fade-in"></image>
<text>{{ it.name.length > 7 ? it.name.slice(0,7) + '...' : it.name }}</text>
</view>
<!-- 小图加载状态 -->
<template v-if="loadingLocation">
<view class="loading-skeleton-small" v-for="n in 3" :key="'loading-' + n">
<view class="skeleton-img"></view>
<view class="skeleton-text"></view>
</view>
</template>
</view>
</view>
<!-- 精品路线 -->
<view class="wenhua">
<scroll-view class="ywtab" scroll-x="true" show-scrollbar="false" enhanced="true">
<view class="ywcontent">
<view class="ywitem" :class="{ 'active': selectedTabValue === null }" @click="handleTabClick(null)">
精品路线
</view>
<view class="ywitem" v-for="(item,index) in glflbq" :key="index"
:class="{ 'active': selectedTabValue === item.dictValue }"
@click="handleTabClick(item.dictValue)">
{{ item.dictLabel }}
</view>
</view>
</scroll-view>
<view class="wrap">
<!-- 加载状态 -->
<view class="waterfall-loading" v-if="loadingTab">
<view class="loading-item" v-for="n in 6" :key="'loading-' + n">
<view class="skeleton-img-large"></view>
<view class="skeleton-title"></view>
<view class="skeleton-desc"></view>
</view>
</view>
<view class="waterfall-container" v-show="!loadingTab">
<view class="waterfall-left">
<view class="demo-warter item-fade-in" v-for="(item, index) in flowList.filter((_, i) => i % 2 === 0)" :key="index" @click="btngonglue(item)">
<u-lazy-load threshold="-450" border-radius="10" :image="getFirstPhoto(item.photo)"
:index="index"></u-lazy-load>
<view class="dizhi">
{{item.name && item.name.length > 10 ? item.name.slice(0,10) + '...' : item.name}}
</view>
<view class="cont">
{{!item.description ? '暂无简介' : (item.description.length > 26 ? item.description.slice(0,26) + '...' : item.description)}}
</view>
</view>
</view>
<view class="waterfall-right">
<view class="demo-warter item-fade-in" v-for="(item, index) in flowList.filter((_, i) => i % 2 === 1)" :key="index" @click="btngonglue(item)">
<u-lazy-load threshold="-450" border-radius="10" :image="getFirstPhoto(item.photo)"
:index="index"></u-lazy-load>
<view class="dizhi">
{{item.name && item.name.length > 10 ? item.name.slice(0,10) + '...' : item.name}}
</view>
<view class="cont">
{{!item.description ? '暂无简介' : (item.description.length > 26 ? item.description.slice(0,26) + '...' : item.description)}}
</view>
</view>
</view>
</view>
</view>
</view>
</scroll-view>
<tab-bar :indexs='0'></tab-bar>
</view>
</template>
<script>
export default {
data() {
return {
bgc: {
backgroundColor: "",
},
loadStatus: 'loadmore',
flowList: [],
list: [],
fixedTabVisible:false,
isAnimating: false,
isHiding: false,
video:[],
currentIndex: 0, // 当前轮播图索引
videoPlaying: {}, // 记录每个视频的播放状态
lists:[],
hotAreaList:[],// 热门景点
recommendAreaList:[],// 推荐景点
strategyList:[],// 攻略
dishList:[],// 美食
pageNum:1,
total:0,
ggobj:[],
ver:false,
scrollIndex: 0, // 当前滚动索引
scrollTimer: null, // 滚动定时器
noTransition: false ,// 是否禁用过渡动画(用于无缝重置)
glflbq:[],
selectedTabValue: null, // 当前选中的tab值null表示"全部"
locationList:[], // 位置列表
selectedLocationValue: null, // 当前选中的位置值null表示"全部"
loadingLocation: false, // 位置数据加载状态
loadingTab: false ,// 攻略数据加载状态
linshi:[]
}
},
// 分享到好友(会话)
onShareAppMessage: function() {
return {
title: '玩转福鼎',
path: '/pages/index/index'
}
},
// 分享到朋友圈
onShareTimeline: function() {
return {
title: '玩转福鼎',
query: '',
path: '/pages/index/index'
}
},
onShow() {
this.getyinc()
},
onLoad() {
this.getgonggao()
this.getinfo()
this.gethome()
this.getlunbos()
this.getlunbo()
this.addRandomData()
this.getglfl()
this.getLocationList()
uni.getLocation({
type: 'gcj02', // 国内地图更兼容
isHighAccuracy: true,
accuracy:'best',
success: (res) => {
console.log('精确坐标:', res)
},
fail: (err) => {
console.error('获取位置失败:', err)
}
})
},
onReady() {
// 启动分段滚动
this.startScroll()
},
onUnload() {
// 清除定时器
if (this.scrollTimer) {
clearInterval(this.scrollTimer)
this.scrollTimer = null
}
},
onReachBottom() {
// 检查是否还有更多数据
if(this.flowList.length >= this.total){
return
}
this.loadStatus = 'loading'
this.addRandomData()
// 延迟重置加载状态
setTimeout(() => {
this.loadStatus = 'loadmore'
}, 500)
},
computed: {
// 热门推荐
hotAreaImages() {
const list = Array.isArray(this.hotAreaList) ? this.hotAreaList : []
const pick = (itemIndex, pictureIndex) => {
const item = list[itemIndex]
if (!item || !item.picture) return ''
const parts = String(item.picture).split(',').filter(Boolean)
return parts[pictureIndex] || parts[0] || ''
}
return [
pick(0, 0),
pick(1, 1),
pick(2, 2)
].filter(Boolean)
},
// 热门推荐名称(与图片索引对齐)
hotAreaNames() {
const list = Array.isArray(this.hotAreaList) ? this.hotAreaList : []
const nameAt = (idx) => {
const item = list[idx]
return item && item.name ? String(item.name) : ''
}
return [nameAt(0), nameAt(1), nameAt(2)]
},
// 热门推荐简介与图片索引对齐超10字截断
hotAreaDescriptions() {
const list = Array.isArray(this.hotAreaList) ? this.hotAreaList : []
const descAt = (idx) => {
const item = list[idx]
const raw = item && item.description ? String(item.description) : ''
if (!raw) return ''
return raw.length > 10 ? (raw.slice(0, 10) + '...') : raw
}
return [descAt(0), descAt(1), descAt(2)]
},
// 推荐景点小图第2-4项最多三项
recommendAreaCards() {
const list = Array.isArray(this.recommendAreaList) ? this.recommendAreaList : []
return list.slice(1, 4).map(it => {
const src = (it && it.picture) ? String(it.picture) : ''
const img = src ? src.split(',').filter(Boolean)[0] || '' : ''
return {
image: img,
name: (it && it.name) ? it.name : '',
id: (it && it.id) ? it.id : ''
}
}).filter(it => it.image && it.name && it.id)
},
// 推荐景点大图(取第一项)
recommendAreaHero() {
const list = Array.isArray(this.recommendAreaList) ? this.recommendAreaList : []
if (!list.length) return null
const first = list[0]
if (!first) return null
const src = first.picture ? String(first.picture) : ''
const img = src ? src.split(',').filter(Boolean)[0] || '' : ''
const name = first.name || ''
const id = first.id || ''
if (!img || !name || !id) return null
return { image: img, name, id }
},
// 美食图片(最多三张)
dishImages() {
const list = Array.isArray(this.dishList) ? this.dishList : []
const firstThree = list.slice(0, 3)
const toImage = (item) => {
if (!item) return ''
// 优先使用 imageUrl若包含多图逗号分隔取第一张再兜底到 picture
const primary = item.imageUrl || item.image_url || ''
const fallback = item.picture || ''
const src = primary || fallback
if (!src) return ''
const parts = String(src).split(',').filter(Boolean)
return parts[0] || ''
}
return firstThree.map(toImage).filter(Boolean)
}
},
methods: {
// 请求位置列表
getLocationList(){
this.$u.get(`/app/scenicArea/location`).then(res =>{
if(res.code == 200){
this.locationList = res.data
}
})
},
// 请求攻略分类
getglfl(){
this.$u.get(`/system/dict/data/type/strategy_type`).then(res =>{
if(res.code == 200){
this.glflbq = res.data
}
})
},
getyinc(){
this.$u.get(`/system/config/configKey/app.version`).then(res =>{
if(res.code == 200){
if(res.data == this.$store.state.ver){
this.ver = true
}else{
this.ver = false
}
}
})
},
// 格式化公告标题,超出长度显示省略号
formatGonggaoTitle(title) {
if (!title || title === null) {
return '欢迎来到福鼎!'
}
const maxLength = 20 // 最大显示字符数,可根据实际宽度调整
if (title.length > maxLength) {
return title.substring(0, maxLength) + '...'
}
return title
},
// 点击查看公告列表
btngg(){
uni.navigateTo({
url:'/pages/gonggao-list'
})
},
btnlb(e){
console.log(e);
if(this.linshi[e].bstType == 2){
uni.navigateTo({
url:'/page_fenbao/remenxq?id=' + this.linshi[e].bstId
})
}else if(this.linshi[e].bstType == 1){
uni.navigateTo({
url:'/page_fenbao/zixunbao/huodongxq?id=' + this.linshi[e].bstId
})
}
},
// 请求公告
getgonggao(){
this.$u.get(`/app/article/list?pageNum=1&pageSize=1&type=6`).then(res =>{
if(res.code == 200){
this.ggobj = res.rows
// 数据加载后启动滚动
this.$nextTick(() => {
this.startScroll()
})
}
})
},
// 启动分段滚动
startScroll() {
// 清除之前的定时器
if (this.scrollTimer) {
clearInterval(this.scrollTimer)
}
// 如果只有一个文本项,不需要滚动
if (!this.ggobj || this.ggobj.length === 0) {
return
}
// 每3秒滚动一次
this.scrollTimer = setInterval(() => {
this.scrollIndex++
// 当滚动到第二个文本项时重置为0实现无缝循环
if (this.scrollIndex >= 2) {
setTimeout(() => {
// 禁用过渡,瞬间重置位置
this.noTransition = true
this.scrollIndex = 0
// 下一帧恢复过渡效果
this.$nextTick(() => {
this.noTransition = false
})
}, 500) // 等待过渡动画完成后再重置
}
}, 3000)
},
// 点击进行搜索
btnsousuo(){
this.$u.get("/getInfo").then(res =>{
if(res.code == 200){
uni.navigateTo({
url:'/page_user/sousuo/index'
})
}else if(res.code == 401){
uni.reLaunch({
url:'/pages/login/login'
})
}
})
},
// 请求个人信息
getinfo(){
this.$u.get("/getInfo").then(res =>{
if(res.code == 200){
}else if(res.code == 401){
this.getlogo()
}
})
},
// 静默登录
getlogo(){
let taht = this
wx.login({
success(res) {
if (res.code) {
let data = {
loginCode: res.code,
appId:taht.$store.state.appid
}
taht.$u.post('/wxLogin', data).then(res => {
if (res.code == 200) {
uni.setStorageSync('token', res.token)
taht.getinfo()
}
})
}
},
})
},
// 请求首页景区
gethome(){
this.$u.get(`/app/home`).then(res =>{
if(res.code == 200){
this.hotAreaList = res.data.hotAreaList; //热门景点
this.recommendAreaList = res.data.recommendAreaList //推荐景点
this.strategyList = res.data.strategyList //攻略
this.dishList = res.data.dishList //美食
}
})
},
// 请求推荐景点列表(根据位置筛选)
getRecommendAreaList(){
// 构建查询参数
let url = `/app/home`
// 如果选中了具体的位置(不是"全部"则添加location参数
if(this.selectedLocationValue !== null) {
url += `?location=${this.selectedLocationValue}`
}
this.$u.get(url).then(res =>{
if(res.code == 200){
// 只更新推荐景点数据,其他字段保持不变
this.recommendAreaList = res.data.recommendAreaList
}
}).finally(() => {
// 请求完成后关闭加载状态
this.loadingLocation = false
})
},
// 请求轮播图
getlunbos(){
this.$u.get(`/app/carousel/list?type=2`).then(res =>{
if(res.code == 200){
let arr = res.rows
this.linshi = res.rows
arr.forEach(item =>{
const compressedUrl = item.imageUrl + "?imageView2/2/w/750/format/png"
this.lists.push({
image:compressedUrl
})
})
}
})
},
getlunbo(){
this.$u.get(`/app/app/basicInfo/1`).then(res =>{
if(res.code == 200){
if(res.data.videoUrl){
let arr = res.data.videoUrl.split(',')
arr.forEach(item =>{
// 直接 push 视频 URL 字符串,而不是对象
if(item && item.trim()){
this.video.push(item.trim())
}
})
}
// if(res.data.carousel){
// let arr = res.data.carousel.split(',')
// arr.forEach(item =>{
// this.lists.push({
// image:item
// })
// })
// }
}
})
},
// 点击热门推荐跳转到列表
btnitem(){
uni.navigateTo({
url:'/page_fenbao/gonglue/index'
})
},
// 点击跳转游玩景点
btnyouwan(item, num){
if(!item || !item.id) {
console.error('缺少景点ID', item)
return
}
if(num == 1){
// 点击大图跳转
uni.navigateTo({
url:'/page_fenbao/remenxq?id=' + item.id
})
}else if(num == 2){
// 点击小图跳转
uni.navigateTo({
url:'/page_fenbao/remenxq?id=' + item.id
})
}
},
// 点击热门推荐页面图片跳转
btnremen(){
uni.navigateTo({
url:'/page_fenbao/remen'
})
},
// 点击跳转页面
btnpage(num){
if(num == 1){ //跳转导览
uni.navigateTo({
url:'/page_user/daolan'
})
}else if(num == 2){ //跳转攻略
uni.navigateTo({
url:'/page_fenbao/gonglue/index'
})
}else if(num == 3){ //跳转住宿
if(this.ver == true){
uni.navigateTo({
url:'/page_fenbao/jiudian/index'
})
}else{
uni.navigateToMiniProgram({ //跳转到美团app预定酒店
appId: 'wx7649daed8f2335c4', // 目标小程序的 AppID必须正确
path: '', // 跳转路径,空字符串表示首页
success(res) {
console.log('跳转成功', res);
},
fail(err) {
console.error('跳转失败', err);
// 常见失败原因AppID错误、用户拒绝跳转、目标小程序未上线
}
})
}
}else if(num == 4){ //跳转美食
uni.navigateTo({
url:'/page_user/meishi/index'
})
}else if(num == 5){ //跳转文化
uni.navigateTo({
url:'/page_user/wenhua/index'
})
}else if(num == 6){ //跳转导游
uni.navigateTo({
url:'/page_fenbao/daoyou/index'
})
}else if(num == 7){ //跳转停车
uni.navigateToMiniProgram({ //跳转到停车小程序
appId: 'wx2ed03cf29689fd2e', // 目标小程序的 AppID必须正确
path: '', // 跳转路径,空字符串表示首页
success(res) {
console.log('跳转成功', res);
},
fail(err) {
console.error('跳转失败', err);
// 常见失败原因AppID错误、用户拒绝跳转、目标小程序未上线
}
})
}else if(num == 8){
uni.navigateTo({
url:'/page_user/techan/index'
})
}
},
// 点击攻略跳转到攻略详情
btngonglue(item){
console.log(item);
uni.navigateTo({
url:'/page_fenbao/gonglue/gongluexq?id=' + item.id
})
},
// 获取第一个图片
getFirstPhoto(photo) {
if (!photo) return ''
// 如果是数组,取第一个元素
if (Array.isArray(photo)) {
return photo[0] || ''
}
// 如果是字符串,可能是逗号分隔的多个图片,取第一个
if (typeof photo === 'string') {
const parts = photo.split(',').filter(Boolean)
return parts[0] + '?imageView2/2/w/300/format/png' || ' '
}
return ''
},
// 处理tab点击事件
handleTabClick(dictValue) {
// 更新选中的tab值
this.selectedTabValue = dictValue
// 重置页码
this.pageNum = 1
// 设置加载状态
this.loadingTab = true
// 重新查询数据
this.addRandomData()
},
// 处理位置点击事件
handleLocationClick(dictValue) {
// 更新选中的位置值
this.selectedLocationValue = dictValue
// 设置加载状态
this.loadingLocation = true
// 只更新推荐景点数据
this.getRecommendAreaList()
},
// 瀑布流添加数据
addRandomData() {
// 构建查询参数
let url = `/app/strategy/list?pageNum=${this.pageNum}&pageSize=20`
// 如果选中了具体的tab不是"全部"则添加theme参数
if(this.selectedTabValue !== null) {
url += `&type=${this.selectedTabValue}`
}
// 直接添加所有数据,确保每个数据都能显示
this.$u.get(url).then(res => {
if(res.code == 200){
this.total = res.total
if(this.pageNum == 1){
// 第一页时清空列表
this.flowList = []
this.list = res.rows
}else{
// 后续页面追加数据
this.list = this.list.concat(res.rows)
}
// 处理数据并映射字段
res.rows.forEach((item, index) => {
this.flowList.push(item)
})
// 页码自增,为下次加载做准备
this.pageNum++
}
}).catch(err => {
console.error('加载瀑布流数据失败:', err)
}).finally(() => {
// 请求完成后关闭加载状态
this.loadingTab = false
})
},
// 页面滚动监听
onPageScroll(e) {
console.log(e,'监听页面滚动数据')
this.fixedTabVisible = e.scrollTop >= 6
// console.log('222',this.fixedTabVisible)
},
// 列表容器滚动监听
handleScroll(e) {
// 获取滚动容器的滚动位置
const scrollTop = e.detail.scrollTop || 0
const shouldShow = scrollTop >= 220
if (shouldShow !== this.fixedTabVisible && !this.isAnimating) {
if (shouldShow) { //根据shouldShow状态来确定头部的显示与隐藏
// 显示上下移动过渡动画
this.isHiding = false
this.fixedTabVisible = true
this.isAnimating = true
setTimeout(() => {
this.isAnimating = false
}, 500)
} else {
// 隐藏上下移动过渡动画
this.isHiding = true
this.isAnimating = true
setTimeout(() => {
this.fixedTabVisible = false
this.isHiding = false
this.isAnimating = false
}, 500)
}
}
console.log('111',this.fixedTabVisible, 'isHiding:', this.isHiding)
},
// 上拉加载更多
handqixing(){
console.log(this.total,this.flowList.length)
if(this.total > this.flowList.length){
this.addRandomData()
}
console.log('加载更多瀑布流数据')
},
// 轮播图切换事件
onSwiperChange(e) {
this.currentIndex = e.detail.current
// 暂停其他视频,播放当前视频
this.video.forEach((item, idx) => {
if (idx !== this.currentIndex) {
this.$set(this.videoPlaying, idx, false)
const videoContext = uni.createVideoContext('swiper-video-' + idx)
if (videoContext) {
videoContext.pause()
}
}
})
},
// 视频播放事件
handleVideoPlay(idx) {
// 更新播放状态
this.$set(this.videoPlaying, idx, true)
// 暂停其他视频
this.video.forEach((item, index) => {
if (index !== idx) {
this.$set(this.videoPlaying, index, false)
const videoContext = uni.createVideoContext('swiper-video-' + index)
if (videoContext) {
videoContext.pause()
}
}
})
},
// 视频暂停事件
handleVideoPause(idx) {
// 更新播放状态
this.$set(this.videoPlaying, idx, false)
},
// 播放视频 - 跳转到视频播放页面
playVideo() {
if (!this.video || this.video.length === 0) {
uni.showToast({
title: '视频加载中...',
icon: 'none'
})
return
}
const currentVideo = this.video[this.currentIndex]
if (currentVideo) {
uni.navigateTo({
url: `/pages/video/index?url=${encodeURIComponent(currentVideo)}`
})
}
},
}
}
</script>
<style lang="scss">
::v-deep .u-swiper-wrap{
border-radius: 0 !important;
}
::v-deep .u-list-image-wrap{
border-radius: 0 !important;
}
page {
background: #E5F9F3;
border-radius: 0rpx 0rpx 0rpx 0rpx;
position: fixed;
top: 0;
left: 0;
}
.bdbox {
width: 100%;
height: 88vh;
overflow: scroll;
box-sizing: border-box;
}
.bdboxs {
width: 100%;
height: 75vh;
overflow: scroll;
padding-bottom: 50rpx;
box-sizing: border-box;
position: relative;
z-index: 9;
background: #E5F9F3;
}
.wenhua {
margin-top: 26rpx;
width: 100%;
padding: 0 20rpx;
box-sizing: border-box;
.waterfall-container {
display: flex;
gap: 20rpx;
.waterfall-left,
.waterfall-right {
flex: 1;
}
}
.demo-warter {
border-radius: 10rpx;
margin-bottom: 20rpx;
background-color: #ffffff;
padding-bottom: 10rpx;
position: relative;
.shuju{
display: flex;
align-items: center;
margin-top: 10rpx;
justify-content: flex-end;
view{
font-size: 14rpx;
color: #3D3D3D;
margin-left: 32rpx;
image{
width: 20rpx;
height: 20rpx;
margin-right: 4rpx;
}
display: flex;
align-items: center;
}
}
.cont{
font-size: 24rpx;
color: #3D3D3D;
padding-left: 18rpx;
margin-top: 10rpx;
image{
width: 28rpx;
height: 28rpx;
margin-right: 8rpx;
}
}
.dizhi{
margin-top: 16rpx;
padding-left: 18rpx;
font-weight: 600;
font-size: 28rpx;
color: #3D3D3D;
}
}
.u-close {
position: absolute;
top: 32rpx;
right: 32rpx;
}
.demo-image {
width: 100%;
border-radius: 4px;
}
.demo-title {
font-size: 30rpx;
margin-top: 5px;
color: $u-main-color;
}
.demo-tag {
display: flex;
margin-top: 5px;
}
.demo-tag-owner {
background-color: $u-type-error;
color: #FFFFFF;
display: flex;
align-items: center;
padding: 4rpx 14rpx;
border-radius: 50rpx;
font-size: 20rpx;
line-height: 1;
}
.demo-tag-text {
border: 1px solid $u-type-primary;
color: $u-type-primary;
margin-left: 10px;
border-radius: 50rpx;
line-height: 1;
padding: 4rpx 14rpx;
display: flex;
align-items: center;
border-radius: 50rpx;
font-size: 20rpx;
}
.demo-price {
font-size: 30rpx;
color: $u-type-error;
margin-top: 5px;
}
.demo-shop {
font-size: 22rpx;
color: $u-tips-color;
margin-top: 5px;
}
.ywtab {
width: 100%;
.ywcontent {
display: flex;
align-items: center;
white-space: nowrap;
padding: 20rpx 0;
}
.ywitem {
font-weight: 600;
font-size: 30rpx;
color: #606060;
margin-right: 46rpx;
flex-shrink: 0;
min-width: 120rpx;
text-align: center;
transition: all 0.3s;
position: relative;
padding: 10rpx 20rpx;
background-repeat: no-repeat;
&.active {
color: #05895D;
font-weight: 700;
font-size: 32rpx;
background-image: url('/static/image/two.png');
background-size: contain;
background-position: right center;
padding-top: 20rpx;
padding-bottom: 20rpx;
}
}
image {
width: 150rpx;
height: 102rpx;
margin-right: 46rpx;
flex-shrink: 0;
}
}
}
.youwan {
margin-top: 26rpx;
width: 100%;
padding: 0 20rpx;
box-sizing: border-box;
.ywlist {
display: flex;
margin-top: 20rpx;
gap: 22rpx;
view {
width: 224rpx;
height: 118rpx;
border-radius: 6rpx;
position: relative;
padding-top: 80rpx;
image {
width: 224rpx;
height: 118rpx;
border-radius: 6rpx;
position: absolute;
top: 0;
left: 0;
z-index: -1;
}
text {
font-weight: 600;
font-size: 24rpx;
color: #FFFFFF;
background: linear-gradient(180deg, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0.7) 100%);
width: 224rpx;
display: inline-block;
padding-left: 14rpx;
height: 40rpx;
line-height: 40rpx;
border-radius:0 0 8rpx 8rpx;
}
}
}
.ywimg {
position: relative;
width: 100%;
height: 264rpx;
overflow: hidden;
image {
width: 100%;
height: 264rpx;
border-radius: 6rpx;
position: absolute;
top: 0;
left: 0;
z-index: 0;
}
.ywimg-text {
position: absolute;
left: 0;
bottom: 0;
right: 0;
padding: 24rpx 40rpx 24rpx;
z-index: 1;
background: linear-gradient(180deg, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0.7) 100%);
border-radius: 0 0 6rpx 6rpx;
.ywimg-text-inner {
display: block;
font-weight: 600;
font-size: 40rpx;
color: #FFFFFF;
text-shadow: 0 2rpx 4rpx rgba(0, 0, 0, 0.4);
}
}
}
.no-data-tip {
width: 100%;
height: 264rpx;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
background: #f5f5f5;
border-radius: 6rpx;
margin-top: 0;
.no-data-icon {
font-size: 80rpx;
margin-bottom: 20rpx;
}
.no-data-text {
font-size: 28rpx;
color: #999;
}
}
.ywtab {
width: 100%;
.ywcontent {
display: flex;
align-items: center;
white-space: nowrap;
padding: 20rpx 0;
}
.ywitem {
font-weight: 600;
font-size: 30rpx;
color: #606060;
margin-right: 46rpx;
flex-shrink: 0;
min-width: 120rpx;
text-align: center;
transition: all 0.3s;
position: relative;
padding: 10rpx 20rpx;
background-repeat: no-repeat;
&.active {
color: #05895D;
font-weight: 700;
font-size: 32rpx;
background-image: url('/static/image/one.png');
background-size: 80rpx 60rpx;
background-position: right center;
}
}
image {
width: 150rpx;
height: 102rpx;
margin-right: 46rpx;
flex-shrink: 0;
}
}
}
.meishi {
width: 100%;
display: flex;
justify-content: space-between;
.meishirt {
width: 352rpx;
height: 514rpx;
background: #F7B782;
border-radius: 10rpx 10rpx 10rpx 10rpx;
.mieshilist {
width: 342rpx;
height: 456rpx;
background: linear-gradient(153deg, #FFFFFF 20%, rgba(255, 255, 255, 0) 100%);
border-radius: 10rpx 10rpx 10rpx 10rpx;
margin-top: 12rpx;
padding-top: 22rpx;
.meishiitem {
display: flex;
align-items: center;
width: 298rpx;
height: 126rpx;
background: #FFFFFF;
box-shadow: 0rpx 4rpx 12rpx 0rpx rgba(0, 0, 0, 0.1);
border-radius: 6rpx 6rpx 6rpx 6rpx;
padding: 12rpx;
box-sizing: border-box;
margin: auto;
margin-bottom: 18rpx;
image {
width: 100rpx;
height: 100rpx;
border-radius: 6rpx;
}
.wz {
.tit {
font-weight: 600;
font-size: 24rpx;
color: #3D3D3D;
display: block;
}
.tits {
font-size: 20rpx;
color: #3D3D3D;
display: block;
margin-top: 4rpx;
}
.dz {
font-size: 16rpx;
color: #3D3D3D;
display: block;
margin-top: 12rpx;
}
}
}
}
.meishitop {
font-weight: 600;
font-size: 28rpx;
color: #664608;
width: 100%;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 24rpx;
padding-top: 8rpx;
box-sizing: border-box;
image {
width: 32rpx;
height: 32rpx;
}
}
}
.meishilt {
width: 342rpx;
height: 514rpx;
background: linear-gradient(41deg, #82D3F7 0%, rgba(218, 190, 255, 0) 100%);
border-radius: 10rpx 10rpx 10rpx 10rpx;
padding: 0 20rpx;
box-sizing: border-box;
.daimg {
width: 1;
height: 278rpx;
border-radius: 14rpx 14rpx 14rpx 14rpx;
margin-top: 4rpx;
margin-bottom: 14rpx;
}
.meishibot {
display: flex;
align-items: center;
justify-content: space-between;
width: 100%;
image {
width: 140rpx;
height: 140rpx;
border-radius: 14rpx 14rpx 14rpx 14rpx;
}
}
.meishitop {
display: flex;
align-items: center;
display: flex;
justify-content: space-between;
width: 100%;
.dibiaoimg {
width: 168rpx;
height: 54rpx;
}
.jiantou {
width: 32rpx;
height: 32rpx;
}
}
}
}
.remen {
width: 100%;
padding: 0 20rpx;
box-sizing: border-box;
.rementitle {
image {
width: 150rpx;
height: 102rpx;
}
}
.rmtopimg {
margin-top: 28rpx;
display: flex;
justify-content: space-between;
width: 100%;
.rmltimg {
image {
width: 342rpx;
height: 342rpx;
}
.rm-card {
position: relative;
height: 342rpx;
width: 342rpx;
overflow: hidden;
border-radius: 16rpx;
image {
width: 342rpx;
height: 342rpx;
display: block;
position: absolute;
top: 0;
left: 0;
z-index: 0;
}
.rm-bottom-mask {
position: absolute;
left: 0;
right: 0;
bottom: 0;
z-index: 1;
width: 100%;
min-height: 88rpx;
box-sizing: border-box;
padding: 24rpx 18rpx 18rpx;
background: linear-gradient(180deg, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0.6) 50%, rgba(0, 0, 0, 0.8) 100%);
border-radius: 0 0 16rpx 16rpx;
}
.name {
font-weight: 600;
font-size: 30rpx;
color: #FFFFFF;
display: block;
}
.jianjie {
font-size: 24rpx;
color: #FFFFFF;
margin-top: 4rpx;
display: block;
}
}
}
.rmrtimg {
display: flex;
flex-direction: column;
gap: 14rpx;
.rm-card {
position: relative;
height: 164rpx;
width: 352rpx;
overflow: hidden;
border-radius: 16rpx;
image {
width: 352rpx;
height: 186rpx;
display: block;
position: absolute;
top: 0;
left: 0;
z-index: 0;
object-fit: cover;
}
.rm-bottom-mask {
position: absolute;
left: 0;
right: 0;
bottom: 0;
z-index: 1;
width: 100%;
min-height: 88rpx;
box-sizing: border-box;
padding: 20rpx 18rpx 18rpx;
background: linear-gradient(180deg, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0.3) 50%, rgba(0, 0, 0, 0.7) 100%);
border-radius: 0 0 16rpx 16rpx;
}
.name {
font-weight: 600;
font-size: 30rpx;
color: #FFFFFF;
display: block;
}
.jianjie {
font-size: 24rpx;
color: #FFFFFF;
margin-top: 4rpx;
display: block;
}
}
}
}
}
.videoxc {
position: relative;
top: -40rpx;
width: 100%;
height: 440rpx;
background-color: #E5F9F3;
border-radius: 20rpx 20rpx 0 0;
overflow: hidden;
padding: 68rpx 50rpx 68rpx 60rpx;
box-sizing: border-box;
image{
position: absolute;
top: 18px;
left: 50%;
transform: translateX(-50%);
width: 720rpx;
height: 400rpx;
}
.swiper {
width: 100%;
height: 100%;
border-radius: 16rpx;
overflow: hidden;
}
.media-wrap {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
position: relative;
video {
width: 100%;
height: 100%;
border-radius: 16rpx;
}
.play-overlay {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
z-index: 1;
/* 覆盖层可以点击,但不会阻挡 video 控件的使用 */
/* 点击视频区域(非控件区域)时跳转 */
.play-icon {
width: 120rpx;
height: 120rpx;
background-color: rgba(0, 0, 0, 0.5);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.3s;
&:active {
background-color: rgba(255, 107, 153, 0.7);
transform: scale(0.95);
}
text {
font-size: 48rpx;
color: #fff;
margin-left: 8rpx; /* 让播放图标稍微右移,看起来更居中 */
line-height: 1;
}
}
}
}
}
.fenlei-container {
margin-top: 520rpx;
.fenlei-scroll {
width: 100%;
height: 288rpx;
white-space: nowrap;
}
.fenlei {
width: 750rpx;
height: 280rpx;
overflow: scroll;
background: linear-gradient(17deg, #2FC1DE 0%, #9CF1BB 62%, rgba(212, 248, 174, 1) 100%), rgba(0, 0, 0, 0.1);
border-radius: 0rpx 0rpx 0rpx 0rpx;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 20rpx;
gap: 30rpx;
.icon {
flex-shrink: 0;
width: 104rpx;
height: 136rpx;
display: flex;
align-items: center;
justify-content: center;
image {
width: 104rpx;
height: 136rpx;
}
}
}
}
.gonggao {
width: 670rpx;
height: 66rpx;
background: linear-gradient( 90deg, rgba(255,255,255,0.05) 0%, rgba(255,255,255,0.5) 49.7%, rgba(255,255,255,0.05) 100%);
// border-radius: 37rpx 37rpx 37rpx 37rpx;
display: flex;
align-items: center;
padding-left: 26rpx;
padding-right: 30rpx;
position: absolute;
top: 26rpx;
left: 50%;
transform: translateX(-50%);
z-index: 2;
overflow: hidden;
image {
width: 38rpx;
height: 38rpx;
margin-right: 26rpx;
flex-shrink: 0;
}
.gonggao-text-wrapper {
flex: 1;
overflow: hidden;
position: relative;
height: 100%;
display: flex;
align-items: flex-start;
}
.gonggao-text-content {
display: flex;
flex-direction: column;
transition: transform 0.5s ease-in-out;
will-change: transform;
&.no-transition {
transition: none;
}
}
.gonggao-text-item {
display: flex;
align-items: center;
font-size: 28rpx;
color: #05895D;
height: 66rpx;
flex-shrink: 0;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
max-width: 100%;
}
}
.serach {
display: flex;
align-items: center;
position: relative;
top: 100rpx;
z-index: 999 !important;
.touxiang {
width: 60rpx;
height: 60rpx;
background-color: #fff;
border-radius: 50%;
margin-left: 24rpx;
}
.shuru {
position: relative;
margin-left: 24rpx;
image {
width: 32rpx;
height: 32rpx;
position: absolute;
left: 38rpx;
top: 18rpx;
}
input {
width: 306rpx;
height: 60rpx;
background: #FFFFFF;
border-radius: 30rpx 30rpx 30rpx 30rpx;
padding-left: 86rpx;
}
}
}
.topimg {
width: 750rpx;
height: 588rpx;
position: absolute;
top: 0;
left: 0;
z-index: 1;
}
/* 固定分类容器样式 */
.fixed-container {
position: fixed;
top: 0;
left: 0;
z-index: 999;
margin-top: 0;
background: linear-gradient(17deg, #2FC1DE 0%, #9CF1BB 62%, #d4f8ae 100%), rgba(0, 0, 0, 0.1);
width: 100%;
}
/* 上下移动动画样式 */
.fade-in {
animation: slideDown 0.5s ease-out forwards;
}
.fade-out {
animation: slideUp 0.5s ease-in forwards;
}
@keyframes slideDown {
from {
transform: translateY(-100%);
opacity: 0;
}
to {
transform: translateY(0);
opacity: 1;
}
}
@keyframes slideUp {
from {
transform: translateY(0);
opacity: 1;
}
to {
transform: translateY(-100%);
opacity: 0;
}
}
/* 图片淡入动画 */
.img-fade-in {
animation: imgFadeIn 0.5s ease-in;
}
/* 列表项淡入动画 */
.item-fade-in {
animation: itemFadeIn 0.5s ease-in;
}
@keyframes imgFadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
@keyframes itemFadeIn {
from {
opacity: 0;
transform: translateY(20rpx);
}
to {
opacity: 1;
transform: translateY(0);
}
}
/* 游玩推荐加载状态 */
.loading-placeholder {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
background: #f5f5f5;
border-radius: 6rpx;
.loading-skeleton {
width: 100%;
height: 264rpx;
background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);
background-size: 200% 100%;
animation: skeleton-loading 1.5s ease-in-out infinite;
border-radius: 6rpx;
}
.loading-text {
margin-top: 20rpx;
font-size: 24rpx;
color: #999;
}
}
.loading-skeleton-small {
width: 224rpx;
height: 118rpx;
border-radius: 6rpx;
background: #f5f5f5;
position: relative;
overflow: hidden;
.skeleton-img {
width: 100%;
height: 100%;
background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);
background-size: 200% 100%;
animation: skeleton-loading 1.5s ease-in-out infinite;
}
.skeleton-text {
position: absolute;
bottom: 10rpx;
left: 14rpx;
width: 60%;
height: 20rpx;
background: linear-gradient(90deg, #e0e0e0 25%, #d0d0d0 50%, #e0e0e0 75%);
background-size: 200% 100%;
animation: skeleton-loading 1.5s ease-in-out infinite;
border-radius: 4rpx;
}
}
/* 精品路线加载状态 */
.waterfall-loading {
display: flex;
flex-wrap: wrap;
gap: 20rpx;
.loading-item {
width: calc(50% - 10rpx);
background: #fff;
border-radius: 10rpx;
padding-bottom: 10rpx;
overflow: hidden;
.skeleton-img-large {
width: 100%;
height: 300rpx;
background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);
background-size: 200% 100%;
animation: skeleton-loading 1.5s ease-in-out infinite;
}
.skeleton-title {
width: 70%;
height: 30rpx;
margin: 16rpx 0 10rpx 18rpx;
background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);
background-size: 200% 100%;
animation: skeleton-loading 1.5s ease-in-out infinite;
border-radius: 4rpx;
}
.skeleton-desc {
width: 85%;
height: 24rpx;
margin-left: 18rpx;
background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);
background-size: 200% 100%;
animation: skeleton-loading 1.5s ease-in-out infinite;
border-radius: 4rpx;
}
}
}
/* 骨架屏加载动画 */
@keyframes skeleton-loading {
0% {
background-position: 200% 0;
}
100% {
background-position: -200% 0;
}
}
</style>