diff --git a/src/app.tsx b/src/app.tsx index be24a70..22fde88 100644 --- a/src/app.tsx +++ b/src/app.tsx @@ -20,9 +20,9 @@ class App extends Taro.Component { ], window: { navigationBarTitleText: 'Mounted', - navigationBarBackgroundColor: '#1AAD19', navigationBarTextStyle: 'white', backgroundColor: '#E8E8E8', + navigationStyle: 'custom', }, } diff --git a/src/components/NavigationBar/index.scss b/src/components/NavigationBar/index.scss new file mode 100644 index 0000000..6f3b5f3 --- /dev/null +++ b/src/components/NavigationBar/index.scss @@ -0,0 +1,84 @@ +@import '../../styles/settings.scss'; + +.m-navigation-bar { + &__container { + position: fixed; + top: 0; + left: 0; + right: 0; + box-sizing: border-box; + display: flex; + align-items: center; + justify-content: center; + z-index: 8000; + } + + &__left { + position: absolute; + left: 0; + } + + &__menu { + display: flex; + align-items: center; + justify-content: space-around; + font-weight: bold; + font-size: 18px; + border: 1px solid; + + &-left, &-right { + flex-grow: 1; + text-align: center; + } + + &-divider { + flex-shrink: 0; + width: 1px; + height: 1em; + } + } + + &__title { + font-weight: bold; + font-size: 18px; + } + + &_white &__menu { + background: rgba(black, 0.15); + border-color: rgba(white, 0.25); + } + + &_white &__menu-divider { + background: rgba(white, 0.25); + } + + &_black &__menu { + background: rgba(white, 0.55); + border-color: rgba(black, 0.25); + } + + &_black &__menu-divider { + background: rgba(black, 0.15); + } +} + +@font-face { + font-family: "m-navigation-bar-iconfont"; + src: url("data:font/woff;charset=utf-8;base64,d09GRgABAAAAAAUQAAsAAAAACCAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAABHU1VCAAABCAAAADMAAABCsP6z7U9TLzIAAAE8AAAARAAAAFY8d0gqY21hcAAAAYAAAABVAAABhmUs0M9nbHlmAAAB2AAAAR8AAAE8ILsQx2hlYWQAAAL4AAAAMQAAADYWIqFMaGhlYQAAAywAAAAgAAAAJAfbA4RobXR4AAADTAAAAAwAAAAMDAD//WxvY2EAAANYAAAACAAAAAgAJACebWF4cAAAA2AAAAAeAAAAIAEPAFpuYW1lAAADgAAAAWsAAAM5gIrW4nBvc3QAAATsAAAAJAAAADXT7s3PeJxjYGRgYOBikGPQYWB0cfMJYeBgYGGAAJAMY05meiJQDMoDyrGAaQ4gZoOIAgCKIwNPAHicY2BkYWCcwMDKwMHUyXSGgYGhH0IzvmYwYuRgYGBiYGVmwAoC0lxTGByeMT6zYG7438AQw9zA0AAUZgTJAQDhYgwceJztkMERgCAMBPdAeTgW4sMCKMWX5dMGHkG78GY2l1zgE2AFsjnNAroRQ5dTRZ7ZIl/iTbGL1NRq7/C5Je+KPY1/Kvzaox7vlMa1JtHXCXoADR8OKgAAAHicHY6/SsNAAMbvyyV3pAXhriGxpLGSkwRKifTfhSJI6eIkdPAV6ugoOhgh3RwdnbvVF/ABXARfwDdx6MWzyw8++H4fHwEhzRvl9JYIQrw0RzYtocdhwH2EAXO+j4W5EQLv4lwJU6EWai2wk4XETqhCmspUslDEafZNTff0meTkmhAfBVLGcYToBNFEHJDpC4xDLiaXKA/QGVciYBY6y5Xt2kXkQqWZKvX/jQhh3+7QH/Mki2nRMVXiMZqkcyzLLXi37nJsyyXmaUIZWz724zUGs3o2wDru4wGAR11s5Fhi41LP5k+8doKgY+5OR+1WAvOlVw6u4l4vNh/OSkMjabVHZ+YlHgJcL4CFNr8Yxrh3feZZ27oe811C/gAnVjyHAHicY2BkYGAA4grD63vj+W2+MnCzMIDAzWa95TD6/9//TSwMzPVALgcDE0gUAFMKDF0AAAB4nGNgZGBgbvjfwBDDwvD/LwMDCwMDUAQFMAMAdawEaAQAAAAEAAAABAD//QAAAAAAJACeeJxjYGRgYGBm8GNgYgABEMkFhAwM/8F8BgAQZwFqAAB4nJ2SPU7DQBCFn/OHSCQKEEh020ABsvOD0qSNlHQUKdI7ztpxZHujzSZSzsABOAUtd+AScAguwJMzaUApglceffvezOyPFsAlPuFh/13z37OHW872XMEZAuEq9b5wjfwsXEcLiXCDuhVu4hEvwi1c4Z0dvNo5Zw/4EPbQw7dwBRfenXAVPe9JuEbWwnXceK/CDepvwk1MvS/hFu4r/ebQ6tDpuZrtVBqZIjaFa+Z+EW7TJHSpKfxZaP2DM9HJJgvtUf+oMdV2TU11g87RnLEutD3sZb1Nes7FKrYmVyO6OsuMWlmz1JELFs6tBu12LHoQmZxHG/JKNUI4xjkUZtgxpohgUCAuo2NeDp8UYksvKfPT0vNZEbKH/6dmwo4JNshK//T60yumXNFiLXkKXT6vzj/6jNmnKHv9vpc1uyR8Vo4j5jxmjuEKCiOp1TxvRlZYld6SSkQ9wKKsWmGANkf8Kz8o95D/AJjlo1sAeJxjYGKAAC4G7ICZkYmRmZGFgSUpMTmbJSM/N5WBAQAZ7QNe") format("woff"); +} + +.m-navigation-bar-iconfont { + font-family: "m-navigation-bar-iconfont" !important; + font-size: 1em; + font-style: normal; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +.m-navigation-bar-icon-home:before { + content: "\e601"; +} + +.m-navigation-bar-icon-back:before { + content: "\e638"; +} diff --git a/src/components/NavigationBar/index.tsx b/src/components/NavigationBar/index.tsx new file mode 100644 index 0000000..3ba8e7c --- /dev/null +++ b/src/components/NavigationBar/index.tsx @@ -0,0 +1,128 @@ +import './index.scss' +import Taro from '@tarojs/taro' +import { component } from '../component' +import { internalStore } from '../internal' +import { last } from 'vtils' +import { NavigationBarProps } from './props' +import { View } from '@tarojs/components' + +function onlyPath(url: string) { + return url ? url.split('?')[0].replace(/^\/+/, '') : '' +} + +export default class NavigationBar extends component({ + props: NavigationBarProps, + state: { + verticalPadding: 0 as number, + horizontalPadding: 0 as number, + navigationBarHeight: 0 as number, + navigationBarFullHeight: 0 as number, + menuButtonHeight: 0 as number, + menuButtonWidth: 0 as number, + backButtonVisible: false as boolean, + homeButtonVisible: false as boolean, + }, +}) { + componentDidShow() { + const menuRect = Taro.getMenuButtonBoundingClientRect() + const sysInfo = Taro.getSystemInfoSync() + const verticalPadding = menuRect.top - sysInfo.statusBarHeight + const horizontalPadding = sysInfo.windowWidth - menuRect.right + const height = menuRect.height + verticalPadding * 2 + const fullHeight = sysInfo.statusBarHeight + height + + const pages = Taro.getCurrentPages() + const backButtonVisible = pages.length > 1 + const homeButtonVisible = onlyPath(last(pages).route) !== onlyPath(this.props.homePath) + + internalStore.customNavigationBarFullHeight = fullHeight + + this.setState({ + verticalPadding: verticalPadding, + horizontalPadding: horizontalPadding, + navigationBarHeight: height, + navigationBarFullHeight: fullHeight, + menuButtonHeight: menuRect.height, + menuButtonWidth: menuRect.width, + backButtonVisible: backButtonVisible, + homeButtonVisible: homeButtonVisible, + }) + } + + componentDidHide() { + internalStore.customNavigationBarFullHeight = 0 + } + + componentWillUnmount() { + internalStore.customNavigationBarFullHeight = 0 + } + + handleBackClick = () => { + Taro.navigateBack() + } + + handleHomeClick = () => { + Taro.navigateTo({ + url: this.props.homePath, + }) + } + + render() { + const { backgroundColor, textStyle, className } = this.props + const { verticalPadding, horizontalPadding, navigationBarHeight, navigationBarFullHeight, menuButtonHeight, menuButtonWidth, backButtonVisible, homeButtonVisible } = this.state + + const actualBackgroundColor = backgroundColor !== 'auto' + ? backgroundColor + : textStyle === 'white' + ? '#000000' + : '#FFFFFF' + + return ( + + + + {!backButtonVisible && !homeButtonVisible ? null : ( + + + {!backButtonVisible ? null : ( + + )} + {!(backButtonVisible && homeButtonVisible) ? null : ( + + )} + {!homeButtonVisible ? null : ( + + )} + + + )} + + {this.props.children} + + + + ) + } +} diff --git a/src/components/NavigationBar/props.ts b/src/components/NavigationBar/props.ts new file mode 100644 index 0000000..2d8c874 --- /dev/null +++ b/src/components/NavigationBar/props.ts @@ -0,0 +1,26 @@ +import { RequiredProp } from '../component' + +export const NavigationBarProps = { + /** + * 小程序主页的绝对路径,可带参数。 + * + * @example '/pages/index/index?id=40' + */ + homePath: '' as any as RequiredProp, + + /** + * 导航栏字体颜色,务必同时设置 `app.json` 中的 `window.navigationBarTextStyle` 且保持二者一致。 + * + * @default 'white' + */ + textStyle: 'white' as 'white' | 'black', + + /** + * 导航栏背景颜色。默认值是 `auto`,表示: + * - 若 `textStyle='white'`,则 `backgroundColor='#000000'`; + * - 若 `textStyle='black'`,则 `backgroundColor='#FFFFFF'`。 + * + * @default 'auto' + */ + backgroundColor: 'auto' as string, +} diff --git a/src/components/Popup/index.tsx b/src/components/Popup/index.tsx index 92ebe74..1131fd7 100644 --- a/src/components/Popup/index.tsx +++ b/src/components/Popup/index.tsx @@ -1,8 +1,8 @@ import MTransition from '../Transition' -import store from '../store' import Taro from '@tarojs/taro' import { CommonEventFunction } from '@tarojs/components/types/common' import { component } from '../component' +import { internalStore } from '../internal' import { MPopupProps, Position, TransitionName } from './props' import { View } from '@tarojs/components' @@ -31,7 +31,7 @@ export default class MPopup extends component({ componentWillMount() { this.setState({ - zIndex: store.zIndex++, + zIndex: internalStore.zIndex++, display: this.props.visible, }) } @@ -90,7 +90,8 @@ export default class MPopup extends component({ diff --git a/src/components/Sticky/index.tsx b/src/components/Sticky/index.tsx index 69d1625..1e52f38 100644 --- a/src/components/Sticky/index.tsx +++ b/src/components/Sticky/index.tsx @@ -1,6 +1,7 @@ import Taro from '@tarojs/taro' import { component } from '../component' import { Disposer, wait } from 'vtils' +import { internalStore } from '../internal' import { MStickyProps } from './props' import { View } from '@tarojs/components' @@ -57,7 +58,7 @@ export default class MSticky extends component({ }) // 监听吸顶内容的位置 - const top = -(this.index === 0 ? 0 : height) + const top = -(this.index === 0 ? internalStore.customNavigationBarFullHeight : height) const intersectionObserver = wx.createIntersectionObserver(this.$scope) const relativeToViewport = intersectionObserver.relativeToViewport({ top }) as any relativeToViewport.observe( @@ -100,7 +101,9 @@ export default class MSticky extends component({ - + {this.props.children} diff --git a/src/components/index.ts b/src/components/index.ts index c245b79..1964430 100644 --- a/src/components/index.ts +++ b/src/components/index.ts @@ -1,6 +1,7 @@ // @index('./[A-Z]*', (pp, cc) => `export { default as M${pp.name} } from '${pp.path}'`) export { default as MDatePicker } from './DatePicker' export { default as MECharts } from './ECharts' +export { default as MNavigationBar } from './NavigationBar' export { default as MPicker } from './Picker' export { default as MPickerView } from './PickerView' export { default as MPopup } from './Popup' @@ -14,6 +15,7 @@ export type ComponentName = ( // @index('./[A-Z]*', (pp, cc, { last }) => `'${pp.name}'${last ? '' : ' |'}`) 'DatePicker' | 'ECharts' | + 'NavigationBar' | 'Picker' | 'PickerView' | 'Popup' | diff --git a/src/components/internal.ts b/src/components/internal.ts new file mode 100644 index 0000000..e324e4b --- /dev/null +++ b/src/components/internal.ts @@ -0,0 +1,4 @@ +export const internalStore = { + zIndex: 5000, + customNavigationBarFullHeight: 0, +} diff --git a/src/components/store.ts b/src/components/store.ts deleted file mode 100644 index 1589023..0000000 --- a/src/components/store.ts +++ /dev/null @@ -1,5 +0,0 @@ -const store = { - zIndex: 5000, -} - -export default store diff --git a/src/pages/DatePicker.tsx b/src/pages/DatePicker.tsx index 68cdb99..cd175c6 100644 --- a/src/pages/DatePicker.tsx +++ b/src/pages/DatePicker.tsx @@ -1,9 +1,9 @@ -import Taro, { Config, ShareAppMessageReturn } from '@tarojs/taro' +import Taro, { ShareAppMessageReturn } from '@tarojs/taro' import { component } from '../components/component' import { Image, View } from '@tarojs/components' import { MDatePicker } from '../components' import { pageUrls } from '.' -import { XBackHome, XItem, XList, XTitle } from './components' +import { XBackHome, XItem, XList, XNavigationBar, XTitle } from './components' const codeImg = 'https://ae01.alicdn.com/kf/Ua09c76aa494640e89c84432e7ad02a381.png' @@ -12,10 +12,6 @@ export default class DatePicker extends component({ selectedDate: [2013, 5, 20], }, }) { - config: Config = { - navigationBarTitleText: 'DatePicker', - } - onShareAppMessage(): ShareAppMessageReturn { return { title: 'DatePicker', @@ -27,6 +23,7 @@ export default class DatePicker extends component({ const { selectedDate } = this.state return ( + DatePicker 日期选择 require('echarts/dist/echarts.min.js') @@ -14,10 +14,6 @@ export default class ECharts extends component({ selectedCountryIndex: 0, }, }) { - config: Config = { - navigationBarTitleText: 'ECharts', - } - onShareAppMessage(): ShareAppMessageReturn { return { title: 'ECharts', @@ -28,6 +24,7 @@ export default class ECharts extends component({ render() { return ( + ECharts 雷达图 diff --git a/src/pages/Home.tsx b/src/pages/Home.tsx index 8dbe017..47ab078 100644 --- a/src/pages/Home.tsx +++ b/src/pages/Home.tsx @@ -5,7 +5,7 @@ import { ComponentName } from '../components' import { Image, Text, View } from '@tarojs/components' import { imgLogo } from './assets' import { pageUrls } from '.' -import { XItem, XList } from './components' +import { XItem, XList, XNavigationBar } from './components' interface ComponentInfo { name: ComponentName, @@ -80,6 +80,8 @@ export default class Home extends component({ render() { return ( + Mounted + {/* Logo */} + Picker 普通选择 + PickerView 普通选择 + Popup {positionList.map(pos => ( + SinglePicker 单项选择 + Sticky {heroTypeList.map(heroType => ( diff --git a/src/pages/TimePicker.tsx b/src/pages/TimePicker.tsx index 91c019d..cbcac02 100644 --- a/src/pages/TimePicker.tsx +++ b/src/pages/TimePicker.tsx @@ -1,9 +1,9 @@ -import Taro, { Config, ShareAppMessageReturn } from '@tarojs/taro' +import Taro, { ShareAppMessageReturn } from '@tarojs/taro' import { component } from '../components/component' import { Image, View } from '@tarojs/components' import { MTimePicker } from '../components' import { pageUrls } from '.' -import { XBackHome, XItem, XList, XTitle } from './components' +import { XBackHome, XItem, XList, XNavigationBar, XTitle } from './components' const codeImg = 'https://ae01.alicdn.com/kf/U53b3c5ab845b44dcaaa730be547043a8Z.png' @@ -12,10 +12,6 @@ export default class TimePicker extends component({ selectedTime: [5, 20], }, }) { - config: Config = { - navigationBarTitleText: 'TimePicker', - } - onShareAppMessage(): ShareAppMessageReturn { return { title: 'TimePicker', @@ -27,6 +23,7 @@ export default class TimePicker extends component({ const { selectedTime } = this.state return ( + TimePicker 时间选择 - + Transition{internalStore.customNavigationBarFullHeight} + {transitionNameList.map(name => ( + {this.props.children} + + ) + } +} diff --git a/src/pages/components/index.ts b/src/pages/components/index.ts index 7aee0c7..834880d 100644 --- a/src/pages/components/index.ts +++ b/src/pages/components/index.ts @@ -3,4 +3,5 @@ export { default as XBackHome } from './BackHome' export { default as XIcon } from './Icon' export { default as XItem } from './Item' export { default as XList } from './List' +export { default as XNavigationBar } from './NavigationBar' export { default as XTitle } from './Title'