的 UI 逻辑等,这里我们采用的方法是抽离 NavBase
组件,供给 NavQuickSearch
和 NavRelatePanel
调用:
renderDefaultItem = ({ text, icons, active }) => {
const { formatText, hasSeperator, length, keepHighlight, isChange } = this.props;
const hasChange = keepHighlight && isChange;
const iconWidth = icons ? this.getStyle('navIcon').width || 18 : 0;
return [
<Text
numberOfLines={1}
style={[
this.getStyle('navText'),
ifElse(active || hasChange, this.getStyle('activeNavText')),
{ maxWidth: 750 / length - iconWidth },
]}>
{ifElse(is('Function')(formatText), formatText(text), text)}
</Text>,
ifElse(
icons,
<Image
ref={r => {
this.refImg = r;
}}
style={this.getStyle('navIcon')}
source={{
uri: ifElse(active || hasChange, icons && icons.active, icons && icons.normal),
}}
/>,
null,
),
ifElse(hasSeperator, <View style={this.navSeperatorStyle} />),
];
};
export default class NavRelatePanel extends NavBase {
static displayName = 'NavRelatePanel';
handleClick = () => {
const { disabled, onNavbarPress } = this.props;
if (disabled) return false;
onNavbarPress(NAV_TYPE.RelatePanel);
};
render() {
const { renderItem, active, text, icons } = this.props;
return (
<View
style={[this.getStyle('navItem'), ifElse(active, this.getStyle('activeNavItem'))]}
onClick={this.handleClick}>
{ifElse(
is('Function')(renderItem),
renderItem && renderItem({ active, instance: this }),
this.renderDefaultItem({ text, icons, active }),
)}
</View>
);
}
}
Panel 核心代码
Panel 的核心功能是对用户定义的 Panel.child 进行基本的功能添加,比如背景 mask 遮罩、动画时机的处理.
Panel 的使用:
<Panel
displayMode={'Fullscreen'} // 配置 Panel 全屏展示,默认为下拉展示
animation={{
// 动画配置
timingFunction: 'cubic-bezier(0.22, 0.61, 0.36, 1)',
duration: 200,
direction: 'left', // 动画方向:从右往左方向滑出
}}>
<MultiSelect {...this.state.data3} />
</Panel>
我们提供基础的动画配置,但是同时,也提供动画的 functionHook,这些都取决于动画的触发时机
get animationConfig() {
const { animation } = this.props;
if (!animation || !is('Object')(animation)) {
return PANEL_ANIMATION_CONFIG;
}
return Object.assign({}, PANEL_ANIMATION_CONFIG, animation);
}
// ...
/**
* 执行动画
* @param nextProps
*/
componentWillReceiveProps(nextProps) {
if (nextProps.visible !== this.props.visible) {
if (nextProps.visible) {
setNativeProps(findDOMNode(this.refPanelContainer), {
style: {
transform: `translateX(-${rem2px(750)})`,
},
});
this.props.disableNavbarClick(true);
this.enterAnimate(this.currentChildref, () => {
this.props.disableNavbarClick(false);
});
this.handleMaskAnimate(true);
} else {
this.handleMaskAnimate(false);
this.props.disableNavbarClick(true);
this.leaveAnimate(this.currentChildref, () => {
this.props.disableNavbarClick(false);
setNativeProps(findDOMNode(this.refPanelContainer), {
style: {
transform: 'translateX(0)',
},
});
});
}
}
}
由于动画的执行需要时间,所以这个时间段,我们应该给 Filter 中的 NavBar 加锁 ,锁的概念也同样提供给用户,毕竟业务逻辑我们是不会侵入的,在上一次的搜索没有结果返回时候,应该给 NavBar 加锁,禁止再次点击(虽然用户可以再 onchange 回调函数中处理,但是作为组件,同样应该考虑并且提供这个能力),同样对于动画也是如此,在该动画正在执行的时候,应该禁止 NavBar 的再次点击。上面的动画配置效果如下:
Panel 中还有核心的处理或许就是关于动画时机的处理。比如在触发动画前,我们需要设置动画初始状态,但是如若如下写法,会出现 Panel 闪动的现象,毕竟我们通过第二次的事件轮训回来才执行初始化,所以这里,如果用户配置启动动画,那么我们需要在 Panel 的最外层添加一个可见的 flag:默认进来 opacity
设置为 0,当动画初