uni-nav-bar.vue 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424
  1. <template>
  2. <view
  3. class="uni-navbar"
  4. :class="{ 'uni-dark': dark, 'uni-nvue-fixed': fixed }"
  5. >
  6. <view
  7. class="uni-navbar__content"
  8. :class="{
  9. 'uni-navbar--fixed': fixed,
  10. 'uni-navbar--shadow': shadow,
  11. 'uni-navbar--border': border
  12. }"
  13. :style="{ 'background-color': themeBgColor }"
  14. >
  15. <status-bar v-if="statusBar" />
  16. <view
  17. :style="{
  18. color: themeColor,
  19. backgroundColor: themeBgColor,
  20. height: navbarHeight
  21. }"
  22. class="uni-navbar__header"
  23. >
  24. <view
  25. @tap="onClickLeft"
  26. class="uni-navbar__header-btns uni-navbar__header-btns-left"
  27. :style="{ width: leftIconWidth }"
  28. >
  29. <slot name="left">
  30. <view class="uni-navbar__content_view" v-if="leftIcon.length > 0">
  31. <uni-icons :color="themeColor" :type="leftIcon" size="20" />
  32. </view>
  33. <view
  34. :class="{ 'uni-navbar-btn-icon-left': !leftIcon.length > 0 }"
  35. class="uni-navbar-btn-text"
  36. v-if="leftText.length"
  37. >
  38. <text :style="{ color: themeColor, fontSize: '12px' }">{{
  39. leftText
  40. }}</text>
  41. </view>
  42. </slot>
  43. </view>
  44. <view class="uni-navbar__header-container" @tap="onClickTitle">
  45. <slot>
  46. <view
  47. class="uni-navbar__header-container-inner"
  48. v-if="title.length > 0"
  49. >
  50. <text
  51. class="uni-nav-bar-text uni-ellipsis-1"
  52. :style="{ color: themeColor }"
  53. >{{ title }}</text
  54. >
  55. </view>
  56. </slot>
  57. </view>
  58. <view
  59. @click="onClickRight"
  60. class="uni-navbar__header-btns uni-navbar__header-btns-right"
  61. :style="{ width: rightIconWidth }"
  62. >
  63. <slot name="right">
  64. <view v-if="rightIcon.length">
  65. <uni-icons :color="themeColor" :type="rightIcon" size="22" />
  66. </view>
  67. <view
  68. class="uni-navbar-btn-text"
  69. v-if="rightText.length && !rightIcon.length"
  70. >
  71. <text
  72. class="uni-nav-bar-right-text"
  73. :style="{ color: themeColor }"
  74. >
  75. {{ rightText }}
  76. <span
  77. class="uni-nav-bar-right-text-number"
  78. v-if="rightNum !== ''"
  79. >{{ rightNum }}</span
  80. >
  81. </text>
  82. <!-- <text class="uni-nav-bar-right-text" :style="{ color: themeColor}">{{ rightNum }}</text> -->
  83. </view>
  84. </slot>
  85. </view>
  86. </view>
  87. </view>
  88. <!-- #ifndef APP-NVUE -->
  89. <view class="uni-navbar__placeholder" v-if="fixed">
  90. <status-bar v-if="statusBar" />
  91. <view
  92. class="uni-navbar__placeholder-view"
  93. :style="{ height: navbarHeight }"
  94. />
  95. </view>
  96. <!-- #endif -->
  97. </view>
  98. </template>
  99. <script>
  100. import statusBar from './uni-status-bar.vue'
  101. const getVal = val => (typeof val === 'number' ? val + 'px' : val)
  102. /**
  103. *
  104. *
  105. * NavBar 自定义导航栏
  106. * @description 导航栏组件,主要用于头部导航
  107. * @tutorial https://ext.dcloud.net.cn/plugin?id=52
  108. * @property {Boolean} dark 开启黑暗模式
  109. * @property {String} title 标题文字
  110. * @property {String} leftText 左侧按钮文本
  111. * @property {String} rightText 右侧按钮文本
  112. * @property {String} leftIcon 左侧按钮图标(图标类型参考 [Icon 图标](http://ext.dcloud.net.cn/plugin?id=28) type 属性)
  113. * @property {String} rightIcon 右侧按钮图标(图标类型参考 [Icon 图标](http://ext.dcloud.net.cn/plugin?id=28) type 属性)
  114. * @property {String} color 图标和文字颜色
  115. * @property {String} backgroundColor 导航栏背景颜色
  116. * @property {Boolean} fixed = [true|false] 是否固定顶部
  117. * @property {Boolean} statusBar = [true|false] 是否包含状态栏
  118. * @property {Boolean} shadow = [true|false] 导航栏下是否有阴影
  119. * @property {Boolean} stat 是否开启统计标题上报
  120. * @event {Function} clickLeft 左侧按钮点击时触发
  121. * @event {Function} clickRight 右侧按钮点击时触发
  122. * @event {Function} clickTitle 中间标题点击时触发
  123. */
  124. export default {
  125. name: 'UniNavBar',
  126. components: {
  127. statusBar
  128. },
  129. emits: ['clickLeft', 'clickRight', 'clickTitle'],
  130. props: {
  131. dark: {
  132. type: Boolean,
  133. default: false
  134. },
  135. title: {
  136. type: String,
  137. default: ''
  138. },
  139. leftText: {
  140. type: String,
  141. default: ''
  142. },
  143. rightText: {
  144. type: String,
  145. default: ''
  146. },
  147. rightNum: {
  148. type: String,
  149. default: ''
  150. },
  151. leftIcon: {
  152. type: String,
  153. default: ''
  154. },
  155. rightIcon: {
  156. type: String,
  157. default: ''
  158. },
  159. fixed: {
  160. type: [Boolean, String],
  161. default: false
  162. },
  163. color: {
  164. type: String,
  165. default: ''
  166. },
  167. backgroundColor: {
  168. type: String,
  169. default: ''
  170. },
  171. statusBar: {
  172. type: [Boolean, String],
  173. default: false
  174. },
  175. shadow: {
  176. type: [Boolean, String],
  177. default: false
  178. },
  179. border: {
  180. type: [Boolean, String],
  181. default: true
  182. },
  183. height: {
  184. type: [Number, String],
  185. default: 44
  186. },
  187. leftWidth: {
  188. type: [Number, String],
  189. default: 60
  190. },
  191. rightWidth: {
  192. type: [Number, String],
  193. default: 60
  194. },
  195. stat: {
  196. type: [Boolean, String],
  197. default: ''
  198. }
  199. },
  200. computed: {
  201. themeBgColor () {
  202. if (this.dark) {
  203. // 默认值
  204. if (this.backgroundColor) {
  205. return this.backgroundColor
  206. } else {
  207. return this.dark ? '#333' : '#FFF'
  208. }
  209. }
  210. return this.backgroundColor || '#FFF'
  211. },
  212. themeColor () {
  213. if (this.dark) {
  214. // 默认值
  215. if (this.color) {
  216. return this.color
  217. } else {
  218. return this.dark ? '#fff' : '#333'
  219. }
  220. }
  221. return this.color || '#333'
  222. },
  223. navbarHeight () {
  224. return getVal(this.height)
  225. },
  226. leftIconWidth () {
  227. return getVal(this.leftWidth)
  228. },
  229. rightIconWidth () {
  230. return getVal(this.rightWidth)
  231. }
  232. },
  233. mounted () {
  234. if (uni.report && this.stat && this.title !== '') {
  235. uni.report('title', this.title)
  236. }
  237. },
  238. methods: {
  239. onClickLeft () {
  240. this.$emit('clickLeft')
  241. },
  242. onClickRight () {
  243. this.$emit('clickRight')
  244. },
  245. onClickTitle () {
  246. this.$emit('clickTitle')
  247. }
  248. }
  249. }
  250. </script>
  251. <style lang="scss" scoped>
  252. $nav-height: 88rpx;
  253. .uni-nvue-fixed {
  254. /* #ifdef APP-NVUE */
  255. position: sticky;
  256. /* #endif */
  257. }
  258. .uni-navbar {
  259. // box-sizing: border-box;
  260. }
  261. .uni-nav-bar-text {
  262. /* #ifdef APP-PLUS */
  263. font-size: 34rpx;
  264. /* #endif */
  265. /* #ifndef APP-PLUS */
  266. font-size: 32rpx;
  267. /* #endif */
  268. }
  269. .uni-nav-bar-right-text {
  270. font-size: 28rpx;
  271. position: relative;
  272. padding-right: 20rpx;
  273. .uni-nav-bar-right-text-number {
  274. padding: 4rpx 8rpx;
  275. background: red;
  276. border-radius: 50%;
  277. color: #fff;
  278. display: inline-block;
  279. font-size: 10rpx;
  280. position: absolute;
  281. right: 0;
  282. top: -20rpx;
  283. font-size: 28rpx;
  284. }
  285. }
  286. .uni-navbar__content {
  287. position: relative;
  288. // background-color: #fff;
  289. // box-sizing: border-box;
  290. background-color: transparent;
  291. }
  292. .uni-navbar__content_view {
  293. // box-sizing: border-box;
  294. }
  295. .uni-navbar-btn-text {
  296. /* #ifndef APP-NVUE */
  297. display: flex;
  298. /* #endif */
  299. flex-direction: column;
  300. justify-content: flex-start;
  301. align-items: center;
  302. line-height: 12px;
  303. }
  304. .uni-navbar__header {
  305. /* #ifndef APP-NVUE */
  306. display: flex;
  307. /* #endif */
  308. padding: 0 10px;
  309. flex-direction: row;
  310. height: $nav-height;
  311. font-size: 28rpx;
  312. }
  313. .uni-navbar__header-btns {
  314. /* #ifndef APP-NVUE */
  315. overflow: hidden;
  316. display: flex;
  317. /* #endif */
  318. flex-wrap: nowrap;
  319. flex-direction: row;
  320. width: 120rpx;
  321. // padding: 0 6px;
  322. justify-content: center;
  323. align-items: center;
  324. /* #ifdef H5 */
  325. cursor: pointer;
  326. /* #endif */
  327. }
  328. .uni-navbar__header-btns-left {
  329. /* #ifndef APP-NVUE */
  330. display: flex;
  331. /* #endif */
  332. width: 120rpx;
  333. justify-content: flex-start;
  334. align-items: center;
  335. }
  336. .uni-navbar__header-btns-right {
  337. /* #ifndef APP-NVUE */
  338. display: flex;
  339. /* #endif */
  340. flex-direction: row;
  341. // width: 150rpx;
  342. // padding-right: 30rpx;
  343. justify-content: flex-end;
  344. align-items: center;
  345. }
  346. .uni-navbar__header-container {
  347. /* #ifndef APP-NVUE */
  348. display: flex;
  349. /* #endif */
  350. flex: 1;
  351. padding: 0 10px;
  352. overflow: hidden;
  353. }
  354. .uni-navbar__header-container-inner {
  355. /* #ifndef APP-NVUE */
  356. display: flex;
  357. /* #endif */
  358. flex: 1;
  359. flex-direction: row;
  360. align-items: center;
  361. justify-content: center;
  362. font-size: 28rpx;
  363. overflow: hidden;
  364. // box-sizing: border-box;
  365. }
  366. .uni-navbar__placeholder-view {
  367. height: $nav-height;
  368. }
  369. .uni-navbar--fixed {
  370. position: fixed;
  371. z-index: 998;
  372. /* #ifdef H5 */
  373. left: var(--window-left);
  374. right: var(--window-right);
  375. /* #endif */
  376. /* #ifndef H5 */
  377. left: 0;
  378. right: 0;
  379. /* #endif */
  380. }
  381. .uni-navbar--shadow {
  382. box-shadow: 0 1px 6px #ccc;
  383. }
  384. .uni-navbar--border {
  385. border-bottom-width: 1rpx;
  386. border-bottom-style: solid;
  387. border-bottom-color: #eee;
  388. }
  389. .uni-ellipsis-1 {
  390. overflow: hidden;
  391. /* #ifndef APP-NVUE */
  392. white-space: nowrap;
  393. text-overflow: ellipsis;
  394. /* #endif */
  395. /* #ifdef APP-NVUE */
  396. lines: 1;
  397. text-overflow: ellipsis;
  398. /* #endif */
  399. }
  400. // 暗主题配置
  401. .uni-dark {
  402. }
  403. </style>