全部代码:
const observers = [] // 用于存储所有观察者 -> 收集起来主要是为了当路由变化时效果之前的观察者。
export default {
// ... 省略
setup() {
const route = useRoute()
onMounted(() => {
initFirstScreen() // 初始化 -> 给首次渲染就在视口的元素加上自定义属性,这些元素永远不用加动画类
animateFn() // 执行核心脚本
})
// 元素是否在视口
const isElementInViewport = element => {
var rect = element.getBoundingClientRect()
const isInViewport =
rect.top >= 0 &&
rect.bottom <=
(window.innerHeight || document.documentElement.clientHeight)
return isInViewport
}
// 检查是否有自定义属性
const checkHasAttribute = element => {
return !!element.getAttribute('snow_is_show')
}
// 初始化函数
const initFirstScreen = () => {
const main = document.querySelector('.vp-doc>div') || []
const paragraphs = [...(main?.children || [])]
paragraphs.forEach(item => {
if (isElementInViewport(item)) {
item.setAttribute('snow_is_show', true)
}
})
}
// 核心脚本
const animateFn = () => {
const main = document.querySelector('.vp-doc>div') || []
const paragraphs = [...(main?.children || [])]
paragraphs.forEach(item => {
const observer = new IntersectionObserver(entries => {
entries.forEach(entry => {
if (entry.isIntersecting && !checkHasAttribute(item)) {
// 元素进入视口
item.classList.add('animate__animated')
item.classList.add('animate__fadeInUp')
item.setAttribute('snow_is_show', true)
}
})
})
observer.observe(item)
observers.push(observer)
})
}
// 清空所有 observer 的函数
const destructionObserver = () => {
observers.forEach(observe => {
observe.disconnect()
})
observers.length = 0
}
watch(
() => route.path,
() =>
nextTick(() => {
destructionObserver() // 先清空所有的观察者
initFirstScreen() // 再初始化一次 类似onMounted
animateFn() // 再次执行核心函数
})
)
},
Layout,
}
标签:const,observer,paragraphs,item,forEach,渐入,滚动,main,好看
From: https://blog.51cto.com/u_15997490/8968943