#创作灵感
今天用固钉组件时发现element-ui的固钉会阻止移动端移动事件,我思来想去决定自己写一个固定组件得了
实现思路
获取钉子的ref实例并监听window滚动事件,当window.scrollY等于钉子的offsetHeight,添加position:fixed和top:0到钉子上,就能强行固定不动了。
这时候会有一个bug:如果元素本来并没有定位,直接添加定位属性会使其脱离文档流造成周围元素坍塌,这该怎么办?于是我再在下面添加一个div作为占位符,当内容被固定上去时,v-if渲染一个相同高度的div撑着文档流的内容,防止坍塌。slot插槽可以自由添加内容。最好在使用时加入z-index保证固钉优先显示
不知道为什么固定上去还需要额外设置宽度和原来一样,这点我也不懂
如果不生效,可以把affixStyle提出来放到一个类里,通过条件判断是否增加类来实现属性的改变
<template>
<!-- 我是钉子 -->
<div ref="dingzi" :style="affixStyle">
<slot></slot>
</div>
<!-- 我是占位符 -->
<div v-if="isTop" :style="{height:theHeight + 'px'}" >
</div>
</template>
<script setup>
import { ref, onMounted, onUnmounted } from 'vue'
const dingzi = ref(null)
const affixStyle = ref({}) // 固钉样式
const offsetT = ref()
const isTop = ref(false)
const theHeight = ref(0)
const handleScroll = () =>{
if (offsetT.value - window.scrollY <= 0 ){
affixStyle.value = {
position: 'fixed',
top: '0rem',
width:`${dingzi.value.offsetWidth}px` // 需要保持宽度不变 不然不知道为什么会坍塌
}
console.log('我在滚');
isTop.value = true
theHeight.value = dingzi.value.offsetHeight;
}else{
affixStyle.value = {}
isTop.value = false
}
}
onMounted(()=>{
window.addEventListener('scroll', handleScroll)
offsetT.value = dingzi.value.offsetTop
})
onUnmounted(()=>{
window.removeEventListener('scroll', handleScroll)
})
</script>