Skip to content

Commit

Permalink
Merge branch 'main' of https://github.com/rzx007/nav
Browse files Browse the repository at this point in the history
  • Loading branch information
rzx007 committed Dec 3, 2023
2 parents bd2339b + 06489eb commit 0b96e04
Show file tree
Hide file tree
Showing 3 changed files with 161 additions and 1 deletion.
3 changes: 2 additions & 1 deletion docs/.vitepress/configs/sidebar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ export const sidebar: DefaultTheme.Config['sidebar'] = {
{ text: '复制高亮代码到剪贴板', link: '/html-dom/copy-highlighted-code-to-the-clipboard' },
{ text: '创建自定义滚动条', link: '/html-dom/create-a-custom-scrollbar' },
{ text: '基于流式数据的类似 chatgpt 的打字机式输出', link: '/html-dom/server-sent-events' },
{ text: '已同步方式实现事件监听', link: '/html-dom/async-addEventListener'}
{ text: '已同步方式实现事件监听', link: '/html-dom/async-addEventListener'},
{ text: '使用 vue 指令实现一个元素平滑上升的效果', link: '/html-dom/vue-slide-smooth' },
]
}
]
Expand Down
84 changes: 84 additions & 0 deletions docs/code/demo/vSlideIn.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
<template>
<div class="container">
<div class="item" v-for="i in 20" :key="i" v-slide-in></div>
</div>
</template>
<script setup>
const DISTANCE = 100
const DURATION = 1000
const map = new WeakMap() // 用户存储元素与动画的映射关系
// 判断元素是否在视口之下
const isBelowViewport = (el) => {
const rect = el.getBoundingClientRect()
return rect.top - DISTANCE > window.innerHeight
}
// 监听元素是否进入视口
const ob = new IntersectionObserver((entries) => {
for (const entry of entries) {
if (entry.isIntersecting) {
// 元素与视口相交了, 播放动画
const el = entry.target
// 获取动画
const animation = map.get(el)
if (animation) {
// 播放动画
animation.play()
// 播放完后取消监听
animation.onfinish = () => {
ob.unobserve(el)
}
}
}
}
})
const vSlideIn = {
mounted(el) {
// 元素在视口之上时不做任何事情
if (!isBelowViewport(el)) {
return
}
// Animate API
const animation = el.animate(
[
{
transform: `translateY(${DISTANCE}px)`,
opacity: 0.5
},
{
transform: 'translateY(0)',
opacity: 1
}
],
{
duration: DURATION,
easing: 'ease-in-out',
fill: 'forwards'
}
)
// 暂停动画
animation.pause()
ob.observe(el)
map.set(el, animation)
},
unmounted(el) {
ob.unobserve(el)
}
}
</script>
<style lang="scss" scoped>
.container {
align-items: center;
height: 32rem;
padding: 1rem;
background-color: #f7fafc;
border: 1px solid #cbd5e0;
overflow: auto;
.item {
width: 100%;
height: 16rem;
background-color: #9dc1d9;
margin-bottom: 1rem;
border-radius: 10px;
}
}
</style>
75 changes: 75 additions & 0 deletions docs/html-dom/vue-slide-smooth.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# 使用 vue 指令实现一个元素平滑上升的效果

::: info
创建一个 vSlideIn.js 文件
:::

```js
const DISTANCE = 100
const DURATION = 1000
const map = new WeakMap() // 用户存储元素与动画的映射关系
// 判断元素是否在视口之下
const isBelowViewport = (el) => {
const rect = el.getBoundingClientRect()
return rect.top - DISTANCE > window.innerHeight
}
// 监听元素是否进入视口
const ob = new IntersectionObserver((entries) => {
for (const entry of entries) {
if (entry.isIntersecting) {
// 元素与视口相交了, 播放动画
const el = entry.target
// 获取动画
const animation = map.get(el)
if (animation) {
// 播放动画
animation.play()
// 播放完后取消监听
animation.onfinish = () => {
ob.unobserve(el)
}
}
}
}
})

export default {
mounted(el) {
// 元素在视口之上时不做任何事情
if (!isBelowViewport(el)) {
return
}
// Animate API
const animation = el.animate(
[
{
transform: `translateY(${DISTANCE}px)`,
opacity: 0.5
},
{
transform: 'translateY(0)',
opacity: 1
}
],
{
duration: DURATION,
easing: 'ease-in-out',
fill: 'forwards'
}
)
// 暂停动画
animation.pause()
ob.observe(el)
map.set(el, animation)
},
unmounted(el) {
ob.unobserve(el)
}
}
```
### 示例

<script setup>
import vSlideIn from '../code/demo/vSlideIn.vue'
</script>
<vSlideIn />

0 comments on commit 0b96e04

Please sign in to comment.