diff --git a/packages/core/src/fixed-view/fixed-view.tsx b/packages/core/src/fixed-view/fixed-view.tsx index f4bc58dfb..e20bf55b0 100644 --- a/packages/core/src/fixed-view/fixed-view.tsx +++ b/packages/core/src/fixed-view/fixed-view.tsx @@ -4,10 +4,13 @@ import classNames from "classnames"; import * as _ from "lodash"; import * as React from "react"; import { type PropsWithChildren, useRef } from "react"; -import { type PlaceholderProps, usePlaceholder } from "../placeholder"; +import { type PlaceholderProps } from "../placeholder"; import SafeArea, { type SafeAreaPosition } from "../safe-area"; import { prefixClassname } from "../styles"; import type { FixedViewPosition } from "./fixed-view.shared"; +import { useHeight } from "../hooks"; +import { addUnitPx } from "../utils/format/unit"; +import mergeStyle from "../utils/merge-style" function useFixedViewPlaceholder(placeholder?: boolean | string | PlaceholderProps) { if (placeholder === true) { @@ -46,7 +49,7 @@ function FixedView(props: FixedViewProps & T) { } = props; const rootRef = useRef(); const placeholder = useFixedViewPlaceholder(placeholderProp); - const Placeholder = usePlaceholder(rootRef); + const height = useHeight(rootRef); if (position !== "top" && position !== "bottom" && position !== true) { return children as JSX.Element; @@ -72,12 +75,14 @@ function FixedView(props: FixedViewProps & T) { ); if (placeholder) { - const { className: placeholderClassName, ...restPlaceholder } = placeholder; + const { className: placeholderClassName, style: styleProp, ...restPlaceholder } = placeholder; + const style = mergeStyle(styleProp, height ? { height: addUnitPx(height) } : {}); return ( - ); } diff --git a/packages/core/src/hooks/use-height.ts b/packages/core/src/hooks/use-height.ts index 0b598f016..ef85c89d2 100644 --- a/packages/core/src/hooks/use-height.ts +++ b/packages/core/src/hooks/use-height.ts @@ -1,15 +1,21 @@ -import { DependencyList, useState, useCallback } from "react" +import { DependencyList, useState, useCallback, useRef } from "react" import { nextTick } from "@tarojs/taro" import { getRect } from "../utils/dom/rect" import { useRenderedEffect, useMounted, useWindowResize } from "./index" export default function useHeight(elementOrRef: any, deps?: DependencyList) { const [height, _setHeight] = useState(0) + const heightRef = useRef(0) const setHeight = useCallback(() => { getRect(elementOrRef) .then((rect) => rect?.height) - .then(_setHeight) + .then((val) => { + if (val !== heightRef.current) { + heightRef.current = val + _setHeight(val) + } + }) // eslint-disable-next-line react-hooks/exhaustive-deps }, []) diff --git a/packages/core/src/input/native-input.scss b/packages/core/src/input/native-input.scss index 45b7839e8..94caea8e3 100644 --- a/packages/core/src/input/native-input.scss +++ b/packages/core/src/input/native-input.scss @@ -6,6 +6,7 @@ width: inherit; min-width: inherit; height: inherit; + min-height: inherit; line-height: inherit; color: inherit; resize: inherit; diff --git a/packages/core/src/list/README.md b/packages/core/src/list/README.md index 140057cf5..e4d2af180 100644 --- a/packages/core/src/list/README.md +++ b/packages/core/src/list/README.md @@ -157,7 +157,7 @@ function ErrorList() { ### 下拉刷新 -List 组件可以与 [PullRefresh](/components/pull-refresh/) 组件结合使用,实现下拉刷新的效果。 +List 组件可以与 [PullRefresh](/components/pull-refresh/) 组件结合使用,实现下拉刷新的效果。固定高度时,scrollTop可以从onScroll中获取`(e.detail.scrollTop)` ```tsx function PullRefreshList() { @@ -231,6 +231,7 @@ function PullRefreshList() { | ---------------------------------------------------------------------- | ---------------------------------- | -------- | | onLoad | 滚动条与底部距离小于 offset 时触发 | - | | ~~onLoading~~
`v0.1.1-alpha.2移除`
| 内部 loading 改变时触发 | - | +| onScroll | 滚动时触发 | e | ### 方法 diff --git a/packages/core/src/list/list.tsx b/packages/core/src/list/list.tsx index 6987616c4..c9fc9749a 100644 --- a/packages/core/src/list/list.tsx +++ b/packages/core/src/list/list.tsx @@ -1,5 +1,5 @@ import { useGetter, useToRef } from "@taroify/hooks" -import { View, ScrollView } from "@tarojs/components" +import { View, ScrollView, ScrollViewProps, BaseEventOrig } from "@tarojs/components" import { ViewProps } from "@tarojs/components/types/View" import classNames from "classnames" import * as React from "react" @@ -13,6 +13,7 @@ import { getScrollParent } from "../utils/dom/scroll" import { raf } from "../utils/raf" import { debounce } from "../utils/lodash-polyfill" import { ListDirection, ListInstance } from "./list.shared" +import PullRefreshContext from "../pull-refresh/pull-refresh.context" function useAssignLoading(state?: T | (() => T)) { const getState = useGetter(state) @@ -46,6 +47,7 @@ export interface ListProps extends ViewProps { fixedHeight?: boolean children?: ReactNode onLoad?(): void + onScroll?(e: BaseEventOrig): void } function List(props: ListProps, ref: ForwardedRef) { @@ -55,19 +57,25 @@ function List(props: ListProps, ref: ForwardedRef) { hasMore = true, direction = "down", offset = 100, - immediateCheck: _immediateCheck = true, + immediateCheck: immediateCheckProp = true, fixedHeight = false, disabled = false, children, onLoad, + onScroll: onScrollProp, ...restProps } = props const rootRef = useRef() const scrollRef = useRef() const edgeRef = useRef() const onLoadRef = useToRef(onLoad) - const immediateCheck = useToRef(_immediateCheck) + const immediateCheck = useToRef(immediateCheckProp) const { isLoading, setLoading } = useAssignLoading(loadingProp) + const { + onTouchStart: onPullRefreshTouchStart, + onTouchEnd: onPullRefreshTouchEnd, + onTouchMove: onPullRefreshTouchMove + } = React.useContext(PullRefreshContext) const check = useMemoizedFn(debounce(() => { raf(async () => { @@ -107,12 +115,31 @@ function List(props: ListProps, ref: ForwardedRef) { } }) - const onScroll = () => { + const onScroll = (e) => { + onScrollProp?.(e) if (fixedHeight) { check() } } + const onTouchStart = (e) => { + if (fixedHeight) { + onPullRefreshTouchStart?.(e) + } + } + + const onTouchMove = (e) => { + if (fixedHeight) { + onPullRefreshTouchMove?.(e) + } + } + + const onTouchEnd = (e) => { + if (fixedHeight) { + onPullRefreshTouchEnd?.(e) + } + } + useDidEffect(() => { check() }, [loadingProp, hasMore, check]) @@ -140,7 +167,16 @@ function List(props: ListProps, ref: ForwardedRef) { ) return ( - + {direction === "down" ? children : listEdge} {direction === "up" ? children : listEdge} diff --git a/packages/core/src/navbar/navbar.scss b/packages/core/src/navbar/navbar.scss index 9b72298ce..9f2db8e65 100644 --- a/packages/core/src/navbar/navbar.scss +++ b/packages/core/src/navbar/navbar.scss @@ -12,6 +12,10 @@ color: $navbar-icon-color; } + &__placeholder { + height: $navbar-height; + } + &__content { position: relative; display: flex; diff --git a/packages/core/src/placeholder/use-placeholder.tsx b/packages/core/src/placeholder/use-placeholder.tsx index e15d2275c..bdd240335 100644 --- a/packages/core/src/placeholder/use-placeholder.tsx +++ b/packages/core/src/placeholder/use-placeholder.tsx @@ -15,6 +15,7 @@ export interface PlaceholderProps extends PropsWithChildren { } export default function usePlaceholder(contentRef: any, { className }: UsePlaceholderOptions = {}) { + console.warn("[Taroify] usePlaceholder is deprecated, please don't use it.") return ({ className: classNameProp, style = {}, children, ...restProps }: PlaceholderProps) => { // eslint-disable-next-line react-hooks/rules-of-hooks const height = useHeight(contentRef, [children]) diff --git a/packages/core/src/pull-refresh/pull-refresh.context.ts b/packages/core/src/pull-refresh/pull-refresh.context.ts index b2a020f87..ef37a0a52 100644 --- a/packages/core/src/pull-refresh/pull-refresh.context.ts +++ b/packages/core/src/pull-refresh/pull-refresh.context.ts @@ -2,10 +2,16 @@ import { createContext } from "react" interface PullRefreshContextValue { distance: number + onTouchStart(event: any): void + onTouchMove(event: any): void + onTouchEnd(event: any): void } const PullRefreshContext = createContext({ distance: 0, + onTouchStart: () => {}, + onTouchMove: () => {}, + onTouchEnd: () => {}, }) export default PullRefreshContext diff --git a/packages/core/src/pull-refresh/pull-refresh.tsx b/packages/core/src/pull-refresh/pull-refresh.tsx index 44e30f026..98d942dc7 100644 --- a/packages/core/src/pull-refresh/pull-refresh.tsx +++ b/packages/core/src/pull-refresh/pull-refresh.tsx @@ -241,6 +241,8 @@ function PullRefresh(props: PullRefreshProps) { setTimeout(() => nextTick(() => updateStatus(0)), +completedDuration) }, [completedDuration, updateStatus]) + const contextValue = useMemo(() => ({ distance, onTouchStart, onTouchMove, onTouchEnd }), [distance, onTouchStart, onTouchMove, onTouchEnd]) + useEffect(() => { if (loading) { updateStatus(headHeight, true) @@ -319,9 +321,7 @@ function PullRefresh(props: PullRefreshProps) { return ( `v0.1.0-alpha.8` | 滚动阈值,标签数量超过阈值且总宽度超过标签栏宽度时开始横向滚动 | _number_ | `5` | | lazyRender | 是否延迟渲染未展示的选项卡 | _boolean_ | `false` | diff --git a/packages/core/src/tabs/tabs-header.scss b/packages/core/src/tabs/tabs-header.scss index 638d08f7c..01d35ce5a 100644 --- a/packages/core/src/tabs/tabs-header.scss +++ b/packages/core/src/tabs/tabs-header.scss @@ -40,6 +40,10 @@ border-radius: $tabs-card-border-radius; } + &--shrink { + width: auto; + } + &::-webkit-scrollbar { display: none; } @@ -49,6 +53,9 @@ .#{$component-prefix}tabs__tab { flex: 1 0 auto; padding: 0 var(--padding-sm, $padding-sm); + &--shrink { + flex: none; + } } } } @@ -77,6 +84,10 @@ border-right: 0 none; } + &--shrink { + flex: none; + } + &--active { color: var(--white, $white); background: $tabs-active-color; diff --git a/packages/core/src/tabs/tabs-header.tsx b/packages/core/src/tabs/tabs-header.tsx index 9cb4b4ca9..9aab48104 100644 --- a/packages/core/src/tabs/tabs-header.tsx +++ b/packages/core/src/tabs/tabs-header.tsx @@ -25,6 +25,7 @@ interface TabsHeaderProps { theme?: TabsTheme bordered?: boolean ellipsis?: boolean + shrink?: boolean tabObjects: TabObject[] swipeThreshold: number @@ -32,7 +33,7 @@ interface TabsHeaderProps { } export default function TabsHeader(props: TabsHeaderProps) { - const { value: activeValue, theme, ellipsis, bordered, tabObjects, swipeThreshold, onTabClick } = props + const { value: activeValue, theme, ellipsis, bordered, shrink, tabObjects, swipeThreshold, onTabClick } = props const themeLine = theme === "line" const themeCard = theme === "card" @@ -79,8 +80,9 @@ export default function TabsHeader(props: TabsHeaderProps) { }, []) const flexBasis = useMemo(() => { + if (shrink) return "" return ellipsis && themeLine ? `${88 / swipeThreshold}%` : "" - }, [ellipsis, themeLine, swipeThreshold]) + }, [ellipsis, themeLine, swipeThreshold, shrink]) useEffect(() => nextTick(resize), [resize, tabObjects]) @@ -109,6 +111,7 @@ export default function TabsHeader(props: TabsHeaderProps) { className={classNames(prefixClassname("tabs__wrap__scroll"), { [prefixClassname("tabs__wrap__scroll--line")]: themeLine, [prefixClassname("tabs__wrap__scroll--card")]: themeCard, + [prefixClassname("tabs__wrap__scroll--shrink")]: shrink && themeCard, })} > + + 内容 1 + 内容 2 + 内容 3 + 内容 4 + + + 内容 1 + 内容 2 + 内容 3 + 内容 4 + + + ) +} + function TabsWithCustomTitle() { return ( @@ -181,12 +200,16 @@ export default function TabsDemo() { + + + +