基于Taro小程序框架,实现一个小程序自定义导航栏

3,488 阅读1分钟

taro官方文档地址先给出:taro-docs.jd.com/taro/docs/R…;

接下来我们要实现的是这个样式的一个自定义导航条:
image.png
简单分析一下,要实现这样的导航条就得兼容所有设备,又因为不同设备系统原有得导航栏高度是不同得。注:下文的Taro是框架对wx对象做的二次封装,其api name和小程序官方一致
而小程序官方提供了这样得api:Taro.getSystemInfoSync(),用于获取系统状态栏信息,可以拿到状态栏高度:statusBarHeight
为了让自定义按钮能和小程序自带的胶囊表现一致,所以就需要获取这个胶囊的大小,小程序提供了Taro.getMenuButtonBoundingClientRect()来获取,剩下的就是常规的写界面了,具体实现看下面的完整代码吧

以下代码是基于我们项目中的UI设计实现

import{ PureComponent } from 'react';
import Taro, { getCurrentInstance } from '@tarojs/taro';
import { View, Image, Text } from '@tarojs/components';

import './index.scss';

class NavBar extends PureComponent {

  static defaultProps = {
    title: null, // 标题
    iconSize: 16, // 默认的icon大小,自定义的左侧返回和主页icon
    homePath: process.env.HOME_PATH, // 这里我是把项目的首页地址配置到了环境变脸中,方便使用
    hideBtns: false, // 是否隐藏左侧按钮
    hideHome: false, // 是否隐藏主页按钮
    onClickBack: null, // 主页按钮的点击事件
    onClickHome: null // 返回按钮的点击事件
  };

  // 主页按钮的点击事件,再给上层暴露的接口中返回了当前主页路径
  handelHomeIcon = () => {
    const { homePath, onClickHome } = this.props;
    if (onClickHome) {
      onClickHome(homePath)
      return
    }
    Taro.reLaunch({url: `/${homePath}`});
  };
  // 返回按钮的点击事件
  handelBackIcon = () => {
    const { onClickBack } = this.props;
    if (onClickBack) {
      onClickBack();
      return
    };
    Taro.navigateBack({delta: 1})
  };

  render() {
    // 获取系统状态栏高度
    const { statusBarHeight } = Taro.getSystemInfoSync()
    // 获取小程序右上角胶囊的大小
    const { height, top } = Taro.getMenuButtonBoundingClientRect();
    /*
      计算出小程序导航栏的整体高度,这里要加上系统状态栏的高度,
      否则小程序顶部内容会顶到状态栏最顶部位置
    */
    const navBarHeight = height + (top - statusBarHeight) * 2 + statusBarHeight;
    /*
      获取当前路劲中的query参数,如果带有页面标题则默认展示query参数中的标题
      这是我再项目中做的一些处理
    */
    const { params } = getCurrentInstance().router;
    const {
      title,
      iconSize = height / 1.8,
      hideBtns,
      hideHome
    } = this.props;

    return (
      <View
        className="global-navbar"
        style={{
          height: `${navBarHeight}px`,
          paddingTop: `${statusBarHeight}px`
        }}
      >
        <View className="g-nav-content">
          {
            !hideBtns && 
            <View
              className="g-nav-c-iconbox"
              style={{
                borderRadius: `${height}px`,
                height: `${height}px`
              }}
            >
              <Image
                className="g-nav-c-icon"
                mode="aspectFit"
                src={require('../../assets/icon/返回.png')}
                style={{
                  height: `${iconSize}px`,
                  width: `${iconSize}px`,
                  transform: `translateX(-1px)`
                }}
                onClick={this.handelBackIcon}
              />
              {
                !hideHome &&
                <>
                  <View className="fw-divider-column" />
                  <Image
                    className="g-nav-c-icon"
                    mode="aspectFit"
                    src={require('../../assets/icon/首页.png')}
                    style={{
                      height: `${iconSize}px`,
                      width: `${iconSize}px`
                    }}
                    onClick={this.handelHomeIcon}
                  />
                </>
              }
            </View>
          }
          <Text
            className={`global-navbar_text ${hideBtns ? 'g-nav-c-title_left' : 'g-nav-c-title_center'}`}
          >
            {title ?? params.pageTitle}
          </Text>
        </View>
      </View>
    )
  }
};

export default NavBar