hx-navbar.vue 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635
  1. <template>
  2. <view class="hx-navbar" >
  3. <view
  4. :class="{'hx-navbar--fixed': fixed,'hx-navbar--shadow':shadow,'hx-navbar--border':border}"
  5. :style="{'background': backgroundColorRgba}"
  6. class="hx-navbar__content">
  7. <block v-if="backgroundImg">
  8. <image class="navbgimg" :src="backgroundImg" mode=""></image>
  9. </block>
  10. <view :style="{ height: statusBarHeight ,'background': statusBarBackground}" class="hx-status-bar" v-if="statusBar" ></view>
  11. <view :style="{color:colorInfo,height: height,'line-height':height}" class="hd hx-navbar__header hx-navbar__content_view">
  12. <view class="hx-navbar__header-btns hx-navbar__content_view" @tap="onClickLeft" v-if="leftSlot" :style="{'color': colorInfo}">
  13. <block v-if="leftText.length || leftIcon.length || back">
  14. <view
  15. v-if="leftIcon.length || back"
  16. :class="back ? 'left_back' : ''"
  17. class="hx-navbar__content_view" >
  18. <uni-icons :type="back ? 'arrowleft' : leftIcon" :color="colorInfo" size="28"/>
  19. </view>
  20. <view
  21. v-if="leftText.length"
  22. :class="{'hx-navbar-btn-icon-left':!leftIcon.length}"
  23. class="hx-navbar-btn-text hx-navbar__content_view">{{ leftText }}</view>
  24. </block>
  25. <block v-else>
  26. <slot name="leftAfter" v-if="leftSlidiSwitch && slotSlidiSwitch == 1" />
  27. <slot name="left" v-else/>
  28. </block>
  29. </view>
  30. <view class="hx-navbar__header-container hx-navbar__content_view">
  31. <view
  32. v-if="title.length"
  33. class="hx-navbar__header-container-inner hx-navbar__content_view">{{ title }}</view>
  34. <!-- 标题插槽 -->
  35. <block v-else>
  36. <slot name="centerAfter" v-if="centerSlidiSwitch && slotSlidiSwitch == 1"/>
  37. <slot v-else/>
  38. </block>
  39. </view>
  40. <view :class="title.length?'hx-navbar__header-btns-right':''"
  41. class="hx-navbar__header-btns hx-navbar__content_view"
  42. @tap="onClickRight"
  43. v-if="rightSlot">
  44. <!-- 优先显示图标 -->
  45. <block v-if="rightIcon.length || rightText.length">
  46. <view class="hx-navbar__content_view" v-if="rightIcon.length">
  47. <uni-icons :type="rightIcon" :color="colorInfo" size="28"/>
  48. </view>
  49. <view v-if="rightText.length" class="hx-navbar-btn-text hx-navbar__content_view">{{ rightText }}</view>
  50. </block>
  51. <block v-else>
  52. <slot name="rightAfter" v-if="rightSlidiSwitch && slotSlidiSwitch == 1"/>
  53. <slot name="right" v-else/>
  54. </block>
  55. </view>
  56. </view>
  57. </view>
  58. <view
  59. v-if="placeholder"
  60. class="hx-navbar__placeholder">
  61. <view :style="{ height: statusBarHeight}" class="hx-status-bar" v-if="statusBar" ></view>
  62. <view :style="{ height: height}" />
  63. </view>
  64. </view>
  65. </template>
  66. <script>
  67. import uniIcons from '../uni-icons/uni-icons.vue'
  68. //获取系统状态栏高度
  69. var statusBarHeight = uni.getSystemInfoSync().statusBarHeight + 'px';
  70. export default {
  71. name: "hx-navbar",
  72. components: {
  73. uniIcons
  74. },
  75. data() {
  76. return {
  77. statusBarHeight: statusBarHeight,
  78. transparentValue: 0,
  79. navTransparentFixedFontColor: '#fff',
  80. statusBarFontColorInfo: [],
  81. backgroundColorRgba: 'rgba(255,255,255,1)',
  82. backgroundColorRgb: 'rgb(222,222,222)',
  83. colorInfo: '#000000',
  84. placeholder: false,
  85. colorContainer: null,
  86. slotSlidiSwitch: 0
  87. };
  88. },
  89. props:{
  90. height:{
  91. type: String,
  92. default: "44px"
  93. },
  94. //导航栏占位符 显示(show),隐藏(hidden),自动(auto:如果头部为固定fiexd ,则显示占位符)
  95. barPlaceholder:{
  96. type: String,
  97. default: "auto"
  98. },
  99. //返回上一页
  100. back:{
  101. type: [Boolean, String],
  102. default: true
  103. },
  104. //标题
  105. title: {
  106. type: String,
  107. default: ''
  108. },
  109. //是否开启左插槽
  110. leftSlot:{
  111. type: [Boolean, String],
  112. default: true
  113. },
  114. //是否开启右插槽
  115. rightSlot:{
  116. type: [Boolean, String],
  117. default: true
  118. },
  119. //左边文字
  120. leftText: {
  121. type: String,
  122. default: ''
  123. },
  124. //右插槽文字
  125. rightText: {
  126. type: String,
  127. default: ''
  128. },
  129. //左插槽图标
  130. leftIcon: {
  131. type: String,
  132. default: ''
  133. },
  134. //右插槽图标
  135. rightIcon: {
  136. type: String,
  137. default: ''
  138. },
  139. //是否固定头
  140. fixed: {
  141. type: [Boolean, String],
  142. default: false
  143. },
  144. //文字颜色
  145. color: {
  146. type: [Array,String],
  147. default: "#000000"
  148. },
  149. //导航栏背景颜色
  150. backgroundColor: {
  151. type: Array,
  152. default: function(){
  153. return new Array([255,255,255],[255,255,255]);
  154. }
  155. },
  156. //线性渐变角度
  157. backgroundColorLinearDeg: {
  158. type: String,
  159. default: '45'
  160. },
  161. //背景图片
  162. backgroundImg: {
  163. type: String,
  164. default: ''
  165. },
  166. //背景透明(show,hidden,auto)
  167. transparent: {
  168. type: String,
  169. default: 'show'
  170. },
  171. //状态栏字体颜色,只支持黑(#000000)和白(#FFFFFF)两种颜色。(,)
  172. statusBarFontColor:{
  173. type: [Array,String],
  174. default:function(){
  175. return new Array("#000000","#000000");
  176. }
  177. },
  178. //是否包含状态栏
  179. statusBar: {
  180. type: [Boolean, String],
  181. default: true
  182. },
  183. //状态栏背景颜色
  184. statusBarBackground:{
  185. type: String,
  186. default: ''
  187. },
  188. //导航栏阴影
  189. shadow: {
  190. type: [String, Boolean],
  191. default: false
  192. },
  193. //导航栏边框
  194. border: {
  195. type: [String, Boolean],
  196. default: false
  197. },
  198. //跳至普通页面
  199. defaultBackUrl: {
  200. type: String,
  201. default: ''
  202. },
  203. //跳至tabber页面
  204. backTabbarUrl: {
  205. type: String,
  206. default: '/pages/index/index'
  207. },
  208. //滑动后切换左插槽
  209. leftSlidiSwitch:{
  210. type: [Boolean,String],
  211. default: false,
  212. },
  213. //滑动后切换中间插槽
  214. centerSlidiSwitch:{
  215. type: [Boolean,String],
  216. default: false
  217. },
  218. //滑动后切换右插槽
  219. rightSlidiSwitch:{
  220. type: [Boolean,String],
  221. default: false
  222. },
  223. //页面的onPageScroll
  224. pageScroll:{
  225. type: Object,
  226. default:function(){
  227. return {}
  228. }
  229. },
  230. },
  231. created(){
  232. var that = this;
  233. //是否添加占位符
  234. switch (that.barPlaceholder){
  235. case 'show':
  236. that.placeholder = true;
  237. break;
  238. case 'hidden':
  239. that.placeholder = false;
  240. break;
  241. case 'auto':
  242. if(that.fixed){
  243. that.placeholder = true;
  244. }
  245. break;
  246. }
  247. //设置状态栏文字颜色
  248. that.setStatusBarFontColor();
  249. //文字颜色
  250. that.colorContainer = typeof that.color == 'object' ? that.color : [that.color,that.color];
  251. that.colorInfo = that.colorContainer[0];
  252. //导航栏透明设置 及监听滚动
  253. switch (that.transparent){
  254. case 'show':
  255. that.transparentValue = 1;
  256. break;
  257. case 'hidden':
  258. that.transparentValue = 0;
  259. break;
  260. case 'auto':
  261. that.setTVAuto(that.pageScroll)
  262. break;
  263. }
  264. that.setBgColor();
  265. //滑动切换
  266. if(that.fixed && (that.leftSlidiSwitch || that.centerSlidiSwitch || that.rightSlidiSwitch)){
  267. that.doScroll(that.pageScroll);
  268. }
  269. },
  270. watch:{
  271. pageScroll(val,oldVal){
  272. var that = this;
  273. //导航栏透明设置 及监听滚动
  274. switch (that.transparent){
  275. case 'show':
  276. that.transparentValue = 1;
  277. break;
  278. case 'hidden':
  279. that.transparentValue = 0;
  280. break;
  281. case 'auto':
  282. this.setTVAuto(val)
  283. break;
  284. }
  285. //滑动切换
  286. if(that.fixed && (that.leftSlidiSwitch || that.centerSlidiSwitch || that.rightSlidiSwitch)){
  287. that.doScroll(val);
  288. }
  289. },
  290. //监控透明度变化
  291. transparentValue(val,oldVal) {
  292. var that = this;
  293. //this.settingColor();
  294. //头条小程序不支持setNavigationBarColor方法
  295. // #ifndef MP-TOUTIAO || H5
  296. if(oldVal > 0.8){
  297. uni.setNavigationBarColor({
  298. frontColor: that.statusBarFontColorInfo[1],
  299. backgroundColor: that.backgroundColorRgb
  300. });
  301. }else if(oldVal < 0.2){
  302. uni.setNavigationBarColor({
  303. frontColor: that.statusBarFontColorInfo[0],
  304. backgroundColor: that.backgroundColorRgb
  305. });
  306. }
  307. // #endif
  308. // #ifdef MP-TOUTIAO
  309. if (tt.setNavigationBarColor) {
  310. if(oldVal > 0.8){
  311. tt.setNavigationBarColor({
  312. frontColor: that.statusBarFontColorInfo[1],
  313. backgroundColor: that.backgroundColorRgb,
  314. success(res) {},
  315. fail(res) {}
  316. });
  317. }else if(oldVal < 0.2){
  318. tt.setNavigationBarColor({
  319. frontColor: that.statusBarFontColorInfo[0],
  320. backgroundColor: that.backgroundColorRgb,
  321. success(res) {},
  322. fail(res) {}
  323. });
  324. }
  325. } else {
  326. console.log("hx-navbar 提示:当前客户端版本过低,无法使用状态栏颜色修改功能,请升级(基础库1.40+)。")
  327. }
  328. // #endif
  329. },
  330. //监听背景颜色
  331. backgroundColor(val,old){
  332. var that = this;
  333. that.setBgColor()
  334. },
  335. color(val,old){
  336. var that = this;
  337. //文字颜色
  338. /* that.colorContainer = typeof val == 'object' ? val : [val,val];
  339. that.colorInfo = that.colorContainer[0]; */
  340. }
  341. },
  342. methods: {
  343. onClickLeft () {
  344. if(this.back){
  345. if(getCurrentPages().length>1){
  346. uni.navigateBack();
  347. }else{
  348. // #ifdef H5
  349. history.back()
  350. // #endif
  351. // #ifndef H5
  352. if(this.defaultBackUrl){
  353. uni.redirectTo({
  354. url:this.defaultBackUrl
  355. })
  356. }else{
  357. if(this.backTabbarUrl){
  358. uni.reLaunch({
  359. url: this.backTabbarUrl
  360. });
  361. }
  362. }
  363. // #endif
  364. }
  365. }else{
  366. this.$emit('click-left')
  367. }
  368. },
  369. onClickRight () {
  370. this.$emit('click-right')
  371. },
  372. //监听滚动后的操作
  373. doScroll(e){
  374. let that = this;
  375. that.$emit('scroll', e);
  376. if (e.scrollTop > 100) {
  377. that.slotSlidiSwitch = 1;
  378. } else {
  379. that.slotSlidiSwitch = 0
  380. }
  381. },
  382. //滑动渐变
  383. setTVAuto(e){
  384. let that = this;
  385. that.$emit('scroll', e);
  386. if (e.scrollTop > 100) {
  387. that.transparentValue = 1;
  388. that.colorInfo = that.colorContainer[1];
  389. } else {
  390. that.transparentValue = e.scrollTop / 100;
  391. that.colorInfo = that.colorContainer[0];
  392. }
  393. that.setBgColor();
  394. },
  395. //背景颜色
  396. setBgColor(){
  397. var that = this;
  398. //如果存在背景图片则背景颜色失效
  399. // if(that.backgroundImg){
  400. // that.backgroundColorRgba = "url(" + that.backgroundImg + ")";
  401. // return;
  402. // }
  403. //背景颜色
  404. if(typeof that.backgroundColor[0] == 'object'){
  405. let l = that.backgroundColor.length;
  406. if( l >= 2){
  407. let rgbStr = "linear-gradient("+ that.backgroundColorLinearDeg +"deg,";
  408. let c = null;
  409. for(var i in that.backgroundColor){
  410. c = that.backgroundColor[i];
  411. rgbStr += "rgba("+ c[0] + "," + c[1] + "," + c[2] +"," + that.transparentValue+")";
  412. if(l != (i*1)+1){
  413. rgbStr += ",";
  414. }
  415. }
  416. rgbStr += ")";
  417. that.backgroundColorRgba = rgbStr;
  418. }
  419. }else{
  420. let rgbStr = that.backgroundColor[0] + ','+ that.backgroundColor[1] + ','+ that.backgroundColor[2];
  421. that.backgroundColorRgb= 'rgb('+ rgbStr + ')';
  422. that.backgroundColorRgba = 'rgba('+ rgbStr +',' + that.transparentValue+')';
  423. }
  424. },
  425. setStatusBarFontColor(){
  426. var that = this;
  427. if(typeof that.statusBarFontColor == 'string'){
  428. that.statusBarFontColorInfo = [that.statusBarFontColor,that.statusBarFontColor];
  429. }else if(typeof that.statusBarFontColor == 'object'){
  430. if (that.statusBarFontColor.length==1){
  431. that.statusBarFontColorInfo = [that.statusBarFontColor[0],that.statusBarFontColor[0]];
  432. }else if(that.statusBarFontColor.length>=2){
  433. that.statusBarFontColorInfo = [that.statusBarFontColor[0],that.statusBarFontColor[1]];
  434. }
  435. }
  436. // #ifndef MP-TOUTIAO || H5
  437. uni.setNavigationBarColor({
  438. frontColor: that.statusBarFontColorInfo[0],
  439. backgroundColor: that.backgroundColorRgb
  440. });
  441. // #endif
  442. // #ifdef MP-TOUTIAO
  443. if (tt.setNavigationBarColor) {
  444. tt.setNavigationBarColor({
  445. frontColor: that.statusBarFontColorInfo[0],
  446. backgroundColor: that.backgroundColorRgb
  447. });
  448. } else {
  449. console.log("hx-navbar 提示:当前客户端版本过低,无法使用状态栏颜色修改功能,请升级(基础库1.40+)。")
  450. }
  451. // #endif
  452. }
  453. },
  454. destroyed(){
  455. },
  456. }
  457. </script>
  458. <style lang="scss">
  459. $nav-height: 44px;
  460. .hd{
  461. overflow: hidden;
  462. }
  463. //防止其他ui影响
  464. .hx-navbar uni-view,
  465. .hx-navbar uni-scroll-view,
  466. .hx-navbar uni-swiper,
  467. .hx-navbar uni-button,
  468. .hx-navbar uni-input,
  469. .hx-navbar uni-textarea,
  470. .hx-navbar uni-label,
  471. .hx-navbar uni-navigator,
  472. .hx-navbar uni-image {
  473. box-sizing: unset;
  474. }
  475. .hx-navbar {
  476. position: relative;
  477. padding-top: 0;
  478. overflow: hidden;
  479. &__content {
  480. display: block;
  481. position: relative;
  482. width: 100%;
  483. /*background-color: $uni-bg-color*/;
  484. overflow: hidden;
  485. .navbgimg{
  486. position: absolute;
  487. top: 0;
  488. left: 0;
  489. z-index: 0;
  490. width: 100%;
  491. }
  492. .hx-navbar__content_view {
  493. // line-height: $nav-height;
  494. display: flex;
  495. align-items: center;
  496. }
  497. .hx-status-bar {
  498. display: block;
  499. width: 100%;
  500. height: 40px;
  501. height: var(--status-bar-height);
  502. position: relative;
  503. z-index: 1;
  504. }
  505. }
  506. &__header {
  507. position: relative;
  508. z-index: 1;
  509. display: flex;
  510. flex-direction: row;
  511. width: 100%;
  512. height: $nav-height;
  513. line-height: $nav-height;
  514. font-size: 36upx;
  515. transition: color 0.5s ease 0s;
  516. &-btns {
  517. display: inline-flex;
  518. flex-wrap: nowrap;
  519. flex-shrink: 0;
  520. min-width: 54px;
  521. //padding: 0 6px;
  522. &:first-child {
  523. padding-left: 0;
  524. }
  525. &:last-child {
  526. min-width: 54px;
  527. }
  528. &-right:last-child{
  529. text-align: right;
  530. flex-direction: row-reverse;
  531. }
  532. }
  533. &-container {
  534. width: 100%;
  535. margin: 0 10upx;
  536. &-inner {
  537. width: 100%;
  538. display: flex;
  539. justify-content: center;
  540. font-size: 36upx;
  541. // padding-right: 60upx;
  542. }
  543. }
  544. }
  545. &__placeholder {
  546. &-view {
  547. height: $nav-height;
  548. }
  549. }
  550. &--fixed {
  551. position: fixed;
  552. top:0;
  553. z-index: 998;
  554. }
  555. &--shadow {
  556. box-shadow: 0 2upx 12upx #ccc;
  557. }
  558. &--border:after {
  559. position: absolute;
  560. z-index: 3;
  561. bottom: 0;
  562. left: 0;
  563. right: 0;
  564. height: 1px;
  565. content: '';
  566. -webkit-transform: scaleY(.5);
  567. transform: scaleY(.5);
  568. background-color: #efefef;
  569. }
  570. }
  571. .left_back{
  572. padding-left: 12upx;
  573. padding-right: 12upx;
  574. }
  575. </style>