mirror of
https://github.com/zhigang1992/react.git
synced 2026-04-26 05:15:44 +08:00
docs: restore the scroll bar of the menu when hash changed
This commit is contained in:
16
lib/components/config-context.ts
Normal file
16
lib/components/config-context.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import React from 'react'
|
||||
|
||||
export interface Configs {
|
||||
onChange?: Function
|
||||
sidebarScrollHeight: number
|
||||
updateSidebarScrollHeight: Function
|
||||
}
|
||||
|
||||
export const defaultConfigs: Configs = {
|
||||
sidebarScrollHeight: 0,
|
||||
updateSidebarScrollHeight: () => {},
|
||||
}
|
||||
|
||||
export const ConfigContext = React.createContext<Configs>(defaultConfigs)
|
||||
|
||||
export const useConfigs = (): Configs => React.useContext(ConfigContext)
|
||||
@@ -1,6 +1,6 @@
|
||||
import React, { useMemo, useState } from 'react'
|
||||
import withDefaults from 'components/utils/with-defaults'
|
||||
import { ConfigContext } from 'lib/states/config-context'
|
||||
import { ConfigContext, Configs } from './config-context'
|
||||
|
||||
interface Props {
|
||||
onChange?: Function
|
||||
@@ -14,15 +14,15 @@ export type ConfigProviderProps = Props & typeof defaultProps
|
||||
const ConfigProvider: React.FC<React.PropsWithChildren<ConfigProviderProps>> = React.memo(({
|
||||
onChange, children,
|
||||
}) => {
|
||||
const [shouldScroll, setShouldScroll] = useState<boolean>(false)
|
||||
const updateShouldScroll = (next: boolean) => {
|
||||
setShouldScroll(next)
|
||||
const [scrollHeight, setScrollHeight] = useState<number>(0)
|
||||
const updateSidebarScrollHeight = (height: number) => {
|
||||
setScrollHeight(height)
|
||||
}
|
||||
const initialValue = useMemo(() => ({
|
||||
const initialValue = useMemo<Configs>(() => ({
|
||||
onChange,
|
||||
shouldScroll,
|
||||
updateShouldScroll,
|
||||
}), [onChange, shouldScroll])
|
||||
sidebarScrollHeight: scrollHeight,
|
||||
updateSidebarScrollHeight,
|
||||
}), [onChange, scrollHeight])
|
||||
|
||||
return (
|
||||
<ConfigContext.Provider value={initialValue}>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React, { useCallback, useMemo } from 'react'
|
||||
import { Button, useTheme, Spacer } from 'components'
|
||||
import useConfigs from 'lib/states/use-config'
|
||||
import { useConfigs } from './config-context'
|
||||
import MoonIcon from './icons/moon'
|
||||
import SunIcon from './icons/sun'
|
||||
import GithubIcon from './icons/github'
|
||||
|
||||
@@ -1,27 +1,17 @@
|
||||
import React, { Children, useEffect } from 'react'
|
||||
import React, { Children } from 'react'
|
||||
import Link from 'next/link'
|
||||
import { useRouter } from 'next/router'
|
||||
import useConfigs from 'lib/states/use-config'
|
||||
|
||||
export interface Props {
|
||||
onAcitve?: Function
|
||||
index: number
|
||||
total: number
|
||||
href: string
|
||||
}
|
||||
|
||||
const ActiveLink: React.FC<React.PropsWithChildren<Props>> = React.memo(
|
||||
({ children, index, href }) => {
|
||||
const { updateShouldScroll } = useConfigs()
|
||||
({ children, href }) => {
|
||||
const { pathname } = useRouter()
|
||||
const isActive = pathname === href
|
||||
const child = Children.only(children)
|
||||
|
||||
useEffect(() => {
|
||||
if (!isActive) return
|
||||
|
||||
updateShouldScroll && updateShouldScroll(index > 16)
|
||||
}, [isActive])
|
||||
|
||||
return (
|
||||
<Link href={href}>
|
||||
|
||||
@@ -1,17 +1,23 @@
|
||||
import React, { useEffect, useMemo, useRef } from 'react'
|
||||
import { withRouter, Router } from 'next/router'
|
||||
import React, { PropsWithChildren, useEffect, useRef } from 'react'
|
||||
import Router from 'next/router'
|
||||
import { useTheme, Spacer } from 'components'
|
||||
import SideItem, { SideItemProps, Sides } from './side-item'
|
||||
import useConfigs from 'lib/states/use-config'
|
||||
import { useConfigs } from '../config-context'
|
||||
|
||||
export interface Props {
|
||||
router: Router
|
||||
}
|
||||
|
||||
export type SideGroupProps = Props & SideItemProps
|
||||
|
||||
export type SideChildren = Sides | Array<Sides>
|
||||
|
||||
const areEqual = (
|
||||
preProps: Readonly<PropsWithChildren<SideGroupProps>>,
|
||||
nextProps: Readonly<PropsWithChildren<SideGroupProps>>,
|
||||
): boolean => {
|
||||
return preProps.sides.length === nextProps.sides.length
|
||||
}
|
||||
|
||||
export const SideGroup: React.FC<{ sides?: SideChildren }> = React.memo(({ sides }) => {
|
||||
if (!sides) return null
|
||||
sides = Array.isArray(sides) ? sides : [sides]
|
||||
@@ -21,17 +27,19 @@ export const SideGroup: React.FC<{ sides?: SideChildren }> = React.memo(({ sides
|
||||
export const Sidebar: React.FC<SideGroupProps> = React.memo(({ sides }) => {
|
||||
const theme = useTheme()
|
||||
const boxRef = useRef<HTMLDivElement>(null)
|
||||
const { shouldScroll, updateShouldScroll } = useConfigs()
|
||||
const totalHeight = useMemo<number>(() => {
|
||||
if (!sides || !Array.isArray(sides)) return 0
|
||||
return sides.length * 36
|
||||
}, [sides])
|
||||
|
||||
const { sidebarScrollHeight, updateSidebarScrollHeight } = useConfigs()
|
||||
|
||||
useEffect(() => {
|
||||
if (!boxRef.current || !shouldScroll) return
|
||||
updateShouldScroll && updateShouldScroll(false)
|
||||
boxRef.current.scrollTo({ top: boxRef.current.scrollHeight })
|
||||
}, [shouldScroll])
|
||||
Router.events.on('routeChangeStart', () => {
|
||||
if (!boxRef.current) return
|
||||
updateSidebarScrollHeight(boxRef.current.scrollTop || 0)
|
||||
})
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
if (!boxRef.current) return
|
||||
boxRef.current.scrollTo({ top: sidebarScrollHeight })
|
||||
}, [boxRef.current])
|
||||
|
||||
return (
|
||||
<div ref={boxRef} className="sides box">
|
||||
@@ -41,11 +49,10 @@ export const Sidebar: React.FC<SideGroupProps> = React.memo(({ sides }) => {
|
||||
<Spacer />
|
||||
<style jsx>{`
|
||||
.sides {
|
||||
height: ${totalHeight}px;
|
||||
width: 100%;
|
||||
padding-bottom: ${theme.layout.gap};
|
||||
}
|
||||
|
||||
|
||||
.box {
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
@@ -74,6 +81,6 @@ export const Sidebar: React.FC<SideGroupProps> = React.memo(({ sides }) => {
|
||||
`}</style>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
}, areEqual)
|
||||
|
||||
export default withRouter(Sidebar)
|
||||
export default Sidebar
|
||||
|
||||
@@ -26,9 +26,7 @@ const SideItem: React.FC<React.PropsWithChildren<SideItemProps>> = React.memo(({
|
||||
{!side.url && <ActiveCatalog name={side.name} />}
|
||||
{side.url && (
|
||||
<div className="link">
|
||||
<ActiveLink href={side.url} index={index} total={sides.length}>
|
||||
<a>{side.name}</a>
|
||||
</ActiveLink>
|
||||
<ActiveLink href={side.url}><a>{side.name}</a></ActiveLink>
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
import React from 'react'
|
||||
|
||||
export interface Configs {
|
||||
onChange?: Function
|
||||
shouldScroll?: boolean
|
||||
updateShouldScroll?: Function
|
||||
}
|
||||
|
||||
export const ConfigContext = React.createContext<Configs>({})
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
import React from 'react'
|
||||
import { ConfigContext, Configs } from './config-context'
|
||||
|
||||
const useConfigs = (): Configs => React.useContext(ConfigContext)
|
||||
|
||||
export default useConfigs
|
||||
Reference in New Issue
Block a user