vue3滚动条滚动后元素固定
代码地址:https://gitee.com/zzhua195/easyblog-web-vuee

Framework.vue
在这个布局组件中,监听main的滚动事件,获取滚动的距离,将它存入store,以便其它组件能够共享,监听到
<template><div class="header"><div class="header-wrapper"><Header></Header></div></div><div class="main" ref="mainRef"><router-view/><div class="main-footer" v-if="route.fullPath === '/blog' || route.fullPath === '/member'"><div class="content-wrapper"><Footer></Footer></div></div></div>
</template><script setup>import Header from './Header.vue';import Footer from './Footer.vue';import { onMounted,ref } from 'vue';import { useStore } from 'vuex'import store from '@/store';import { useRoute } from 'vue-router'const route = useRoute()const mainRef = ref(null)onMounted(()=>{// console.log(mainRef.value);mainRef.value.addEventListener('scroll',function(){store.commit('updateMainScrollTop',mainRef.value.scrollTop)})})</script><style lang="scss"></style>
Blog.vue
- 先给main-body-right动态绑定sitcky的类名,在这个类名下,先设置好固定定位的样式
- 监听store里的滚动距离,如果大于这个距离,就给main-body-right添加sticky这个类名,如果小于就删除这个类名
- 第三步也是最麻烦的,我们需要动态的获取到teamUserRef这个dom距离它的定位父元素的高度,不想写死这个高度。有几个坑踩过了:
- 不能直接在onMounted中获取mainRef距离它最近的定位父元素的高度,因为onMounted是在组件挂载完后执行,注意到,在setup里面,是通过promise发的异步请求,数据还没返回来,这个时候setup已经执行完了,用的是定义的最初的数据就进行了渲染
- 不能直接在then的回调中直接去拿mainRef距离它最近的定位父元素的高度,因为(js单线程),等到数据回来了(事件循环任务队列),执行完then回调后(整个then执行完),再执行的渲染,应该是要等到到渲染完毕,才能获取到这个距离,要放到nextTick里面才行。
- 因为在setup里面有获取专栏和专题这2个数据,也不知道谁先谁后,所以两个地方都写吧
- mainRef刚开始是直接写在BlogItem组件上的,发现拿到的是undefined,是因为vue3需要使用defineExpose把组件需要的东西暴露出来,才能拿到,拿到的也不是dom。我以为拿到的是dom,这是错的!
- 也可以监听BlogItem的finished事件,来获取这个高度,但是触发事件时也必须写在onUpdated里面,
- 下面是执行的打印情况,也可以从中看出vue它的执行过程,可以看到三个子组件先onMounted了,然后父组件就onMounted了,然后专栏的数据响应回来了,先把回调全部执行完(专栏同步),然后触发子组件更新,updated回调,然后nextTick就执行了,专题也是一样。



<template><div class="main-body content-wrapper" :style="{ 'min-height': 'calc(100% - 10px)' }"><div class="main-body-left"><BlogItem :blogInfo="blogInfo" v-for="blogInfo, index in blogDataInfo.list" :key="index" class="blog-info" /><el-pagination background layout="prev, pager, next" style="margin-bottom: 12px;":total="blogDataInfo.totalCount" @current-change="handleCurrentChange" :pageSize="blogDataInfo.pageSize" /></div><div :class="['main-body-right', { 'sticky': isSticky }]"><div><blog-side-item who="zhuanlan" @finished="finishd" title="分类专栏"><ul><li class="li-side-category" v-for="category, index in categoryListInfo" :key="index"><div class="side-category"><img class="avatar" :src="proxy.globalInfo.imageUrl + category.cover" alt=""><router-link :to="'/category/' + category.categoryId"><h2>{{ category.categoryName }}</h2></router-link></div><div class="count"><span>{{ category.blogCount }}篇</span></div></li></ul></blog-side-item></div><div><blog-side-item who="zhuanti" @finished="finishd" title="专题"><ul><li class="li-side-category" v-for="special, index in specialInfo.list" :key="index"><div class="side-category"><img class="avatar" :src="proxy.globalInfo.imageUrl + special.cover"><router-link :to="'/special/' + special.categoryId"><h2>{{ special.categoryName }}</h2></router-link></div><div class="count"><span>{{ special.blogCount }}篇</span></div></li></ul></blog-side-item></div><div style="transition:top 1s;" ref="teamUserRef"><blog-side-item who="team-user" title="博客成员" class="team-user" id="teamUser" ><ul><li v-for="userInfo, index in userListInfo" :key="index" class="user-li"><router-link :to="'/member#user-info-' + userInfo.userId" href="#" class="user-part"><img :src="proxy.globalInfo.imageUrl + userInfo.avatar" alt=""><div class="user-info"><div class="nick-name">{{ userInfo.nickName }}</div><div class="profession">{{ userInfo.profession }}</div></div></router-link><div class="count"><span>{{ userInfo.blogCount }}</span></div></li></ul></blog-side-item></div></div></div>
</template><script setup>
import { ref, reactive, getCurrentInstance, onMounted, onBeforeUnmount, watch, nextTick, onUpdated } from 'vue'
import BlogItem from './BlogItem.vue'
import BlogSideItem from './BlogSideItem.vue';
import Footer from '@/views/Footer.vue';
import { useStore } from 'vuex'
const store = useStore()
const { proxy } = getCurrentInstance()const topLength = ref(500)const api = {loadBlogList: "/view/loadBlogList",loadCategory: "/view/loadCategory",loadUser: "/view/loadTeamUser",loacSpecial: "/view/loadSpecial",
};const blogDataInfo = ref({pageSize: 10,pageNo: 1
})async function loadBlogList() {let result = await proxy.Request({url: api.loadBlogList,params: {pageSize: blogDataInfo.value.pageSize,pageNo: blogDataInfo.value.pageNo}})blogDataInfo.value = result
}
loadBlogList()
function handleCurrentChange(pageNo) {blogDataInfo.value.pageNo = pageNoloadBlogList()
}const categoryListInfo = ref({})
async function loadCategoryList() {let result = await proxy.Request({url: api.loadCategory,params: {pageSize: 5}})categoryListInfo.value = result/* topLength.value = teamUserRef.value.offsetTopconsole.log(teamUserRef.value.offsetTop, 1, '专栏'); */console.log('专栏同步');nextTick(()=>{topLength.value = teamUserRef.value.offsetTopconsole.log(teamUserRef.value.offsetTop, 1, '专栏');})
}
loadCategoryList()const userListInfo = ref([])async function loadUserInfoList() {let result = await proxy.Request({url: api.loadUser,params: {pageSize: 5}})userListInfo.value = result
}
loadUserInfoList()const specialInfo = ref([])async function loadSpecialList() {let result = await proxy.Request({url: api.loacSpecial,params: {pageSize: 3}})specialInfo.value = result/* topLength.value = teamUserRef.value.offsetTopconsole.log(teamUserRef.value.offsetTop, 2, '专题'); */console.log('专题同步');nextTick(()=>{topLength.value = teamUserRef.value.offsetTopconsole.log(teamUserRef.value.offsetTop, 2, '专题'); })
}
loadSpecialList()const isSticky = ref(false)
let val = null
const teamUserRef = ref(null)watch(() => store.state.mainScrollTop, (newVal, oldVal) => {// console.log('监听到: ' + newVal);if (newVal >= topLength.value) {isSticky.value = true} else {isSticky.value = false}
}, { immediate: true })onMounted(()=>{console.log(teamUserRef.value,'Blog.vue组件onMounted');
})function finishd(who) {topLength.value = teamUserRef.value.offsetTopconsole.log(teamUserRef.value.offsetTop, 'finished回调', who);
}onUpdated(()=>{console.log('Blog.vue组件更新了');
})
</script><style lang="scss" scoped>
.li-side-category {height: 52px;display: flex;justify-content: space-between;align-items: center;.count {margin-left: 5px;flex-shrink: 0;}.side-category {flex: 1;/* 开启省略的关键或者使用width:0 */overflow: hidden;display: inline-flex;align-items: center;.avatar {width: 40px;height: 40px;border-radius: 5px;margin-right: 5px;}a {text-overflow: ellipsis;white-space: nowrap;/* white-space属性为nowrap时,不会因为超出容器宽度而发生换行 */overflow: hidden;h2 {font-weight: normal;margin: 0;font-size: 16px;color: #1890ff;display: inline;}}}
}.user-li {padding: 10px 5px;display: flex;justify-content: space-between;align-items: center;.count {flex-shrink: 0;margin-left: 10px;}.user-part {display: inline-flex;align-items: center;flex-grow: 1;overflow: hidden;img {width: 50px;height: 50px;border-radius: 50%;margin-right: 10px;}.user-info {overflow: hidden;.nick-name {font-size: 20px;text-overflow: ellipsis;white-space: nowrap;overflow: hidden;}.profession {text-overflow: ellipsis;white-space: nowrap;overflow: hidden;color: #8d8d8d;font-size: 12px;}}}}.sticky .team-user {position: fixed;top: 90px;
}</style>
BlogItem.vue
<template><div class="side-item"><div class="side-item-top"><div class="title">{{ title }}</div><div class="more"><a href="#" title="更多" class="iconfont icon-gengduo1"></a></div></div><div class="side-item-body"><slot><div class="no-data">暂无数据</div></slot></div></div>
</template><script setup>
import { ref,reactive,onMounted,onUpdated } from 'vue'
const props = defineProps(['title','who'])
const emit = defineEmits(['finished'])
onMounted(()=>{console.log(props.who, 'onMounted');
})
onUpdated(()=>{console.log(props.who, 'updated');emit('finished',props.who)
})
defineExpose({'halo':'你好吗'
})
</script><style lang="scss">
.side-item {width: 300px;box-sizing: border-box;background-color: #fff;border-radius: 5px;padding: 8px;box-shadow: 0 3px 10px 0px rgb(0 0 0 / 10%);margin-bottom: 10px;.more a {color: #1890ff;font-size: 20px;}.side-item-top {height: 32px;line-height: 32px;display: flex;padding: 0 5px;justify-content: space-between;border-bottom: 1px solid #ddd;}.side-item-body {.no-data {color: #9a9a9a;height: 120px;display: flex;justify-content: center;align-items: center;}}
}
</style>
相关文章:
vue3滚动条滚动后元素固定
代码地址:https://gitee.com/zzhua195/easyblog-web-vuee Framework.vue 在这个布局组件中,监听main的滚动事件,获取滚动的距离,将它存入store,以便其它组件能够共享,监听到 <template><div c…...
新吲哚菁绿染料IR-825 NHS,IR825 NHS ester,IR825 SE,IR-825 活性酯,用于科研实验研究和临床
IR825 NHS理论分析:中文名:新吲哚菁绿-琥珀酰亚胺酯,IR-825 琥珀酰亚胺酯,IR-825 活性酯英文名:IR825 NHS,IR-825 NHS,IR825 NHS ester,IR825 SECAS号:N/AIR825 NHS产品详…...
GO语言--接口(interface)的定义及使用
接口定义 接口也是一种数据类型,它代表一组方法的集合。 接口是非侵入式的。即接口设计者无需知道接口被哪些类型实现,而接口使用者只需知道实现怎样的接口,并且无须指明实现哪一个接口。编译器在编译时就会知道哪个类型实现哪个接口&#…...
【Python语言基础】——Python MongoDB 查询
Python语言基础——Python MongoDB 查询 文章目录 Python语言基础——Python MongoDB 查询一、Python MongoDB 查询一、Python MongoDB 查询 筛选结果 在集合中查找文档时,您能够使用 query 对象过滤结果。 find() 方法的第一个参数是 query 对象,用于限定搜索。 实例 查找地…...
第十四届蓝桥杯模拟赛【第三期】Python
1 进制转换 问题描述 请找到一个大于 2022 的最小数,这个数转换成十六进制之后,所有的数位(不含前导 0)都为字母(A 到 F)。 请将这个数的十进制形式作为答案提交。 答案:2730 def ch…...
windows 下docker 安装clickhouse
docker 下载https://www.docker.com/products/docker-desktop/将下载下来的Docker Desktop Installer.exe文件双击进行安装即可,安装完成后,任务栏会出现一个蓝色的小鲸鱼图标(注意安装完成后可能会重启系统)Docker Desktop如果出…...
【华为OD机试真题 JAVA】TLV编码问题
标题:TLV编码问题 | 时间限制:1秒 | 内存限制:262144K | 语言限制:不限 TLV编码是按TagLengthValue格式进行编码的,一段码流中的信元用tag标识,tag在码流中唯一不重复,length表示信元value的长度,value表示信元的值,码流以某信元的tag开头,tag固定占一个字节,lengt…...
深度学习 Day26——使用Pytorch实现猴痘病识别
深度学习 Day26——使用Pytorch实现猴痘病识别 文章目录深度学习 Day26——使用Pytorch实现猴痘病识别一、前言二、我的环境三、前期工作1、设置GPU导入依赖项2、导入猴痘病数据集3、划分数据集四、构建CNN网络五、训练模型1、设置超参数2、编写训练函数3、编写测试函数4、正式…...
redis简单介绍
对于一名前端工程师,想要进阶成为全栈工程师,redis技术是我们一定需要掌握的。作为当前非关系型数据库Nosql中比较热门的key-value存储系统,了解redis的原理和开发是极其重要的。本文我会循序渐进的带领大家一步步认识redis,使用r…...
Understanding services:理解服务(Service)
文章目录背景1. 准备工作2. ros2 service list 命令3. ros2 service type 命令3.1 ros2 service list -t 命令4. ros2 service find 命令5. ros2 interface show 命令6. ros2 service call 命令参考官方文档: Understanding services背景 服务(Service&…...
【链表OJ题(五)】合并两个有序链表
📝个人主页:Sherry的成长之路 🏠学习社区:Sherry的成长之路(个人社区) 📖专栏链接:数据结构 🎯长路漫漫浩浩,万事皆有期待 文章目录链表OJ题(五)1. 合并…...
C++ Primer第五版_第三章习题答案(1~10)
文章目录练习3.1练习3.2一次读入一行一次读入一个词练习3.3练习3.4大的字符串长度大的字符串练习3.5未隔开的隔开的练习3.6练习3.7练习3.8练习3.9练习3.10练习3.1 使用恰当的using 声明重做 1.4.1节和2.6.2节的练习。 // 1.4.1 #include <iostream>using std::cin; using…...
小样本学习
机器学习就是从数据中学习,从而使完成任务的表现越来越好。小样本学习是具有有限监督数据的机器学习。类似的,其他的机器学习定义也都是在机器学习定义的基础上加上不同的限制条件衍生出来。例如,弱监督学习是强调在不完整、不准确、有噪声、…...
python打包成apk界面设计,python打包成安装文件
大家好,给大家分享一下如何将python程序打包成apk文件,很多人还不知道这一点。下面详细解释一下。现在让我们来看看! 1、如何用python制作十分秒加减的apk 如何用python制作十分秒加减的apk?用法:. apk包放入apk文件目录,然后输入…...
pytorch转onnx踩坑日记
在深度学习模型部署时,从pytorch转换onnx的过程中,踩了一些坑。本文总结了这些踩坑记录,希望可以帮助其他人。 首先,简单说明一下pytorch转onnx的意义。在pytorch训练出一个深度学习模型后,需要在TensorRT或者openvin…...
极智AI | GPT4来了,ChatGPT又该升级了
欢迎关注我,获取我的更多经验分享 大家好,我是极智视界,本文介绍一下 GPT4来了,ChatGPT又该升级了,更多的是个人思考。 邀您加入我的知识星球「极智视界」,星球内有超多好玩的项目实战源码下载,链接:https://t.zsxq.com/0aiNxERDq 从 ChatGPT 发布 (2022年11月30日) 到…...
智能优化算法之灰狼优化算法(GWO)的实现(Python附源码)
文章目录一、灰狼优化算法的实现思路1、社会等级结构分级2、包围猎物3、攻击猎物4、搜索猎物二、算法步骤三、实例一、灰狼优化算法的实现思路 灰狼优化算法(Grey Wolf Optimizer,简称GWO)是由Seyedali Mirjalili等人于2014年提出的一种群智…...
leetCode热题10-15 解题代码,思路
前言 计划做一系列算法题的文章,因为自己这块确实比较薄弱,但又很重要!写这篇文章前,我已经刷了一本剑指offer,leetcode top150道,牛客某题库106道 这个样子吧,感觉题量算是入门了吧࿱…...
同步辐射GISAXS和GIWAXS的原理及应用领域
同步辐射GISAXS和GIWAXS是两种常用的同步辐射X射线衍射技术,它们在材料科学、化学、生物学、物理学等领域中广泛应用。本文将从原理、实验方法和应用三个方面,对同步辐射GISAXS和GIWAXS进行描述和比较。 一、原理 GISAXS和GIWAXS都是利用X射线与样品相互…...
OpManager 进行网络性能管理
计算机网络构成了任何组织的 IT 基础架构的支柱。由于企业严重依赖基于互联网的应用程序,由于网络相关问题,最终用户不受影响非常重要。因此,借助网络管理解决方案监控和提高网络性能对于保持企业始终正常运行至关重要。这将确保维护服务级别…...
突破不可导策略的训练难题:零阶优化与强化学习的深度嵌合
强化学习(Reinforcement Learning, RL)是工业领域智能控制的重要方法。它的基本原理是将最优控制问题建模为马尔可夫决策过程,然后使用强化学习的Actor-Critic机制(中文译作“知行互动”机制),逐步迭代求解…...
服务器硬防的应用场景都有哪些?
服务器硬防是指一种通过硬件设备层面的安全措施来防御服务器系统受到网络攻击的方式,避免服务器受到各种恶意攻击和网络威胁,那么,服务器硬防通常都会应用在哪些场景当中呢? 硬防服务器中一般会配备入侵检测系统和预防系统&#x…...
学校招生小程序源码介绍
基于ThinkPHPFastAdminUniApp开发的学校招生小程序源码,专为学校招生场景量身打造,功能实用且操作便捷。 从技术架构来看,ThinkPHP提供稳定可靠的后台服务,FastAdmin加速开发流程,UniApp则保障小程序在多端有良好的兼…...
Python实现prophet 理论及参数优化
文章目录 Prophet理论及模型参数介绍Python代码完整实现prophet 添加外部数据进行模型优化 之前初步学习prophet的时候,写过一篇简单实现,后期随着对该模型的深入研究,本次记录涉及到prophet 的公式以及参数调优,从公式可以更直观…...
oracle与MySQL数据库之间数据同步的技术要点
Oracle与MySQL数据库之间的数据同步是一个涉及多个技术要点的复杂任务。由于Oracle和MySQL的架构差异,它们的数据同步要求既要保持数据的准确性和一致性,又要处理好性能问题。以下是一些主要的技术要点: 数据结构差异 数据类型差异ÿ…...
【python异步多线程】异步多线程爬虫代码示例
claude生成的python多线程、异步代码示例,模拟20个网页的爬取,每个网页假设要0.5-2秒完成。 代码 Python多线程爬虫教程 核心概念 多线程:允许程序同时执行多个任务,提高IO密集型任务(如网络请求)的效率…...
虚拟电厂发展三大趋势:市场化、技术主导、车网互联
市场化:从政策驱动到多元盈利 政策全面赋能 2025年4月,国家发改委、能源局发布《关于加快推进虚拟电厂发展的指导意见》,首次明确虚拟电厂为“独立市场主体”,提出硬性目标:2027年全国调节能力≥2000万千瓦࿰…...
wpf在image控件上快速显示内存图像
wpf在image控件上快速显示内存图像https://www.cnblogs.com/haodafeng/p/10431387.html 如果你在寻找能够快速在image控件刷新大图像(比如分辨率3000*3000的图像)的办法,尤其是想把内存中的裸数据(只有图像的数据,不包…...
java高级——高阶函数、如何定义一个函数式接口类似stream流的filter
java高级——高阶函数、stream流 前情提要文章介绍一、函数伊始1.1 合格的函数1.2 有形的函数2. 函数对象2.1 函数对象——行为参数化2.2 函数对象——延迟执行 二、 函数编程语法1. 函数对象表现形式1.1 Lambda表达式1.2 方法引用(Math::max) 2 函数接口…...
数据结构第5章:树和二叉树完全指南(自整理详细图文笔记)
名人说:莫道桑榆晚,为霞尚满天。——刘禹锡(刘梦得,诗豪) 原创笔记:Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊) 上一篇:《数据结构第4章 数组和广义表》…...
