微信小程序電商實戰(zhàn)-自定義頂部導(dǎo)航欄

夢想.jpg

感謝讀者@Followyour的好心提醒,對于安卓機,下拉刷新確實無法做到導(dǎo)航欄不跟著下拉义锥,特此做一下修正,并且自定義導(dǎo)航欄存在它的不足岩灭,比如部分安卓機型無法獲取statusBarHeight拌倍,因此給予一個默認(rèn)值20PX,但這并不能完全覆蓋所有機型噪径,還有一點是使用自定義導(dǎo)航欄對于web-view的兼容性未做測試

本文章是一個系列文章柱恤,以一個完整的可用于生產(chǎn)的實際項目探索微信小程序開發(fā)中我們經(jīng)常會遇到的問題,希望能提供完美的解決方案找爱,這次是本系列文章的第二篇了梗顺,以下列出該系列文章鏈接。

  1. 微信小程序及h5车摄,基于taro寺谤,zoro最佳實踐探索
  2. 微信小程序電商實戰(zhàn)-登錄模塊設(shè)計

微信自6.6.0版本之后提供了自定義頂部導(dǎo)航欄的功能,這使得我們的全屏頁面設(shè)計成為了可能

首先演示下最終的實現(xiàn)效果


微信小程序自定義導(dǎo)航欄演示.gif

我們實現(xiàn)了一個與微信之前的導(dǎo)航欄行為基本一致吮播,樣式可自定義的導(dǎo)航欄变屁,接下來讓我們一步一步實現(xiàn)它,這里主要需要考慮如下幾點

  • 不同的手機意狠,狀態(tài)欄高度不同粟关,需要進(jìn)行相關(guān)適配
  • 當(dāng)開啟小程序下拉刷新時,如何讓頂部導(dǎo)航不會跟著下拉(僅IOS有效)
  • 自定義導(dǎo)航欄封裝成獨立組件摄职,實現(xiàn)僅需引入到頁面誊役,無需對頁面樣式做相關(guān)適配工作

該項目托管于github,有興趣的可以直接查看源碼谷市,weapp-clover蛔垢,如何運行項目源碼請查看ztaro

要想實現(xiàn)自定義導(dǎo)航,首先我們需要配置navigationStyle為custom(src/app.js)

config = {
  window: {
    navigationStyle: 'custom'
  }
}

再實際情況中迫悠,我們往往需要對自定義導(dǎo)航進(jìn)行各種各樣的定制化鹏漆,因此我們希望,封裝一個最基本的導(dǎo)航欄创泄,用于解決適配問題艺玲,其他樣式的導(dǎo)航欄僅需對其進(jìn)行二次封裝,無需在關(guān)心適配問題鞠抑,對于這個項目饭聚,我們封裝組件如下:

ComponentBaseNavigation 導(dǎo)航欄基本組件,用于解決適配問題
ComponentHomeNavigation 引入基本導(dǎo)航組件搁拙,定制化首頁導(dǎo)航欄組件
ComponentCommonNavigation 引入基本導(dǎo)航組件秒梳,定制化其他頁面導(dǎo)航組件

ComponentBaseNavigation實現(xiàn)

對于適配不通手機頂部的狀態(tài)欄高度法绵,我們需要利用微信wx.getSystemInfo獲取狀態(tài)欄的高度,因此在user model中新增如下代碼(src/models/user.js)

// 省略其他無關(guān)代碼
import Taro from '@tarojs/taro'

export default {
  namespace: 'user',

  mixins: ['common'],

  state: {
    systemInfo: {},
  },

  async setup({ put }) {
    // 新增初始化獲取用戶手機系統(tǒng)相關(guān)信息酪碘,存儲到redux全局狀態(tài)中
    Taro.getSystemInfo().then(systemInfo =>
      put({ type: 'update', payload: { systemInfo } }),
    )
  }
}

實現(xiàn)組件邏輯(src/components/base/navigation/navigation.js)

import Taro, { Component } from '@tarojs/taro'
import { View } from '@tarojs/components'
import { connect } from '@tarojs/redux'

import './navigation.scss'

@connect(({ user }) => ({
  // 鏈接redux中存儲的狀態(tài)欄高度到組件中
  statusBarHeight: user.systemInfo.statusBarHeight,
}))
class ComponentBaseNavigation extends Component {
  static defaultProps = {
    color: 'white',
    backgroundColor: '#2f3333',
  }

  render() {
    const { statusBarHeight, backgroundColor, color } = this.props

    const barStyle = {
      paddingTop: `${statusBarHeight || 20}px`,
      backgroundColor,
      color,
    }

    return (
      <View className="navigation">
        <View className="bar" style={barStyle}>
          {this.props.children}
        </View>
        <View className="placeholder" style={barStyle} />
      </View>
    )
  }
}

export default ComponentBaseNavigation

樣式如下(src/components/base/navigation.scss)

// 大寫的PX單位是為了告訴Taro朋譬,不要轉(zhuǎn)換成單位rpx
// 通過測試和觀察發(fā)現(xiàn),微信頂部的膠囊寬高如下兴垦,并且各個屏幕下一致
// 因此采用PX單位
$capsule-padding: 6PX; // 膠囊的上下padding距離
$capsule-height: 32PX; // 膠囊的高度
$capsule-width: 88PX; // 膠囊的寬度

$navigation-height: $capsule-padding * 2 + $capsule-height;
$navigation-font-size: 15PX;
$navigation-icon-font-size: 25PX;
$navigation-box-shadow: 0 2PX 2PX #222;

.navigation {
  position: relative;
  background: transparent;
  
  .bar {
    position: fixed;
    top: 0;
    left: 0;
    display: flex;
    flex-direction: row;
    justify-content: center;
    align-items: center;
    width: 100%;
    height: $navigation-height;
    z-index: 1;
    font-size: $navigation-font-size;
  }

  .placeholder {
    display: block;
    height: $navigation-height;
    background: transparent;
  }
}

要解決我們先前提到的問題當(dāng)開啟小程序下拉刷新時徙赢,如何讓頂部導(dǎo)航不會跟著下拉,僅僅只需設(shè)置.bar樣式為position: fixed探越,這樣當(dāng)我們下拉刷新時導(dǎo)航欄就不會跟著動了狡赐,那為什么我們還需要.placeholder標(biāo)簽?zāi)?/p>

如果你嘗試著去掉它,并且運行查看效果時扶关,你會發(fā)現(xiàn)阴汇,頁面的內(nèi)容會被頂部導(dǎo)航欄遮擋了,我們需要對每個頁面進(jìn)行額外的設(shè)置以使它如預(yù)期一樣顯示节槐,比如給每個頁面設(shè)置頂部padding,這樣的消耗太大拐纱,因此我們專門設(shè)置placeholder標(biāo)簽占據(jù)與導(dǎo)航欄相同的高度铜异,使頁面不被遮擋,且無需額外處理

ComponentHomeNavigation實現(xiàn)

有了這樣一個基礎(chǔ)組件秸架,我們要實現(xiàn)首頁導(dǎo)航欄效果就變得相當(dāng)?shù)暮唵瘟俗嶙苯由洗a(src/components/home/navigation/navigation.js)

import Taro, { Component } from '@tarojs/taro'
import { View, Image, Text } from '@tarojs/components'

import { noop } from '../../../utils/tools'
import ComponentBaseNavigation from '../../base/navigation/navigation'

import './navigation.scss'

class ComponentHomeNavigation extends Component {
  static defaultProps = {
    onSearch: noop,
  }

  render() {
    const { onSearch } = this.props

    return (
      <ComponentBaseNavigation>
        <View className="navigation">
          <Image className="logo" src="@oss/logo.png" />
          <View className="search" onClick={onSearch}>
            <View className="icon iconfont icon-search" />
            <Text className="text">搜索</Text>
          </View>
        </View>
      </ComponentBaseNavigation>
    )
  }
}

export default ComponentHomeNavigation

引入導(dǎo)航組件到首頁中, 省略樣式代碼(src/pages/home/home.js)

import Taro, { Component } from '@tarojs/taro'
import { View } from '@tarojs/components'
import { dispatcher } from '@opcjs/zoro'

import ComponentCommonLogin from '../../components/common/login/login'
import ComponentCommonSlogan from '../../components/common/slogan/slogan'
// 引入導(dǎo)航組件
import ComponentHomeNavigation from '../../components/home/navigation/navigation'
import ComponentHomeCarousel from '../../components/home/carousel/carousel'
import ComponentHomeBrand from '../../components/home/brand/brand'

import './home.scss'

class PageHome extends Component {
  config = {
    enablePullDownRefresh: true,
  }

  state = {
    // 請到README.md中查看此參數(shù)說明
    __TAB_PAGE__: true, // eslint-disable-line
  }

  componentDidMount() {
    dispatcher.banner.getBannerInfo()
    dispatcher.brand.getHotBrandList()
  }

  onPullDownRefresh() {
    Promise.all([
      dispatcher.banner.getBannerInfo(),
      dispatcher.brand.getHotBrandList(),
    ])
      .then(Taro.stopPullDownRefresh)
      .catch(Taro.stopPullDownRefresh)
  }

  handleGoSearch = () => Taro.navigateTo({ url: '/pages/search/search' })

  render() {
    return (
      <View className="home">
        <ComponentCommonLogin />
        <ComponentHomeNavigation onSearch={this.handleGoSearch} />
        <ComponentHomeCarousel />
        <View class="content">
          <ComponentCommonSlogan />
          <ComponentHomeBrand />
        </View>
      </View>
    )
  }
}

export default PageHome

ComponentCommonNavigation實現(xiàn)

該組件的實現(xiàn)方式與首頁基本一致,需要提的一點就是返回鍵的實現(xiàn)东抹,我們該如何統(tǒng)一的判斷該頁面是否需要返回鍵呢蚂子,這里需要利用微信接口wx.getCurrentPages(),實現(xiàn)代碼如下(src/components/common/navigation/navigation.js)

import Taro, { Component } from '@tarojs/taro'
import { View } from '@tarojs/components'
import classNames from 'classnames'

import ComponentBaseNavigation from '../../base/navigation/navigation'

import './navigation.scss'

class ComponentCommonNavigation extends Component {
  static defaultProps = {
    title: '',
  }

  state = {
    canBack: false,
  }

  componentDidMount() {
    // 獲取當(dāng)前頁面是否需要返回鍵
    const canBack = Taro.getCurrentPages().length > 1
    this.setState({ canBack })
  }

  handleGoHome = () => Taro.switchTab({ url: '/pages/home/home' })
  
  handleGoBack = () => Taro.navigateBack()

  render() {
    const { title } = this.props
    const { canBack } = this.state

    return (
      <ComponentBaseNavigation>
        <View className={classNames('navigation', { padding: !canBack })}>
          <View className="tools">
            {canBack && (
              <View
                className="iconfont icon-arrow-left back"
                onClick={this.handleGoBack}
              />
            )}
            <View
              className="iconfont icon-home home"
              onClick={this.handleGoHome}
            />
          </View>
          <View className="title">{title}</View>
        </View>
      </ComponentBaseNavigation>
    )
  }
}

export default ComponentCommonNavigation

感謝觀看缭黔,文筆不佳食茎,不能完全表達(dá)出設(shè)計思路,代碼是最好的表達(dá)馏谨,移步weapp-clover

本項目會持續(xù)完善别渔,如有興趣,請關(guān)注一波

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末惧互,一起剝皮案震驚了整個濱河市哎媚,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌喊儡,老刑警劉巖拨与,帶你破解...
    沈念sama閱讀 206,723評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異艾猜,居然都是意外死亡买喧,警方通過查閱死者的電腦和手機攀甚,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,485評論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來岗喉,“玉大人秋度,你說我怎么就攤上這事∏玻” “怎么了荚斯?”我有些...
    開封第一講書人閱讀 152,998評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長查牌。 經(jīng)常有香客問我事期,道長,這世上最難降的妖魔是什么纸颜? 我笑而不...
    開封第一講書人閱讀 55,323評論 1 279
  • 正文 為了忘掉前任兽泣,我火速辦了婚禮,結(jié)果婚禮上胁孙,老公的妹妹穿的比我還像新娘唠倦。我一直安慰自己,他們只是感情好涮较,可當(dāng)我...
    茶點故事閱讀 64,355評論 5 374
  • 文/花漫 我一把揭開白布稠鼻。 她就那樣靜靜地躺著,像睡著了一般狂票。 火紅的嫁衣襯著肌膚如雪候齿。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,079評論 1 285
  • 那天闺属,我揣著相機與錄音慌盯,去河邊找鬼。 笑死掂器,一個胖子當(dāng)著我的面吹牛亚皂,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播唉匾,決...
    沈念sama閱讀 38,389評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼孕讳,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了巍膘?” 一聲冷哼從身側(cè)響起厂财,我...
    開封第一講書人閱讀 37,019評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎峡懈,沒想到半個月后璃饱,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,519評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡肪康,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,971評論 2 325
  • 正文 我和宋清朗相戀三年荚恶,在試婚紗的時候發(fā)現(xiàn)自己被綠了撩穿。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,100評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡谒撼,死狀恐怖食寡,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情廓潜,我是刑警寧澤抵皱,帶...
    沈念sama閱讀 33,738評論 4 324
  • 正文 年R本政府宣布,位于F島的核電站辩蛋,受9級特大地震影響呻畸,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜悼院,卻給世界環(huán)境...
    茶點故事閱讀 39,293評論 3 307
  • 文/蒙蒙 一伤为、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧据途,春花似錦绞愚、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,289評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至便脊,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間光戈,已是汗流浹背哪痰。 一陣腳步聲響...
    開封第一講書人閱讀 31,517評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留久妆,地道東北人晌杰。 一個月前我還...
    沈念sama閱讀 45,547評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像筷弦,于是被迫代替她去往敵國和親肋演。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,834評論 2 345

推薦閱讀更多精彩內(nèi)容