Skip to content

Commit

Permalink
feat: ✨implement full function notice-bar
Browse files Browse the repository at this point in the history
  • Loading branch information
huang-xiao-jian committed Jun 29, 2020
1 parent 29d2f4e commit ff61ad0
Show file tree
Hide file tree
Showing 3 changed files with 318 additions and 104 deletions.
206 changes: 116 additions & 90 deletions packages/NoticeBar/NoticeBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,18 @@ import React, {
FunctionComponent,
CSSProperties,
ReactElement,
useMemo,
useState,
} from 'react';
import clsx from 'clsx';
import { usePageInstance, useNativeEffect } from 'remax';
import { useNativeEffect } from 'remax';
import { View, Navigator } from 'remax/wechat';
// internal
import Icon from '../Icon';
import { Switch, Case } from '../tools/Switch';
import pickStyle from '../tools/pick-style';
import { Switch, Case, Select } from '../tools/Switch';
import withDefaultProps from '../tools/with-default-props-advance';
import uuid from '../tools/uuid';
import { useTransition, NoticeBarActionTypes } from './use-transition';
import './NoticeBar.css';

// 默认值填充属性
Expand All @@ -35,10 +37,12 @@ interface NeutralNoticeBarProps {
}

interface ExogenousNoticeBarProps {
// 提示文字
text: string;
// left side icon
leftIcon?: string | ReactElement;
// right side
rightIcon?: ReactElement;
rightIcon?: string | ReactElement;
// navigator target
url?: string;
// 容器类名,用以覆盖内部
Expand All @@ -48,10 +52,15 @@ interface ExogenousNoticeBarProps {
}

type NoticeBarProps = NeutralNoticeBarProps & ExogenousNoticeBarProps;
type NoticeBarRects = [
WechatMiniprogram.BoundingClientRectCallbackResult,
WechatMiniprogram.BoundingClientRectCallbackResult
];

const DefaultNoticeBarProps: NeutralNoticeBarProps = {
mode: '',
delay: 1,
// 滚动效果延迟,单位 ms
delay: 100,
speed: 50,
scrollable: true,
color: '#ed6a0c',
Expand All @@ -60,8 +69,7 @@ const DefaultNoticeBarProps: NeutralNoticeBarProps = {
openType: 'navigate',
};

// TODO - find better way to support NoticeBar scroll animation
// TODO - resolve right icon drift from center
// TODO - 支持动态修改 speed
const NoticeBar: FunctionComponent<NoticeBarProps> = (props) => {
const {
className,
Expand All @@ -74,11 +82,22 @@ const NoticeBar: FunctionComponent<NoticeBarProps> = (props) => {
scrollable,
openType,
url,
children,
text,
speed,
delay,
onClick,
} = props;

// closable 信息栏
const [visible, setVisible] = useState(true);
// 限定查询范围
const [contentID, wrapID] = useMemo(() => [uuid(), uuid()], []);
const stylesheets: Record<string, CSSProperties> = {
container: {
color,
backgroundColor,
},
};
const classnames = {
container: clsx(className, 'van-notice-bar', {
'van-notice-bar--withicon': mode,
Expand All @@ -88,98 +107,105 @@ const NoticeBar: FunctionComponent<NoticeBarProps> = (props) => {
'van-ellipsis': !scrollable && !wrapable,
}),
};
const style: CSSProperties = {
color,
backgroundColor,

// 使用 CSS3 transition 处理动画,放弃微信动画 API
const [transitionStyle, dispatch] = useTransition();

const onClosableIcon = () => {
setVisible(false);
};

const page = usePageInstance();
const [animation] = useState<any>();
const onTransitionEnd = () => {
dispatch({
type: NoticeBarActionTypes.Iteration,
});
};

useNativeEffect(() => {
// setAnimation()
const query = page.createSelectorQuery();

query.select('.van-notice-bar__content').boundingClientRect();
query.select('.van-notice-bar__wrap').boundingClientRect();

query.exec(
(
rects: [
WechatMiniprogram.BoundingClientRectCallbackResult,
WechatMiniprogram.BoundingClientRectCallbackResult
]
) => {
const [contentRect, wrapRect] = rects;

if (contentRect && wrapRect && contentRect.width && wrapRect.width) {
if (scrollable && wrapRect.width < contentRect.width) {
// const duration = (contentRect.width / speed) * 1000;
// setAnimation(
// wx
// .createAnimation({
// duration: 0,
// timingFunction: 'linear',
// })
// .translateX(wrapRect.width)
// .step()
// .export()
// );
// wx.nextTick(() => {
// setAnimation(
// wx
// .createAnimation({
// duration,
// timingFunction: 'linear',
// delay,
// })
// .translateX(-contentRect.width)
// .step()
// .export()
// );
// });
}
// 恢复初始状态,静默 transition, transform 相关属性
dispatch({
type: NoticeBarActionTypes.Pristine,
});

// 微信 API 查询节点
const qs = wx.createSelectorQuery();

// 使用 ID 进行查询,支持多实例并存
qs.select(`#${contentID}`).boundingClientRect();
qs.select(`#${wrapID}`).boundingClientRect();
qs.exec((rects: NoticeBarRects) => {
const [contentRect, wrapRect] = rects;

if (contentRect && wrapRect && contentRect.width && wrapRect.width) {
if (scrollable && wrapRect.width < contentRect.width) {
// 参数设置
dispatch({
type: NoticeBarActionTypes.Preset,
payload: {
delay,
duration: (contentRect.width / speed) * 1000,
warpWidth: wrapRect.width,
contentWidth: contentRect.width,
},
});
// 滚动启动
dispatch({
type: NoticeBarActionTypes.Drift,
});
}
}
);
}, [page, scrollable, speed, delay]);
});
}, [scrollable, text]);

return (
<View
style={pickStyle(style)}
className={classnames.container}
onClick={onClick}
>
{/* left icon */}
<Switch>
<Case in={typeof leftIcon === 'string'}>
<Icon
name={leftIcon as string}
size="16px"
className="van-notice-bar__left-icon"
/>
</Case>
<Case default>{leftIcon}</Case>
</Switch>
{/* center content */}
<View className="van-notice-bar__wrap">
<View className="van-notice-bar__content" animation={animation}>
{children}
<Select in={visible}>
<View
style={stylesheets.container}
className={classnames.container}
onClick={onClick}
>
{/* left icon */}
<Switch>
<Case in={typeof leftIcon === 'string'}>
<Icon
name={leftIcon as string}
size="16px"
className="van-notice-bar__left-icon"
/>
</Case>
<Case default>{leftIcon}</Case>
</Switch>

{/* center content */}
<View className="van-notice-bar__wrap" id={wrapID}>
<View
className={classnames.content}
id={contentID}
style={transitionStyle}
onTransitionEnd={onTransitionEnd}
>
{text}
</View>
</View>

{/* right icon */}
<Switch>
<Case in={mode === 'closeable'}>
<View className="van-notice-bar__right-icon">
<Icon name="cross" onClick={onClosableIcon} />
</View>
</Case>
<Case in={mode === 'link'}>
<Navigator url={url} openType={openType}>
<View className="van-notice-bar__right-icon">
<Icon name="arrow" />
</View>
</Navigator>
</Case>
<Case default>{rightIcon}</Case>
</Switch>
</View>
{/* right icon */}
<Switch>
<Case in={mode === 'closeable'}>
<Icon name="cross" className="van-notice-bar__right-icon" />
</Case>
<Case in={mode === 'link'}>
<Navigator url={url} openType={openType}>
<Icon className="van-notice-bar__right-icon" name="arrow" />
</Navigator>
</Case>
<Case default>{rightIcon}</Case>
</Switch>
</View>
</Select>
);
};

Expand Down
Loading

0 comments on commit ff61ad0

Please sign in to comment.