uni-app跨端自定義navbar+tabbar元件|沉浸式導航條|仿鹹魚凸起標籤欄
在跨端專案開發中,uniapp是個不錯的框架。採用vue.js和小程式語法結構,使得入門開發更容易。擁有非常豐富的外掛生態。支援編譯到h5、小程式及App等多個終端平臺。
如上圖:編譯到h5+小程式+App端效果
◆ 準備
在專案根目錄components下新建ua-navbar和ua-tabbar元件。
在main.js中全域性引入元件。
// 引入自定義元件 import NavBar from './components/ua-navbar/index.vue' import TabBar from './components/ua-tabbar/index.vue' Vue.component('navbar', NavBar) Vue.component('tabbar', TabBar)
HBuilderX 2.5.5起支援easycom元件模式。大家也可以根據需要改為此種引入模式,會更加方便。
傳統vue元件,需要安裝、引用、註冊,三個步驟後才能使用元件。easycom將其精簡為一步。 只要元件安裝在專案的components目錄下,並符合components/元件名稱/元件名稱.vue目錄結構。就可以不用引用、註冊,直接在頁面中使用。
◆ uniapp獲取手機狀態條
如果專案中導航欄採用自定義模式 "globalStyle": { "navigationStyle": "custom" } 那麼狀態列就需要重新計算了。
在App.vue中全域性設定
/** * @Desc uniapp獲取狀態列資訊 * @Time andy by 2021/7/6 * @About Q:282310962 wx:xy190310 */ <script> import Vue from 'vue' export default { globalData: { // 全域性設定狀態列和導航欄高度 statusBarH: 0, customBarH: 0, }, onLaunch: function() { uni.getSystemInfo({ success: (e) => { // 獲取手機狀態列高度 let statusBar = e.statusBarHeight let customBar // #ifndef MP customBar = statusBar + (e.platform == 'android' ? 50 : 45) // #endif // #ifdef MP-WEIXIN // 獲取膠囊按鈕的佈局位置資訊 let menu = wx.getMenuButtonBoundingClientRect() // 導航欄高度 = 膠囊下距離 + 膠囊上距離 - 狀態列高度 customBar = menu.bottom + menu.top - statusBar // #endif // #ifdef MP-ALIPAY customBar = statusBar + e.titleBarHeight // #endif // 注意:此方法不支援原生Nvue頁面 Vue.prototype.statusBarH = statusBar Vue.prototype.customBarH = customBar // 支援nvue頁面寫法(相容H5/小程式/APP/APP-Nvue) this.globalData.statusBarH = statusBar this.globalData.customBarH = customBar } }) }, // ... } </script>
◆ uniapp自定義沉浸式導航條
<!-- 導航條模板 --> <template> <view class="ua__navbar"> <view class="ua__navbar-wrap" :class="{'custom': custom, 'fixed': fixed || transparent}" :style="{'height': customBarH + 'px', 'padding-top': (custom ? statusBarH : 0) + 'px', 'background': bgcolor, 'color': color, 'z-index': zIndex}"> <!-- //左側 (返回) --> <view class="action navbar-action__left" v-if="back && back!='false'" @click="onBack"> <template v-if="$slots.back"> <slot name="back" /> </template> <template v-else><text class="iconfont nvuefont" :style="{'color': color}">{{'\ue84c'}}</text></template> <slot name="backText" /> </view> <slot name="left" /> <!-- //標題 --> <view v-if="!search" class="navbar-title" :class="{'center': center}"> <template v-if="$slots.title"> <slot name="title" /> </template> <template v-else><text :style="{'color': color}">{{title}}</text></template> </view> <!-- //搜尋框 --> <view v-if="search" class="action navbar-action__search"> <slot name="search" /> </view> <!-- //右側 --> <view class="action navbar-action__right"> <slot name="right" /> </view> </view> </view> </template>
<script> export default { props: { // 是否採用自定義導航模式 custom: { type: [Boolean, String], default: false }, // 是否返回 back: { type: [Boolean, String], default: true }, // 標題 title: { type: String, default: '' }, // 標題顏色 color: { type: String, default: '#353535' }, // 背景色 bgcolor: { type: String, default: '#fff' }, // 標題是否居中 center: { type: [Boolean, String], default: false }, // 搜尋框 search: { type: [Boolean, String], default: false }, // 是否固定導航 fixed: { type: [Boolean, String], default: false }, // 是否背景透明 transparent: { type: [Boolean, String], default: false }, // 設定層疊 zIndex: { type: [Number, String], default: '2022' }, }, data() { return { statusBarH: 0, customBarH: 0, } }, beforeCreate() { // #ifdef APP-NVUE var domModule = weex.requireModule('dom'); domModule.addRule('fontFace', { 'fontFamily': "nvueIcon", 'src': "url('/static/fonts/iconfont.ttf')" }); // #endif }, created() { const app = getApp() // 獲取狀態列和導航條高度 this.statusBarH = app.globalData.statusBarH this.customBarH = this.custom ? app.globalData.customBarH : app.globalData.customBarH - this.statusBarH }, methods: { onBack() { uni.navigateBack({ delta: 1 }) } } } </script>
支援自定義背景色(漸變)、文字顏色、標題居中、搜尋框、透明沉浸式、是否固定及層級等功能。
也可以根據自定義插槽來實現一些城市選擇、按鈕、圓點提示、圖片等功能。
<navbar :back="true" title="標題內容" bgcolor="#09f" color="#fff" fixed zIndex="1010" />
<navbar custom bgcolor="linear-gradient(to right, #ff007f, #0000ff)" color="#55ffff" center transparent zIndex="3003"> <template slot="back"><text class="iconfont icon-arrL"></text></template> <template slot="backText"><text>我的</text></template> <template slot="title"><image src="/static/img2.jpg" style="height:20px;width:20px;" /> Admin</template> <template slot="right"> <view class="ml-20" @click="handleAdd"><text class="iconfont icon-tianjia"></text></view> <view class="ml-20"><text class="iconfont icon-msg"></text></view> </template> </navbar>
◆ uniapp自定義底部標籤欄導航
<!-- 標籤欄模板 --> <template> <view class="ua__tabbar" :class="{'fixed': fixed}"> <view class="ua__tabbar-wrap flexbox flex-alignc" :style="{'background': bgcolor}"> <view v-for="(item, index) in tabs" :key="index" class="ua__tabbar-item flexbox flex-col" :class="currentTabIndex == index ? 'on' : ''" @click="switchTabs(index, item)"> <view v-if="item.icon||item.img" class="ua__tabbar-icon" :class="{'dock': item.dock}"> <template v-if="item.dock"> <view class="dock-bg flexbox" :style="{'background': item.dockBg ? item.dockBg : activeColor}"> <text v-if="item.icon" class="iconfont nvuefont" :class="item.icon" :style="{'color': (currentTabIndex == index && !item.dock ? activeColor : color), 'font-size': item.iconSize}">{{item.icon.charAt(1) == '' ? item.icon : ''}}</text> <image v-if="item.img" class="iconimg" :src="currentTabIndex == index && item.activeImg ? item.activeImg : item.img" :style="{'font-size': item.iconSize}" /> </view> </template> <template v-else> <text v-if="item.icon" class="iconfont nvuefont" :class="item.icon" :style="{'color': (currentTabIndex == index && !item.dock ? activeColor : color), 'font-size': item.iconSize}">{{item.icon.charAt(1) == '' ? item.icon : ''}}</text> <image v-if="item.img" class="iconimg" :src="currentTabIndex == index && item.activeImg ? item.activeImg : item.img" :style="{'font-size': item.iconSize}" /> </template> <text v-if="item.badge" class="vui__badge ua__tabbar-icon__badge">{{item.badge}}</text> <text v-if="item.dot" class="vui__badge-dot ua__tabbar-icon__badgeDot"></text> </view> <view v-if="item.title&&!item.dock" class="ua__tabbar-title"> <text class="ua__tabbar-title__text" :style="{'color': (currentTabIndex == index ? activeColor: color)}">{{item.title}}</text> <template v-if="!item.icon&&!item.img"> <text v-if="item.badge" class="vui__badge ua__tabbar-title__badge">{{item.badge}}</text> <text v-if="item.dot" class="vui__badge-dot ua__tabbar-title__badgeDot"></text> </template> </view> </view> </view> </view> </template>
<script> export default { props: { current: { type: [Number, String], default: 0 }, // 背景色 bgcolor: { type: String, default: '#fff' }, // 顏色 color: { type: String, default: '#9d9ea5' }, // 啟用顏色 activeColor: { type: String, default: '#ff007f' }, // 是否固定 fixed: { type: [Boolean, String], default: false }, // tab選項 tabs: { type: Array, default: () => [] }, }, data() { return { currentTabIndex: this.current } }, beforeCreate() { // #ifdef APP-NVUE var domModule = weex.requireModule('dom'); domModule.addRule('fontFace', { 'fontFamily': "nvueIcon", 'src': "url('/static/fonts/iconfont.ttf')" }); // #endif }, created() { /* uniapp獲取當前頁面路徑 (App、小程式、H5通用) */ let pages = getCurrentPages() //獲取頁面棧陣列 let page = pages[pages.length - 1] //獲取當前頁面物件 let route = page.route //獲取當前頁面路由 this.selectRoute(route) }, methods: { // 匹配當前路由頁面 selectRoute(curPath) { curPath = curPath.substr(0, 1) == '/' ? curPath : '/' + curPath this.tabs.map((item, index) => { if(item.path == curPath) { this.currentTabIndex = index } }) }, switchTabs(index, item) { if(item.path) { // this.$router.push(item.path) uni.navigateTo({ url: item.path }) }else { this.currentTabIndex = index this.$emit('click', index) } } } } </script>
<style scoped> .nvuefont {font-family: nvueIcon;} .ua__tabbar { /* #ifndef APP-NVUE */ display:-webkit-box; display:-webkit-flex; display:flex; display:-ms-flexbox; /* #endif */ flex-direction: row; } .ua__tabbar-wrap {flex: 1; flex-direction: row; background-color: #fff; color: #333; height: 110rpx; position: relative; z-index: 2021;} .ua__tabbar.fixed{padding-top: 110rpx;} .ua__tabbar.fixed .ua__tabbar-wrap{ /* #ifdef APP-NVUE */ left: 0; right: 0; /* #endif */ /* #ifndef APP-NVUE */ width: 100%; /* #endif */ max-width: 750px; position: fixed; bottom: 0; } .ua__tabbar-item{flex: 1; align-items: center; justify-content: center; height: 110rpx; position: relative;} /* 圖示 */ .ua__tabbar-icon{ /* #ifdef APP-NVUE */ padding: 0 20rpx; /* #endif */ display: flex; align-items: center; justify-content: center; margin: 0 auto; height: 50rpx; position: relative; border:1px dashed red; } /* dock選單 */ .ua__tabbar-item .dock { /* #ifdef APP-NVUE */ height: 200rpx; /* #endif */ /* #ifndef APP-NVUE */ position: static; /* #endif */ border: 1px solid green; } .ua__tabbar-item .dock .dock-bg { background-color: #f57b15; border-radius: 1000rpx; align-items: center; justify-content: center; height: 100rpx; width: 100rpx; /* #ifdef APP-NVUE */ box-shadow: 0 0 6px rgba(0,0,0,.3); /* #endif */ /* #ifndef APP-NVUE */ box-shadow: 0 8px 12px rgba(0,0,0,.3); position: absolute; top: -50rpx; left: 50%; transform: translateX(-50%); /* #endif */ } .ua__tabbar-item .dock .iconfont {color: #fff!important;} /* 字型圖示/圖片 */ .ua__tabbar-item .iconfont{color:#9d9ea5; font-size: 45rpx; transition: color .3s;} .ua__tabbar-item .iconimg{display: block; font-size: 40rpx; height: 1em; width: 1em;} .ua__tabbar-item.on .iconfont{color:#f57b15;} /* 標題 */ .ua__tabbar-title{ /* #ifdef APP-NVUE */ padding: 0 20rpx; /* #endif */ position: relative; transition: color .3s; border: 1px solid blue; } .ua__tabbar-title__text {color: #9d9ea5; font-size: 30rpx; } .ua__tabbar-item.on .ua__tabbar-title__text{color: #f57b15;} </style>
支援自定義背景色(漸變)、文字顏色|選中顏色、是否固定、是否dock凸起按鈕等功能。
<tabbar bgcolor="linear-gradient(to top, rgba(0, 255, 127, 0.9), transparent)" color="#eee" activeColor="#ff0" fixed @click="handleTabClicked" :tabs="[ { path: `/pages/index/index`, icon: `icon-home`, title: `首頁`, badge: 38, }, { icon: `icon-tianjia`, dock: true, dockBg: `#ff007f`, iconSize: `30px`, }, { icon: `\ue606`, dot: true, title: `錢包`, }, ]" />
tabs選項裡面的引數
path: '/pages/index/index' 自定義跳轉頁面 icon: 'icon-home' iconfont圖示 支援icon-xxx和`\ue642`寫法,在nvue頁面必須寫成`\ue642`格式 title: '首頁' 標題 img: 'http://...' 自定義圖片地址 activeImg: '' 自定義選中圖片 dock: true 底部中間凸起按鈕 dockBg: '#f90' 凸起按鈕背景色(不設定則為activeColor) iconSize: '30px' 圖示/圖片大小 badge: 18 小紅點數字 dot: true 小圓點
根據專案需要,可以設定多個子標籤欄選單。
注意:在nvue頁面,icon圖示則需要使用 '\ue642' 這種unicode寫法。
<tabbar bgcolor="linear-gradient(to right, #00ffff, #00ff7f)" color="#fff" active-color="#ff007f" fixed="true" @click="tabbarClicked" :tabs="[ { path: `/pages/index/index`, icon: `icon-search`, title: `首頁`, badge: 6 }, { icon: `\ue644`, dot: true }, { img: `/static/logo.png`, title: `釋出`, dock: true, dockBg: `#ff007f`, iconSize: `30px` }, { img: `/static/img1.jpg`, activeImg: `/static/img2.jpg`, title: `圖片`, dot: true }, { path: `/pages/ucenter/index`, icon: `icon-search`, title: `我` }, ]" />
ending,基於uniapp模擬導航條/底部tabbar元件就介紹到這裡。希望以上分享對大家有所幫助!?