前言
在vue3中滚动至一定高度tab按钮吸顶(h5中在header下、小程序中置顶),动态计算出后台返回的数据长度通过长度展示不同的样式
目录
一、templete部分
<template>
<div @scroll="changeScroll" class="series_container">
<v-header :headerOpt="headerOpt" :title="title"></v-header>
<div id="bannerfix">
<div class="banner">
<img class="bannerImg" src="https://img-blog.csdnimg.cn/a432feb7b8c445dc8df68f71cabdc584.png?x-oss-process=image/resize,m_fixed,h_300,image/format,png" alt="">
</div>
<div class="desbox">
<div class="title">我是标题1111111111111111111111111111111111111111111111111111111</div>
<div class="des_flex">
<div ref="descontent" :class="['des',desFlag?'showFlag':'']">我是详情描述我是详情描述我是详情描述我是详情描述我是详情描述我是详情描述我是详情描述我是详情描述我是详情描述我是详情描述我是详情描述我是详情描述我是详情描述我是详情描述我是详情描述我是详情描述我是详情描述我是详情描述</div>
<div v-if="!showdesFlag" :class="['btn',desFlag?'':'showbtn']" @click="desFlag=!desFlag"></div>
</div>
</div>
</div>
<div :class="['series_main',scrollTopflag?'mainfix':'']">
<div :class="['tab',scrollTopflag&&isWechat?'tabfix1':'',scrollTopflag&&!isWechat?'tabfix':'']">
<div :class="['tab_btn',chooseTab==1?'tabActive':'']" @click="changeTab(1)">tab1<div class="border"></div></div>
<div :class="['tab_btn',chooseTab==2?'tabActive':'']" @click="changeTab(2)">tab2</div>
</div>
<div v-if="chooseTab==1">
<div class="series_detail">测试数据</div>
</div>
<div class="ser_list" v-if="chooseTab==2">
<div class="ser_item" @click="toDetail(item)" v-for="(item,index) in 10" :key="index+'index'">
<div class="lef">
<img class="lef_img" src="https://p.qqan.com/up/2022-9/16644325731126722.jpg" alt="">
</div>
<div class="rig">
<div>
<div class="rigtitle">我是目录标题</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
二、script部分
<script>
import { defineComponent, nextTick, onMounted, ref } from 'vue'
import { useRouter, useRoute } from 'vue-router'
import { seriesCourseDetail } from "../../api/class/class";
import header from '../../components/header.vue'
export default defineComponent({
components: {
"v-header":header,
},
setup() {
const router = useRouter(),
route = useRoute()
const title = ref(route.name || '')
let seriesInfo=ref({})//详情信息
let descontent=ref(null)//获取元素
let desFlag=ref(false)//展示样式
let chooseTab=ref(1)//选中tab
let showdesFlag=ref(false)//是否展示按钮
const u = navigator.userAgent;
let isiOS=ref(false)
let isWechat=ref(false)
isWechat.value=sessionStorage.getItem("isminiPro") ? true : false;//是否小程序
isiOS.value = !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/); //ios终端
const headerOpt = ref({
backUrl: "",
backQuery: {},
});
const query = ref({
queryStr: "",
paramObj: {},
});
let scrollTopflag=ref(false)//滚动flag
let redirectUri = "";
let openId = ref("");
//对参数处理
const getParams = () => {
let urlQuery = window.location.href.split("?")[1];
let arr = urlQuery.split("&");
let paramObj = {};
arr.forEach((item) => {
let itemArr = item.split("=");
paramObj[itemArr[0]] = itemArr[1];
});
query.value.queryStr = urlQuery; // 结果示例:code=code&seriesCode=123
query.value.paramObj = paramObj; // 结果示例:{ code: code, seriesCode:123 }
};
//修改选中tab
const changeTab=(index)=>{
chooseTab.value=index
}
//获取信息
const getseriesCourseDetail=(params)=>{
seriesCourseDetail(params).then((res)=>{
if(res.data){
seriesInfo.value=res.data
nextTick(()=>{
init()
})
}
})
}
let init=()=>{
//计算课程介绍高度
let lineHeight =22
if(descontent.value.offsetHeight >lineHeight*1){
desFlag.value=true
}else{
showdesFlag.value=true
}
}
//fix顶部打开
let changeScroll=(e)=>{
let tarScro = e.target.scrollTop
let fixheight=document.getElementById('bannerfix').clientHeight
if(tarScro>=fixheight-10){
// console.log('fix顶部了');
scrollTopflag.value=true
}else{
scrollTopflag.value=false
}
}
onMounted(() => {
getParams()
if(route.query.seriesCode){
getseriesCourseDetail(route.query.seriesCode)
}
})
return {
title,
chooseTab,
seriesInfo,
desFlag,
descontent,
showdesFlag,
isiOS,
isWechat,
headerOpt,
scrollTopflag,
changeTab,
changeScroll,
}
},
})
</script>
三、style
.series_container{
height: 100vh;
background-color: #F6F8FA;
padding-bottom: 1.2rem;
box-sizing: border-box;
overflow-x: hidden;
overflow-y: auto;
}
.series_container1{
padding-bottom: 0;
}
.series_container .banner{
height: 5.64rem;
display: -webkit-box;
-webkit-box-pack: center;
-webkit-box-align: center;
overflow: hidden;
}
.series_container .banner .bannerImg{
max-width: 100%;
max-height: 100%;
}
.series_container .desbox{
padding: .32rem .24rem;
background-color: #fff;
margin-bottom: .2rem;
}
.series_container .desbox .title{
font-weight: 500;
font-size: .32rem;
line-height: .48rem;
color: #000;
word-break: break-all;
}
.series_container .desbox .des_flex{
display: flex;
/* align-items: center; */
}
.series_container .desbox .des_flex .des{
flex:1;
font-size: .28rem;
line-height: .44rem;
color: #999999;
word-break: break-all;
}
.series_container .desbox .des_flex .showFlag{
overflow:hidden;
text-overflow:ellipsis;
white-space: nowrap;
/* display:-webkit-box;
-webkit-box-orient:vertical;
-webkit-line-clamp:1; */
}
.series_container .desbox .des_flex .btn{
width: .40rem;
height: .28rem;
background: url('../../assets/arrow_down.png') center right no-repeat;
background-size: .28rem .28rem;
margin-top: .1rem;
}
.series_container .desbox .des_flex .showbtn{
background: url('../../assets/arrow_up.png') center right no-repeat;
background-size: .28rem .28rem;
}
.series_container .series_main{
background-color: #fff;
}
.series_container .series_main .tab .tab_btn .border{
width: .32rem;
height: 0px;
border: 0.02rem solid #EFEFEF;
transform: rotate(90deg);
position: absolute;
right: -.16rem;
}
.series_container .series_main .tab{
display: flex;
height: 1rem;
box-sizing: border-box;
/* border-bottom: 0.01rem solid #EFEFEF; */
}
.series_container .tabfix{
position: fixed;
top: .88rem;
width: 100%;
background-color: #FFFFFF;
z-index: 999;
}
.series_container .tabfix1{
position: fixed;
top: 0;
width: 100%;
background-color: #FFFFFF;
z-index: 999;
}
.series_container .mainfix{
padding-top: 1rem;
}
.series_container .series_main .tab .tab_btn{
flex: 1;
font-size: .28rem;
line-height: .48rem;
color: #151515;
border-radius: .08rem;
position: relative;
display: flex;
justify-content: center;
align-items: center;
}
.series_container .series_main .tab .tabActive{
color: #FF0095;
font-weight: bold;
}
.series_container .series_detail{
padding:0.24rem;
min-height: 4.82rem;
}
.series_container .series_detail img{
max-width: 100%;
max-height: 100%;
}
.series_container .series_main .ser_list{
padding: 0 .2rem;
}
.series_container .series_main .ser_item{
padding: .32rem 0;
border-bottom:.01rem solid #efefef ;
display: flex;
}
.series_container .series_main .ser_item .lef{
width: 2.16rem;
height: 1.62rem;
margin-right: .2rem;
display: -webkit-box;
-webkit-box-pack: center;
-webkit-box-align: center;
overflow: hidden;
position: relative;
border-radius: .08rem;
}
.series_container .series_main .ser_item .lef .lef_img{
max-width: 100%;
height: 100%;
}
.series_container .series_main .ser_item .rig{
display: flex;
flex-direction: column;
justify-content: space-between;
}
.series_container .series_main .ser_item .rig .rigtitle{
font-weight: 500;
font-size: .28rem;
width: 4.2rem;
line-height: .44rem;
color: #151515;
overflow:hidden;
text-overflow:ellipsis;
white-space: nowrap;
}
四、展示效果
五、白屏问题
以上代码经过测试在ios部分手机滑的快是切换存在白屏可能
换了一种写法
onMounted(() => {
window.addEventListener('scroll', changeScroll, false)
})
onUnmounted(() => {
window.removeEventListener("scroll", changeScroll);
});
去掉了templete写的滚动事件 @scroll="changeScroll",在事件委托中添加changeScroll事件,方法不变
在css中 添加 min-height: 100vh;
新增判断微信或者ios方法
/* 是否微信环境 */
export function wxEnv() {
let ua = window.navigator.userAgent.toLowerCase();
return ua.match(/MicroMessenger/i) == "micromessenger";
}
/* 是否ios终端 */
export function isIOS() {
let u = navigator.userAgent;
return !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/); //ios终端
}