UNPKG

nuke-tabbar

Version:

带导航切换的tab组件

254 lines (239 loc) 8.23 kB
/** @jsx createElement */ import { createElement, cloneElement, isValidElement, Component } from 'rax'; import View from 'nuke-view'; import ScrollView from 'nuke-scroll-view'; import Dimensions from 'nuke-dimensions'; import { isWeb } from 'nuke-env'; import Item from './item'; import Content from './content'; import { connectStyle } from 'nuke-theme-provider'; import stylesProvider from '../styles'; // import wpo from './log/log.js'; const WIDTH = '750rem'; // 0 tabbar 完全渲染完毕 // 2/3 tabbar 切换tab渲染完毕(普通模式/embed模式) // const rec = t => Date.now() - t; class Tabbar extends Component { static Item = Item; constructor(props) { super(props); // wpo.setConfig({ // sample : 1, // spmId : 'nuke.perf', // request: stream.fetch // }); // this.t = Date.now(); // 兼容代码,旧api为activeKey为string,新api为obj this.keyObj = props.activeKey.key !== undefined; this.state = { selectedKey: this.getKey(props), }; this._control = { switch: true }; this.asFramework = props.asContainer === false || props.asFramework; } getKey(thisProps) { const props = thisProps || this.props; return this.keyObj ? props.activeKey.key : props.activeKey; } handleTouchTap = (tabKey, needChangeState = true) => { // this.t = Date.now() needChangeState && this.props.onChange && this.props.onChange({ prev: this.getKey(), next: tabKey }); needChangeState && this.setState({ selectedKey: tabKey }); this.keyObj ? (this.props.activeKey.key = tabKey) : (this.props.activeKey = tabKey); }; componentWillReceiveProps(nextProps) { // this.t = Date.now() // 屏蔽掉来自item press事件的state中activeKey的变更,render中将不处理,并且同步本地的activeKey值 if (!this._control.switch) { this.keyObj ? (nextProps.activeKey.key = this.props.activeKey.key) : (nextProps.activeKey = this.props.activeKey); } else { // 主动change state后不会产生onchange this.setState({ selectedKey: this.keyObj ? nextProps.activeKey.key : nextProps.activeKey, }); } } getTabs() { const tabs = []; if (this.props.children) { if (this.props.children.length) { this.props.children.map((tab) => { if (isValidElement(tab)) { tabs.push(tab); } }); return tabs; } tabs.push(this.props.children); } return tabs; } getStyles = () => { const { navTop = false, capsule = false, iconBar = false, themeStyle } = this.props; const { itemStyle = {} } = this.props; if (itemStyle.height) { itemStyle.height = parseInt(itemStyle.height, 10); } if (itemStyle.width) { itemStyle.width = parseInt(itemStyle.width, 10); } const barWrapperStyle = Object.assign( {}, { width: WIDTH, ...itemStyle, position: 'absolute' }, navTop || capsule ? { top: 0 } : { bottom: 0 } ); let barHeight = themeStyle.navBar.height; if (capsule) { barHeight = themeStyle.navCapsule.height; } if (iconBar) { barHeight = themeStyle['nav-item-has-icon'].height; } if (itemStyle.height) { barHeight = `${itemStyle.height}rem`; } const barStyle = Object.assign( {}, themeStyle.navBar, { backgroundColor: barWrapperStyle.backgroundColor || '#ffffff' }, iconBar ? themeStyle['nav-item-has-icon'] : {}, capsule ? themeStyle.navCapsule : { width: itemStyle.width || '750rem' }, { height: barHeight } // capsule ? { height: itemStyle.height || null } ); return { barWrapperStyle, barStyle, }; }; renderTabNav(tabs) { const { itemStyle = {}, navTop = false, capsule = false, iconBar = false } = this.props; /* * 修改导航条及content为绝对定位,以避免在embed模式下weex渲染遮挡问题。 */ const { barWrapperStyle, barStyle } = this.getStyles(); const tabDOM = tabs && tabs.length ? tabs : null; if (this.props.navScrollable) { return ( <View className="bar-wrapper" style={barWrapperStyle}> <ScrollView horizontal="true" showsHorizontalScrollIndicator={false} className="tab-nav" style={[ barStyle, isWeb ? { flexBasis: 'auto', } : {}, ]} contentContainerStyle={isWeb ? { flexBasis: 'auto' } : {}} > {tabDOM} </ScrollView> </View> ); } return ( <View className="bar-wrapper" style={barWrapperStyle}> <View className="tab-nav" style={barStyle}> {tabs} </View> </View> ); } render() { const tabContent = []; const { barStyle } = this.getStyles(); const themeStyle = this.props.themeStyle; const tabsList = this.getTabs(); let tabs = []; if (tabsList.length > 0) { tabs = tabsList.map((tab, index) => { if (tab.props.children || tab.props.src) { tabContent.push( createElement( Content, { src: tab.props.src || null, asFramework: this.asFramework, customMethod: { focus: this.props.customFocus, changeTo: this.props.customChange, }, key: index, webUrl: tab.props.webUrl || null, tabKey: tab.props.tabKey, selected: this.state.selectedKey === tab.props.tabKey, handleTouchTap: this.handleTouchTap, }, tab.props.children ) ); } return cloneElement(tab, { _control: this._control, asFramework: this.asFramework, navStyle: this.props.navStyle, index, style: Object.assign({}, tab.props.style, { height: barStyle.height }), tabKey: tab.props.tabKey, capsule: this.props.capsule, navTop: this.props.navTop, iconBar: this.props.iconBar, navScrollable: this.props.navScrollable, selected: this.state.selectedKey === tab.props.tabKey, selectedColor: this.props.selectedColor, selectedIcon: tab.props.selectedIcon, handleTouchTap: this.handleTouchTap, }); }); } const tabContainerStyle = Object.assign({}, themeStyle.tabContainer, this.props.style); // var barStyle = Object.assign({},styles.navBar,this.props.itemStyle); // if(this.props.iconBar){ // Object.assign(barStyle, styles['nav-item-has-icon']) // } const autoStyleHeight = Dimensions.get('window').height; const tabContentStyle = this.props.navTop || this.props.capsule ? Object.assign({}, themeStyle.tabContent, { marginTop: barStyle.height, }) : Object.assign({}, themeStyle.tabContent, { marginBottom: barStyle.height, }); // console.log('this.state.selectedKey', this.state.selectedKey); const index = Number(this.state.selectedKey) || 0; const contentStyle = this.props.contentStyle; if (this.props.navTop || this.props.capsule) { return ( <View className="tab-container" style={tabContainerStyle}> {tabsList.length > 0 ? this.renderTabNav(tabs) : null} {tabContent.length ? ( <View className="tab-content" style={[tabContentStyle, contentStyle]}> {tabContent} </View> ) : null} </View> ); } return ( <View className="tab-container" style={tabContainerStyle}> {tabContent.length ? ( <View className="tab-content" style={[tabContentStyle, contentStyle]}> {tabContent.length ? tabContent : null} </View> ) : null} {tabsList.length > 0 ? this.renderTabNav(tabs) : null} </View> ); } } Tabbar.defaultProps = { asFramework: true, themeStyle: {}, }; Tabbar.displayName = 'Tabbar'; export default connectStyle(stylesProvider)(Tabbar);