记一个复杂组件(Filter)的从设计到开发 (6)

Filter 的代码就是初始化、format、检查校验各种传参,以及 Panel 和 NavBar 通信中转 比如 format、比如 handleNavbarPress

NavBar 核心代码 NavBar 架构

记一个复杂组件(Filter)的从设计到开发

核心代码

从架构图中大概可以看出,NavBar 中通过不同的配置,展示不同的 NavBarItem 的类型,NavQuickSearch,NavRelatePanel

这里需要注意的是: NavBar 的数据是通过 Filter props 传入的,如果状态放到 Filter 也就是 NavBar 的父组件管理的话,会导致 Panel 组件不必要的渲染(虽然已经提供 Panel 层的 shouldComponentUpdate 的配置参数),同时也是为了组件设计的高内聚、低耦合,我们将传入的 props 封装到 NavBar 的 state 中,自己管理状态。

constructor(props) { super(props); const navConfig = formatNavConfig(props.navConfig); this.state = { navConfig, }; } // 这里我们提供内部的 formatNavConfig 方法,具体内容根据不同组件业务需求不同代码逻辑不同,这里就不展开说明了

NavBar 中还需要注意的就是被动更新:Panel 层点击后,NavBar 上文字的更新,因为这里我们利用父组件来进行 Panel 和 NavBar 的通信

//Filter.js 调用 NavBar 的方法 /** * 更新 Navbar 文案 */ handleNavTextChange = (index, navText, isChange = true) => { // Navbar 的 render 抽离到内部处理,可以减少一次 Filter.Panel 的额外 render this.asyncTask(() => { this.refNavbar.updateOptions(index, navText, isChange); }); }; //NavBar.js 提供给 Filter.js 调用的 updateOptions /** * 更新 navConfig,Filter 组件调用 * 异步 setState 规避 rax 框架 bug: 用户在 componentDidMount 函数中调用中 this.props.onChange 回调 * 重现Code:https://jsplayground.taobao.org/raxplayground/cefec50a-dfe5-4e77-a29a-af2bbfcfcda3 * @param index * @param text * @param isChange */ updateOptions = (index, text, isChange = true) => { setTimeout(() => { const { navConfig } = this.state; this.setState({ navConfig: navConfig.map((item, i) => { if (index === i) { return { ...item, text, isChange, }; } return item; }), }); }, 0); };

最后 NavBar 中的 item 分为 快速搜索和带有 panel 的 NavBarItem两种,但是对于其公共功能,比如渲染的 UI 逻辑等,这里我们采用的方法是抽离 NavBase 组件,供给 NavQuickSearch 和 NavRelatePanel 调用:

NavBase 部分代码

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} />), ]; };

NavRelatePanel.js

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>

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zzzzys.html