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 基础架构的支柱。由于企业严重依赖基于互联网的应用程序,由于网络相关问题,最终用户不受影响非常重要。因此,借助网络管理解决方案监控和提高网络性能对于保持企业始终正常运行至关重要。这将确保维护服务级别…...
uniapp 对接腾讯云IM群组成员管理(增删改查)
UniApp 实战:腾讯云IM群组成员管理(增删改查) 一、前言 在社交类App开发中,群组成员管理是核心功能之一。本文将基于UniApp框架,结合腾讯云IM SDK,详细讲解如何实现群组成员的增删改查全流程。 权限校验…...

label-studio的使用教程(导入本地路径)
文章目录 1. 准备环境2. 脚本启动2.1 Windows2.2 Linux 3. 安装label-studio机器学习后端3.1 pip安装(推荐)3.2 GitHub仓库安装 4. 后端配置4.1 yolo环境4.2 引入后端模型4.3 修改脚本4.4 启动后端 5. 标注工程5.1 创建工程5.2 配置图片路径5.3 配置工程类型标签5.4 配置模型5.…...

关于nvm与node.js
1 安装nvm 安装过程中手动修改 nvm的安装路径, 以及修改 通过nvm安装node后正在使用的node的存放目录【这句话可能难以理解,但接着往下看你就了然了】 2 修改nvm中settings.txt文件配置 nvm安装成功后,通常在该文件中会出现以下配置&…...
测试markdown--肇兴
day1: 1、去程:7:04 --11:32高铁 高铁右转上售票大厅2楼,穿过候车厅下一楼,上大巴车 ¥10/人 **2、到达:**12点多到达寨子,买门票,美团/抖音:¥78人 3、中饭&a…...

论文浅尝 | 基于判别指令微调生成式大语言模型的知识图谱补全方法(ISWC2024)
笔记整理:刘治强,浙江大学硕士生,研究方向为知识图谱表示学习,大语言模型 论文链接:http://arxiv.org/abs/2407.16127 发表会议:ISWC 2024 1. 动机 传统的知识图谱补全(KGC)模型通过…...

零基础在实践中学习网络安全-皮卡丘靶场(第九期-Unsafe Fileupload模块)(yakit方式)
本期内容并不是很难,相信大家会学的很愉快,当然对于有后端基础的朋友来说,本期内容更加容易了解,当然没有基础的也别担心,本期内容会详细解释有关内容 本期用到的软件:yakit(因为经过之前好多期…...

HDFS分布式存储 zookeeper
hadoop介绍 狭义上hadoop是指apache的一款开源软件 用java语言实现开源框架,允许使用简单的变成模型跨计算机对大型集群进行分布式处理(1.海量的数据存储 2.海量数据的计算)Hadoop核心组件 hdfs(分布式文件存储系统)&a…...
【Go语言基础【12】】指针:声明、取地址、解引用
文章目录 零、概述:指针 vs. 引用(类比其他语言)一、指针基础概念二、指针声明与初始化三、指针操作符1. &:取地址(拿到内存地址)2. *:解引用(拿到值) 四、空指针&am…...
省略号和可变参数模板
本文主要介绍如何展开可变参数的参数包 1.C语言的va_list展开可变参数 #include <iostream> #include <cstdarg>void printNumbers(int count, ...) {// 声明va_list类型的变量va_list args;// 使用va_start将可变参数写入变量argsva_start(args, count);for (in…...
Vite中定义@软链接
在webpack中可以直接通过符号表示src路径,但是vite中默认不可以。 如何实现: vite中提供了resolve.alias:通过别名在指向一个具体的路径 在vite.config.js中 import { join } from pathexport default defineConfig({plugins: [vue()],//…...