You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

u-navbar.vue 8.9 KiB

2 年之前
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311
  1. <template>
  2. <view class="">
  3. <view class="u-navbar" :style="[navbarStyle]" :class="{ 'u-navbar-fixed': isFixed, 'u-border-bottom': borderBottom }">
  4. <view class="u-status-bar" :style="{ height: statusBarHeight + 'px' }"></view>
  5. <view class="u-navbar-inner" :style="[navbarInnerStyle]">
  6. <view class="u-back-wrap" v-if="isBack" @tap="goBack">
  7. <view class="u-icon-wrap"><u-icon :name="backIconName" :color="backIconColor" :size="backIconSize"></u-icon></view>
  8. <view class="u-icon-wrap u-back-text u-line-1" v-if="backText" :style="[backTextStyle]">{{ backText }}</view>
  9. </view>
  10. <view class="u-navbar-content-title" v-if="title" :style="[titleStyle]">
  11. <view
  12. class="u-title u-line-1"
  13. :style="{
  14. color: titleColor,
  15. fontSize: titleSize + 'rpx'
  16. }"
  17. >
  18. {{ title }}
  19. </view>
  20. <view class="u-titles" v-if="titles != ''">
  21. {{ titles }}
  22. </view>
  23. </view>
  24. <view class="u-slot-content" :style="[titleStyle]"><slot></slot></view>
  25. <view class="u-slot-right"><slot name="right"></slot></view>
  26. </view>
  27. </view>
  28. <!-- 解决fixed定位后导航栏塌陷的问题 -->
  29. <view class="u-navbar-placeholder" v-if="isFixed" :style="{ width: '100%', height: Number(navbarHeight) + statusBarHeight + 'px' }"></view>
  30. </view>
  31. </template>
  32. <script>
  33. // 获取系统状态栏的高度
  34. let systemInfo = uni.getSystemInfoSync();
  35. let menuButtonInfo = {};
  36. // 如果是小程序,获取右上角胶囊的尺寸信息,避免导航栏右侧内容与胶囊重叠(支付宝小程序非本API,尚未兼容)
  37. // #ifdef MP-WEIXIN || MP-BAIDU || MP-TOUTIAO || MP-QQ
  38. menuButtonInfo = uni.getMenuButtonBoundingClientRect();
  39. // #endif
  40. /**
  41. * navbar 自定义导航栏
  42. * @description 此组件一般用于在特殊情况下,需要自定义导航栏的时候用到,一般建议使用uniapp自带的导航栏。
  43. * @tutorial https://www.uviewui.com/components/navbar.html
  44. * @property {String Number} height 导航栏高度(不包括状态栏高度在内,内部自动加上),注意这里的单位是px(默认44)
  45. * @property {String} back-icon-color 左边返回图标的颜色(默认#606266)
  46. * @property {String} back-icon-name 左边返回图标的名称,只能为uView自带的图标(默认arrow-left)
  47. * @property {String Number} back-icon-size 左边返回图标的大小,单位rpx(默认30)
  48. * @property {String} back-text 返回图标右边的辅助提示文字
  49. * @property {Object} back-text-style 返回图标右边的辅助提示文字的样式,对象形式(默认{ color: '#606266' })
  50. * @property {String} title 导航栏标题,如设置为空字符,将会隐藏标题占位区域
  51. * @property {String Number} title-width 导航栏标题的最大宽度,内容超出会以省略号隐藏,单位rpx(默认250)
  52. * @property {String} title-color 标题的颜色(默认#606266)
  53. * @property {String Number} title-size 导航栏标题字体大小,单位rpx(默认32)
  54. * @property {Function} custom-back 自定义返回逻辑方法
  55. * @property {String Number} z-index 固定在顶部时的z-index值(默认980)
  56. * @property {Boolean} is-back 是否显示导航栏左边返回图标和辅助文字(默认true)
  57. * @property {Object} background 导航栏背景设置,见官网说明(默认{ background: '#ffffff' })
  58. * @property {Boolean} is-fixed 导航栏是否固定在顶部(默认true)
  59. * @property {Boolean} border-bottom 导航栏底部是否显示下边框,如定义了较深的背景颜色,可取消此值(默认true)
  60. * @example <u-navbar back-text="返回" title="剑未配妥,出门已是江湖"></u-navbar>
  61. */
  62. export default {
  63. name: "u-navbar",
  64. props: {
  65. // 导航栏高度,单位px,非rpx
  66. height: {
  67. type: [String, Number],
  68. default: ''
  69. },
  70. // 返回箭头的颜色
  71. backIconColor: {
  72. type: String,
  73. default: '#606266'
  74. },
  75. // 左边返回的图标
  76. backIconName: {
  77. type: String,
  78. default: 'arrow-left'
  79. },
  80. // 左边返回图标的大小,rpx
  81. backIconSize: {
  82. type: [String, Number],
  83. default: '30'
  84. },
  85. // 返回的文字提示
  86. backText: {
  87. type: String,
  88. default: ''
  89. },
  90. // 返回的文字的 样式
  91. backTextStyle: {
  92. type: Object,
  93. default() {
  94. return {
  95. color: '#606266'
  96. }
  97. }
  98. },
  99. // 导航栏标题
  100. title: {
  101. type: String,
  102. default: ''
  103. },
  104. // 标题下面的副标题
  105. titles: {
  106. type: String,
  107. default: ''
  108. },
  109. // 标题的宽度,如果需要自定义右侧内容,且右侧内容很多时,可能需要减少这个宽度,单位rpx
  110. titleWidth: {
  111. type: [String, Number],
  112. default: '250'
  113. },
  114. // 标题的颜色
  115. titleColor: {
  116. type: String,
  117. default: '#606266'
  118. },
  119. // 标题的字体大小
  120. titleSize: {
  121. type: [String, Number],
  122. default: 32
  123. },
  124. isBack: {
  125. type: [Boolean, String],
  126. default: true
  127. },
  128. // 对象形式,因为用户可能定义一个纯色,或者线性渐变的颜色
  129. background: {
  130. type: Object,
  131. default() {
  132. return {
  133. background: '#ffffff'
  134. }
  135. }
  136. },
  137. // 导航栏是否固定在顶部
  138. isFixed: {
  139. type: Boolean,
  140. default: true
  141. },
  142. // 是否显示导航栏的下边框
  143. borderBottom: {
  144. type: Boolean,
  145. default: true
  146. },
  147. zIndex: {
  148. type: [String, Number],
  149. default: ''
  150. },
  151. // 自定义返回逻辑
  152. customBack: {
  153. type: Function,
  154. default: null
  155. }
  156. },
  157. data() {
  158. return {
  159. menuButtonInfo: menuButtonInfo,
  160. statusBarHeight: systemInfo.statusBarHeight
  161. };
  162. },
  163. computed: {
  164. // 导航栏内部盒子的样式
  165. navbarInnerStyle() {
  166. let style = {};
  167. // 导航栏宽度,如果在小程序下,导航栏宽度为胶囊的左边到屏幕左边的距离
  168. style.height = this.navbarHeight + 'px';
  169. // // 如果是各家小程序,导航栏内部的宽度需要减少右边胶囊的宽度
  170. // #ifdef MP
  171. let rightButtonWidth = systemInfo.windowWidth - menuButtonInfo.left;
  172. style.marginRight = rightButtonWidth + 'px';
  173. // #endif
  174. return style;
  175. },
  176. // 整个导航栏的样式
  177. navbarStyle() {
  178. let style = {};
  179. style.zIndex = this.zIndex ? this.zIndex : this.$u.zIndex.navbar;
  180. // 合并用户传递的背景色对象
  181. Object.assign(style, this.background);
  182. return style;
  183. },
  184. // 导航中间的标题的样式
  185. titleStyle() {
  186. let style = {};
  187. // #ifndef MP
  188. style.left = (systemInfo.windowWidth - uni.upx2px(this.titleWidth)) / 2 + 'px';
  189. style.right = (systemInfo.windowWidth - uni.upx2px(this.titleWidth)) / 2 + 'px';
  190. // #endif
  191. // #ifdef MP
  192. // 此处是为了让标题显示区域即使在小程序有右侧胶囊的情况下也能处于屏幕的中间,是通过绝对定位实现的
  193. let rightButtonWidth = systemInfo.windowWidth - menuButtonInfo.left;
  194. style.left = (systemInfo.windowWidth - uni.upx2px(this.titleWidth)) / 2 + 'px';
  195. style.right = rightButtonWidth - (systemInfo.windowWidth - uni.upx2px(this.titleWidth)) / 2 + rightButtonWidth + 'px';
  196. // #endif
  197. style.width = uni.upx2px(this.titleWidth) + 'px';
  198. return style;
  199. },
  200. // 转换字符数值为真正的数值
  201. navbarHeight() {
  202. // #ifdef APP-PLUS || H5
  203. return this.height ? this.height : 44;
  204. // #endif
  205. // #ifdef MP
  206. // 小程序特别处理,让导航栏高度 = 胶囊高度 + 两倍胶囊顶部与状态栏底部的距离之差(相当于同时获得了导航栏底部与胶囊底部的距离)
  207. // 此方法有缺陷,暂不用(会导致少了几个px),采用直接固定值的方式
  208. // return menuButtonInfo.height + (menuButtonInfo.top - this.statusBarHeight) * 2;//导航高度
  209. let height = systemInfo.platform == 'ios' ? 44 : 48;
  210. return this.height ? this.height : height;
  211. // #endif
  212. }
  213. },
  214. created() {},
  215. methods: {
  216. goBack() {
  217. // 如果自定义了点击返回按钮的函数,则执行,否则执行返回逻辑
  218. if(typeof this.customBack === 'function') {
  219. this.customBack();
  220. } else {
  221. uni.navigateBack();
  222. }
  223. }
  224. }
  225. };
  226. </script>
  227. <style scoped lang="scss">
  228. @import "../../libs/css/style.components.scss";
  229. .u-navbar {
  230. width: 100%;
  231. }
  232. .u-navbar-fixed {
  233. position: fixed;
  234. left: 0;
  235. right: 0;
  236. top: 0;
  237. z-index: 991;
  238. }
  239. .u-status-bar {
  240. width: 100%;
  241. }
  242. .u-navbar-inner {
  243. display: flex;
  244. justify-content: space-between;
  245. position: relative;
  246. align-items: center;
  247. }
  248. .u-back-wrap {
  249. display: flex;
  250. align-items: center;
  251. flex: 1;
  252. flex-grow: 0;
  253. padding: 14rpx 14rpx 14rpx 24rpx;
  254. }
  255. .u-back-text {
  256. padding-left: 4rpx;
  257. font-size: 30rpx;
  258. }
  259. .u-navbar-content-title {
  260. display: flex;
  261. flex-direction: column;
  262. align-items: center;
  263. justify-content: center;
  264. flex: 1;
  265. position: absolute;
  266. left: 0;
  267. right: 0;
  268. min-height: 60rpx;
  269. text-align: center;
  270. flex-shrink: 0;
  271. }
  272. .u-navbar-centent-slot {
  273. flex: 1;
  274. }
  275. .u-title {
  276. line-height: 60rpx;
  277. font-size: 32rpx;
  278. flex: 1;
  279. }
  280. .u-titles {
  281. margin-bottom: 15rpx;
  282. font-size: 24rpx;
  283. text-align: center;
  284. }
  285. .u-navbar-right {
  286. flex: 1;
  287. display: flex;
  288. align-items: center;
  289. justify-content: flex-end;
  290. }
  291. .u-slot-content {
  292. flex: 1;
  293. display: flex;
  294. align-items: center;
  295. }
  296. </style>