navbar.tsx 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. import React from 'react'
  2. import { View, Text } from '@tarojs/components'
  3. import { cn } from '@/utils/cn'
  4. import Taro from '@tarojs/taro'
  5. export interface NavbarProps {
  6. title?: string
  7. leftText?: string
  8. leftIcon?: string
  9. rightText?: string
  10. rightIcon?: string
  11. backgroundColor?: string
  12. textColor?: string
  13. border?: boolean
  14. fixed?: boolean
  15. placeholder?: boolean
  16. onClickLeft?: () => void
  17. onClickRight?: () => void
  18. children?: React.ReactNode
  19. className?: string
  20. }
  21. const systemInfo = Taro.getSystemInfoSync()
  22. const menuButtonInfo = Taro.getMenuButtonBoundingClientRect()
  23. // 计算导航栏高度
  24. const NAVBAR_HEIGHT = 44
  25. const STATUS_BAR_HEIGHT = systemInfo.statusBarHeight || 0
  26. const TOTAL_HEIGHT = STATUS_BAR_HEIGHT + NAVBAR_HEIGHT
  27. export const Navbar: React.FC<NavbarProps> = ({
  28. title,
  29. leftText,
  30. leftIcon = 'i-heroicons-chevron-left-20-solid',
  31. rightText,
  32. rightIcon,
  33. backgroundColor = 'bg-white',
  34. textColor = 'text-gray-900',
  35. border = true,
  36. fixed = true,
  37. placeholder = true,
  38. onClickLeft,
  39. onClickRight,
  40. children,
  41. className,
  42. }) => {
  43. // 处理左侧点击
  44. const handleLeftClick = () => {
  45. if (onClickLeft) {
  46. onClickLeft()
  47. } else {
  48. // 默认返回上一页
  49. Taro.navigateBack()
  50. }
  51. }
  52. // 渲染左侧内容
  53. const renderLeft = () => {
  54. if (children) return null
  55. return (
  56. <View
  57. className="absolute left-3 top-0 bottom-0 flex items-center z-10"
  58. style={{ height: NAVBAR_HEIGHT }}
  59. onClick={handleLeftClick}
  60. >
  61. <View className="flex items-center">
  62. {leftIcon && (
  63. <View className={cn(leftIcon, 'w-5 h-5', textColor)} />
  64. )}
  65. {leftText && (
  66. <Text className={cn('ml-1 text-sm', textColor)}>{leftText}</Text>
  67. )}
  68. </View>
  69. </View>
  70. )
  71. }
  72. // 渲染右侧内容
  73. const renderRight = () => {
  74. if (!rightText && !rightIcon) return null
  75. return (
  76. <View
  77. className="absolute right-3 top-0 bottom-0 flex items-center z-10"
  78. style={{ height: NAVBAR_HEIGHT }}
  79. onClick={onClickRight}
  80. >
  81. <View className="flex items-center">
  82. {rightText && (
  83. <Text className={cn('mr-1 text-sm', textColor)}>{rightText}</Text>
  84. )}
  85. {rightIcon && (
  86. <View className={cn(rightIcon, 'w-5 h-5', textColor)} />
  87. )}
  88. </View>
  89. </View>
  90. )
  91. }
  92. // 渲染标题
  93. const renderTitle = () => {
  94. if (children) return children
  95. return (
  96. <Text className={cn('text-base font-semibold', textColor)}>
  97. {title}
  98. </Text>
  99. )
  100. }
  101. // 导航栏样式
  102. const navbarStyle = {
  103. height: TOTAL_HEIGHT,
  104. paddingTop: STATUS_BAR_HEIGHT,
  105. }
  106. return (
  107. <>
  108. <View
  109. className={cn(
  110. 'relative w-full',
  111. backgroundColor,
  112. border && 'border-b border-gray-200',
  113. fixed && 'fixed top-0 left-0 right-0 z-50',
  114. className
  115. )}
  116. style={navbarStyle}
  117. >
  118. {/* 导航栏内容 */}
  119. <View
  120. className="relative flex items-center justify-center"
  121. style={{ height: NAVBAR_HEIGHT }}
  122. >
  123. {renderLeft()}
  124. {renderTitle()}
  125. {renderRight()}
  126. </View>
  127. </View>
  128. {/* 占位元素 */}
  129. {fixed && placeholder && (
  130. <View style={{ height: TOTAL_HEIGHT }} />
  131. )}
  132. </>
  133. )
  134. }
  135. // 预设样式
  136. export const NavbarPresets = {
  137. // 默认白色导航栏
  138. default: {
  139. backgroundColor: 'bg-white',
  140. textColor: 'text-gray-900',
  141. border: true,
  142. },
  143. // 深色导航栏
  144. dark: {
  145. backgroundColor: 'bg-gray-900',
  146. textColor: 'text-white',
  147. border: true,
  148. },
  149. // 透明导航栏
  150. transparent: {
  151. backgroundColor: 'bg-transparent',
  152. textColor: 'text-white',
  153. border: false,
  154. },
  155. // 主色调导航栏
  156. primary: {
  157. backgroundColor: 'bg-blue-500',
  158. textColor: 'text-white',
  159. border: false,
  160. },
  161. }
  162. // 快捷创建函数
  163. export const createNavbar = (preset: keyof typeof NavbarPresets) => {
  164. return NavbarPresets[preset]
  165. }
  166. export default Navbar