-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
175 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
import { BasicTarget, TargetType, TargetValue } from '@/types'; | ||
|
||
export function getTargetElement<T extends TargetType>(target: BasicTarget<T>, defaultElement?: T) { | ||
if (!isBrowser) { | ||
return undefined; | ||
} | ||
|
||
if (!target) { | ||
return defaultElement; | ||
} | ||
|
||
let targetElement: TargetValue<T>; | ||
|
||
if (isFunction(target)) { | ||
targetElement = target(); | ||
} else if ('current' in target) { | ||
targetElement = target.current; | ||
} else { | ||
targetElement = target; | ||
} | ||
|
||
return targetElement; | ||
} | ||
|
||
const isBrowser = !!( | ||
typeof window !== 'undefined' && | ||
window.document && | ||
window.document.createElement | ||
); | ||
|
||
export default isBrowser; | ||
|
||
// eslint-disable-next-line @typescript-eslint/ban-types | ||
export const isFunction = (value: unknown): value is Function => typeof value === 'function'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
/** | ||
* title: Default usage | ||
* desc: Observe if the element is visible. | ||
* | ||
* title.zh-CN: 基础用法 | ||
* desc.zh-CN: 监听元素是否在可见区域内 | ||
*/ | ||
|
||
import React, { useRef } from 'react'; | ||
|
||
import { useInView } from '@nmsn/utils'; | ||
|
||
export default () => { | ||
const ref = useRef(null); | ||
const [inViewport] = useInView(ref); | ||
return ( | ||
<div> | ||
<div style={{ width: 300, height: 300, overflow: 'scroll', border: '1px solid' }}> | ||
scroll here | ||
<div style={{ height: 800 }}> | ||
<div | ||
ref={ref} | ||
style={{ | ||
border: '1px solid', | ||
height: 100, | ||
width: 100, | ||
textAlign: 'center', | ||
marginTop: 80, | ||
}} | ||
> | ||
observer dom | ||
</div> | ||
</div> | ||
</div> | ||
<div style={{ marginTop: 16, color: inViewport ? '#87d068' : '#f50' }}> | ||
inViewport: {inViewport ? 'visible' : 'hidden'} | ||
</div> | ||
</div> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
--- | ||
title: useInView | ||
toc: false | ||
--- | ||
|
||
# useInView | ||
|
||
观察元素是否在可见区域,以及元素可见比例。 | ||
|
||
<code src="./demo.tsx"></code> | ||
|
||
## API | ||
|
||
```typescript | ||
const [inView, ratio] = useInView( | ||
target, | ||
options?: Options | ||
); | ||
``` | ||
|
||
### Params | ||
|
||
| 参数 | 说明 | 类型 | 默认值 | | ||
| ------- | ---------------- | ----------------------------------------------------------- | ------ | | ||
| target | DOM 节点或者 ref | `Element` \| `() => Element` \| `MutableRefObject<Element>` | - | | ||
| options | 设置 | `Options` | - | | ||
|
||
### Options | ||
|
||
更多信息参考 [Intersection Observer API](https://developer.mozilla.org/zh-CN/docs/Web/API/Intersection_Observer_API) | ||
|
||
| 参数 | 说明 | 类型 | 默认值 | | ||
| ---------- | ------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------ | ------ | | ||
| threshold | 可以是单一的 number 也可以是 number 数组,target 元素和 root 元素相交程度达到该值的时候 ratio 会被更新 | `number` \| `number[]` | - | | ||
| rootMargin | 根(root)元素的外边距 | `string` | - | | ||
| root | 指定根(root)元素,用于检查目标的可见性。必须是目标元素的父级元素,如果未指定或者为 null,则默认为浏览器视窗。 | `Element` \| `Document` \| `() => (Element/Document)` \| `MutableRefObject<Element>` | - | | ||
|
||
### Result | ||
|
||
| 参数 | 说明 | 类型 | | ||
| ---------- | ----------------------------------------------------------- | ------------------------ | | ||
| inView | 是否可见 | `boolean` \| `undefined` | | ||
| ratio | 当前可见比例,在每次到达 `options.threshold` 设置节点时更新 | `number` \| `undefined` | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
import { useEffect, useState } from 'react'; | ||
|
||
import { getTargetElement } from '@/helper'; | ||
import { BasicTarget } from '@/types'; | ||
|
||
export interface Options { | ||
rootMargin?: string; | ||
threshold?: number | number[]; | ||
root?: BasicTarget<Element>; | ||
} | ||
|
||
function useInView(target: BasicTarget, options?: Options) { | ||
const [state, setState] = useState<boolean>(); | ||
const [ratio, setRatio] = useState<number>(); | ||
|
||
useEffect(() => { | ||
const el = getTargetElement(target); | ||
|
||
if (!el) { | ||
return; | ||
} | ||
|
||
const observer = new IntersectionObserver( | ||
entries => { | ||
for (const entry of entries) { | ||
setRatio(entry.intersectionRatio); | ||
setState(entry.isIntersecting); | ||
} | ||
}, | ||
{ | ||
...options, | ||
root: getTargetElement(options?.root), | ||
}, | ||
); | ||
|
||
observer.observe(el); | ||
|
||
return () => { | ||
observer.disconnect(); | ||
}; | ||
}, [options?.rootMargin, options?.threshold]); | ||
|
||
return [state, ratio] as const; | ||
} | ||
|
||
export default useInView; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,18 @@ | ||
import { MutableRefObject } from 'react'; | ||
|
||
export declare type ValueOf<T> = T[keyof T]; | ||
|
||
export declare type ArrayElement<A> = A extends readonly (infer T)[] ? T : never; | ||
|
||
export declare type GetKeyByValueType<T, Condition> = { | ||
[K in keyof T]: T[K] extends Condition ? K : never; | ||
}[keyof T]; | ||
|
||
export type TargetValue<T> = T | undefined | null; | ||
|
||
export type TargetType = HTMLElement | Element | Window | Document; | ||
|
||
export type BasicTarget<T extends TargetType = Element> = | ||
| (() => TargetValue<T>) | ||
| TargetValue<T> | ||
| MutableRefObject<TargetValue<T>>; |
ade47d4
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Successfully deployed to the following URLs:
utils – ./
nmsn-utils.vercel.app
utils-nmsn.vercel.app
utils-git-main-nmsn.vercel.app