app/pages/tabbar/vlog/index.nvue
2025-03-19 15:33:19 +08:00

569 lines
16 KiB
Plaintext
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="mypage" :id="pageId">
<!-- <list :id="pageId" class="page" :bounce="true" isSwiperList="true"> -->
<!-- 左中右的三个页面切换, 依次是: 附近 - 关注 - 推荐 -->
<swiper ref="swiper1" id="tab-bar-view" style="my-swiper" :style="{height: screenHeight + 'px'}"
:current="curIndex" @change="changeTopTab" @transition="onswiperscroll" @animationfinish="animationfinish"
@onAnimationEnd="animationfinish">
<!-- <swiper-item>
<view class="near-by" :style="{height: screenHeight+'px'}">
<text ref="fujin" :pid="0" :parentId="pageId" class="warn-info">暂未开放,敬请期待!</text>
</view>
</swiper-item> -->
<swiper-item>
<!-- <view v-if="myUserInfo == null" ref="videoFollowComp" class="my-follow" :style="{height: screenHeight+'px'}">
<text class="warn-info">请登录后查看!</text>
</view> -->
<video-follow-comp ref="videoFollowComp" :pid="1" :parentId="pageId" :screenHeight="screenHeight"
:playFollowStatus="playFollowStatus" :videoList="videoList" :refreshList="refreshList"
:pagingList="pagingList" @showLoading="showLoading" @hideLoading="hideLoading"
@letFollowVideoPause="letFollowVideoPause"
@displayVideoPaging="displayVideoPaging"></video-follow-comp>
</swiper-item>
<swiper-item>
<video-comp ref="videoComp" :pid="2" :parentId="pageId" :screenHeight="screenHeight"
:playStatus="playStatus" :videoList="videoList" :refreshList="refreshList" :pagingList="pagingList"
@showLoading="showLoading" @hideLoading="hideLoading"
@displayVideoPaging="displayVideoPaging"></video-comp>
</swiper-item>
</swiper>
<view class="header" id="head" :style="{marginTop:statusBarHeight+'px'}" v-if="!isLoading">
<text class="header-left"></text>
<view class="header-center">
<!-- <view class="header-item" @click="tapFollow(0)">
<text class="header-item-title">附近</text>
<view class="header-item-line" :class="{'activate-line': curIndex === 0}"></view>
</view>
<view class="header-item" @click="tapFollow(1)">
<text class="header-item-title">关注</text>
<view class="header-item-line" :class="{'activate-line': curIndex === 1}"></view>
</view>
<view class="header-item" @click="tapFollow(2)">
<text class="header-item-title">推荐</text>
<view class="header-item-line" :class="{'activate-line': curIndex === 2}"></view>
</view> -->
<scroll-view ref="tabbar1" id="tab-bar" class="tab-bar" :scroll="false" :scroll-x="true"
:show-scrollbar="false" :scroll-into-view="scrollInto">
<view style="flex-direction: column;flex: 1;">
<view style="flex-direction: row;flex: 1;justify-content: space-around;">
<view class="uni-tab-item" v-for="(tab,index) in tabList" :key="tab.id" :id="tab.id"
:ref="'tabitem'+index" :data-id="index" :data-current="index" @click="ontabtap">
<text class="uni-tab-item-title scroll-view-animation"
:class="tabIndex==index ? 'uni-tab-item-title-active' : ''">{{tab.name}}</text>
</view>
</view>
<view class="scroll-view-indicator">
<view ref="underline" class="scroll-view-underline" :class="'scroll-view-animation'"
:style="{left: indicatorLineLeft + 'px', width: indicatorLineWidth + 'px'}"></view>
</view>
</view>
</scroll-view>
<!-- <view class="tab-bar-line">tab-bar-line</view> -->
</view>
<image class="header-right-search normal-img" src="/static/images/icon-search.png" @click="goSearch">
</view>
<view class="header" :style="{marginTop:statusBarHeight+'px'}" v-if="isLoading">
<text class="header-left"></text>
<view class="header-center">
<view class="header-item">
<text class="header-refresh-title">下拉刷新视频</text>
</view>
</view>
<image class="header-right-search normal-img" src="/static/images/loading.gif">
</view>
<!-- 顶部切换的导航 end -->
</view>
<!-- </list> -->
</template>
<script>
let animation = weex.requireModule('animation')
let dom = weex.requireModule('dom');
let system = uni.getSystemInfoSync();
// 缓存每页最多
const MAX_CACHE_DATA = 100;
// 缓存页签数量
const MAX_CACHE_PAGE = 3;
const TAB_PRELOAD_OFFSET = 1;
import storage from "@/utils/storage.js"; //缓存
import {
vlogList
} from "@/api/vlog"
import {
isStrEmpty
} from '@/utils/tools.js'
import videoComp from '@/components/vlog/videoComp.nvue';
import videoFollowComp from '@/components/vlog/videoFollowComp.nvue';
export default {
components: {
videoComp,
videoFollowComp
},
data() {
return {
isLoading: false,
statusBarHeight: system.statusBarHeight,
screenHeight: system.screenHeight,
curIndex: 1,
playStatus: false,
playFollowStatus: false,
videoList: [], // 首页一开始查询所得的默认视频列表
refreshList: [], // 下拉刷新后获得的新的列表
pagingList: [], // 分页list
refresh: 0, // 从me页面传来的refresh用于退出登录后重新刷新当前页的视频
/////////////////
pageList: ['videoFollowComp', 'videoComp'],
tabList: [
{
id: "tab" + 0,
name: '关注',
pageid: 1
},
{
id: "tab" + 1,
name: '推荐',
pageid: 2
}
], //tabs内容,'fujin','videoFollowComp','videoComp'
indicatorLineLeft: 0,
indicatorLineWidth: 0,
cacheTab: [],
scrollInto: "",
pageId: "page",
tabIndex: 1,
}
},
onReady() {
this._lastTabIndex = 0;
this.swiperWidth = 0;
this.tabbarWidth = 0;
this.tabListSize = {};
this._touchTabIndex = 0;
this._headHeight = 100;
var timer = setTimeout(()=>{
this.selectorQuery();
clearTimeout(timer)
},100)
},
onTabItemTap: function(e) {
console.log(e)
// let tabIndex = e.index;
// this.playStatus = tabIndex === 0 ? true : false;
// 切换视频要做暂停或播放的判断
// let me = this;
// if (tabIndex == 0) {
// me.playStatus = false;
// me.playFollowStatus = true;
// } else if (tabIndex == 2) {
// me.playStatus = true;
// me.playFollowStatus = false;
// }
},
onShow() {
let me = this;
this.myUserInfo = storage.getVlogUserInfo() || null;
// 如果当前没有list, 则relaunch
if (this.$refs.videoComp != undefined) {
let playerList = this.$refs.videoComp.playerList;
if (playerList != undefined && playerList.length == 0) {
this.$refs.videoComp.displayVideoPaging(1, true);
}
}
// 判断如果当前是tab为1或2则播放否则不播放
if (me.curIndex == 0) {
me.playFollowStatus = true;
} else if (me.curIndex == 1) {
me.playStatus = true;
}
// onShow的时候关注的话则重新刷一下list
var justFollowVlogerId = uni.getStorageSync("justFollowVlogerId") || '';
console.log('我是justFollowVlogerId', justFollowVlogerId)
if (!isStrEmpty(justFollowVlogerId)) {
this.$refs.videoComp.reFollowPlayList(justFollowVlogerId);
uni.setStorageSync("justFollowVlogerId", "");
}
// 取消关注也要重新刷一下list
var justCancelVlogerId = uni.getStorageSync("justCancelVlogerId");
if (!isStrEmpty(justCancelVlogerId)) {
this.$refs.videoComp.reCancelPlayList(justCancelVlogerId);
uni.setStorageSync("justCancelVlogerId", "");
}
},
onHide() {
var me = this;
// 显示和隐藏需要判断根据不同tab做暂停或者隐藏
if (me.curIndex == 0) {
me.playFollowStatus = false;
} else if (me.curIndex == 1) {
me.playStatus = false;
}
},
// 当前页下拉刷新
onPullDownRefresh() {
var me = this;
// 下拉刷新判断如果是不同tab那么组件中刷新的请求也不同
if (me.curIndex == 0) {
this.$refs.videoFollowComp.displayVideoPaging(1, true);
} else if (me.curIndex == 1) {
this.$refs.videoComp.displayVideoPaging(1, true);
}
},
methods: {
// 前往搜索页面
goSearch() {
uni.navigateTo({
url: "/pages/search/search"
})
},
// ----------头部区域点击tabs
ontabtap(e) {
let index = e.target.dataset.current || e.currentTarget.dataset.current;
this.tapFollow(index)
this.switchTab(index);
},
//
selectorQuery() {
uni.createSelectorQuery().in(this).select('#head').boundingClientRect().exec(rect => {
this._headHeight = rect[0].height;
});
// 查询 tabbar 宽度
uni.createSelectorQuery().in(this).select('#tab-bar').boundingClientRect().exec(rect => {
this.tabbarWidth = rect[0].width;
console.log(this.tabbarWidth)
});
// 查询 tabview 宽度
uni.createSelectorQuery().in(this).select('#tab-bar-view').boundingClientRect().exec(rect => {
this.swiperWidth = rect[0].width;
console.log(this.swiperWidth)
});
// 因 nvue 暂不支持 class 查询
var queryTabSize = uni.createSelectorQuery().in(this);
for (var i = 0; i < this.tabList.length; i++) {
queryTabSize.select('#' + this.tabList[i].id).boundingClientRect();
}
queryTabSize.exec(rects => {
rects.forEach((rect) => {
rect.left = rect.left - 40; //修正 left 值,减去 padding-left: 40px
this.tabListSize[rect.dataset.id] = rect;
})
console.log(this.tabListSize[this.tabIndex])
this.updateIndicator(this.tabListSize[this.tabIndex].left, this.tabListSize[this.tabIndex]
.width);
this.switchTab(this.tabIndex);
});
},
onswiperscroll(e) {
var offsetX = e.detail.dx;
var preloadIndex = this._lastTabIndex;
if (offsetX > TAB_PRELOAD_OFFSET) {
preloadIndex++;
} else if (offsetX < -TAB_PRELOAD_OFFSET) {
preloadIndex--;
}
if (preloadIndex === this._lastTabIndex || preloadIndex < 0 || preloadIndex > this.pageList.length - 1) {
return;
}
let prop = this.pageList[preloadIndex]
let obj = this.$refs[prop]
if (obj.playerList.length === 0) {
// this.loadTabData(preloadIndex);
}
var percentage = Math.abs(this.swiperWidth / offsetX);
var currentSize = this.tabListSize[this._lastTabIndex];
var preloadSize = this.tabListSize[preloadIndex];
var lineL = currentSize.left + (preloadSize.left - currentSize.left) / percentage;
var lineW = currentSize.width + (preloadSize.width - currentSize.width) / percentage;
this.updateIndicator(lineL, lineW);
},
animationfinish(e) {
let index = e.detail.current;
this._lastTabIndex = index;
this.switchTab(index);
this.updateIndicator(this.tabListSize[index].left, this.tabListSize[index].width);
},
updateIndicator(left, width) {
// console.log(left)
// console.log(width)
this.indicatorLineLeft = left
this.indicatorLineWidth = width;
},
switchTab(index) {
// console.dir(this.$refs)
let props = this.pageList[index]
let obj = this.$refs[props]
if (obj.playerList.length === 0) {
// this.loadTabData(index);
}
obj.setScrollRef(this._headHeight);
if (this.tabIndex === index) {
return;
}
console.log(this.cacheTab)
// 缓存 tabId
if (obj.playerList.length > MAX_CACHE_DATA) {
let isExist = this.cacheTab.indexOf(this.tabIndex);
if (isExist < 0) {
this.cacheTab.push(this.tabIndex);
}
}
this.tabIndex = index;
this.curIndex = index;
this.scrollTabTo(index);
this.scrollInto = this.tabList[index].id;
// 释放 tabId
if (this.cacheTab.length > MAX_CACHE_PAGE) {
let cacheIndex = this.cacheTab[0];
this.clearTabData(cacheIndex);
this.cacheTab.splice(0, 1);
}
// const el = this.$refs['tabitem' + index][0];
// animation.transition(el, {
// duration: 3000, //ms
// timingFunction: 'ease',
// delay: 1000 //ms
// });
},
scrollTabTo(index) {
const el = this.$refs['tabitem' + index][0];
let offset = 0;
// TODO fix ios offset
if (index > 0) {
offset = this.tabbarWidth / 2 - this.tabListSize[index].width / 2;
if (this.tabListSize[index].right < this.tabbarWidth / 2) {
offset = this.tabListSize[0].width;
}
}
dom.scrollToElement(el, {
offset: -offset
});
},
//----------------------------
// 左滑右滑选项卡改变选中状态
changeTopTab: function(e) {
var current = e.detail.current;
this.switchTab(current)
this.curIndex = current;
this.tabIndex = current
this.playFollowStatus = this.curIndex === 1 ? true : false;
this.playStatus = this.curIndex === 2 ? true : false;
},
// 点击头部选项卡,切换页面
tapFollow: function(current) {
this.curIndex = current;
this.tabIndex = current
this.playFollowStatus = this.curIndex === 1 ? true : false;
this.playStatus = this.curIndex === 2 ? true : false;
},
// 下拉刷新改变head的字样显示
showLoading() {
this.isLoading = true;
},
hideLoading() {
this.isLoading = false;
},
letFollowVideoPause() {
this.playFollowStatus = false;
}
}
}
</script>
<style scoped>
/* index start */
.mypage {
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
background-color: #000000;
}
/* index end */
/* 顶部选项卡 start */
.header {
position: absolute;
left: 0;
right: 0;
flex-direction: row;
height: 100rpx;
line-height: 100rpx;
align-items: center;
padding-left: 40px;
padding-right: 40px;
}
.header-center {
flex: 1;
flex-direction: row;
align-items: center;
justify-content: center;
}
.header-left,
.header-right {
color: #999;
height: 100rpx;
line-height: 100rpx;
align-items: flex-start;
justify-content: flex-end;
font-family: iconfont;
}
.header-right-search {
height: 100rpx;
/* align-items: flex-start;
justify-content: flex-end; */
}
.header-item {
align-items: center;
margin-left: 6rpx;
margin-right: 6rpx;
}
.header-item-title {
width: 120rpx;
text-align: center;
height: 60rpx;
line-height: 60rpx;
color: #FFFFFF;
font-size: 16px;
font-weight: 600;
}
.header-refresh-title {
width: 300rpx;
text-align: center;
height: 60rpx;
line-height: 60rpx;
color: #FFFFFF;
font-size: 16px;
font-weight: 600;
}
.header-item-line {
height: 5rpx;
line-height: 8rpx;
width: 60rpx;
border-radius: 8rpx;
}
/* 顶部选项卡 end */
/* 选项卡轮播组件 start */
.my-swiper {
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
}
.near-by {
background-color: #000000;
align-items: center;
justify-content: center;
}
.my-follow {
background-color: #000000;
align-items: center;
justify-content: center;
}
/* 选项卡轮播组件 end */
.warn-info {
color: #FFFFFF;
font-size: 36rpx;
font-weight: 600;
}
.normal-img {
width: 50rpx;
height: 50rpx;
opacity: 0.8;
}
/* */
.tab-bar {
/* width: 750upx; */
flex: 1;
height: 84upx;
flex-direction: row;
white-space: nowrap;
justify-content: center;
align-items: center;
}
.uni-tab-item {
display: inline-block;
flex-wrap: nowrap;
/* padding-left: 25px; */
/* padding-right: 25px; */
}
.uni-tab-item-title {
color: #999;
font-size: 30upx;
height: 80upx;
line-height: 80upx;
flex-wrap: nowrap;
white-space: nowrap;
}
.uni-tab-item-title-active {
color: #FFFFFF;
}
.scroll-view-indicator {
position: relative;
height: 2px;
background-color: transparent;
}
.scroll-view-underline {
position: absolute;
top: 0;
bottom: 0;
width: 0;
/* background-color: #007AFF; */
background-color: #FFFFFF;
}
.scroll-view-animation {
transition-duration: 0.2s;
/* transition-property: transform; */
}
.tab-bar-line {
height: 1upx;
background-color: #cccccc;
}
</style>