taro react hooks 小程序自定义头部

446 阅读2分钟

taro react hooks 小程序自定义头部,第一次写,自己记录

  • title: 标题
  • isOccupySpace: 是否占位
  • leftSolt: 左侧solt
  • centerSolt: 中间solt
  • background: 背景色
  • isShowHome: 是否需要回到首页按钮
  • isShowSearch: 是否需要左侧搜索
  • backColor: 返回按钮颜色(黑色false,白色true, 默认false黑色)
  • logoTextWhite: 白色logo
  • logoTextBlack: 黑色logo
  • logoPosition: logo位置(左侧-left,中间-center)
  • getCustomBarHeight: 获取导航高度:function
import React, { ReactNode, useEffect, memo } from 'react';
import { View, Image } from '@tarojs/components';
import { getCurrentPages, getSystemInfoSync, getMenuButtonBoundingClientRect } from '@tarojs/taro';

const { statusBarHeight, windowWidth } = getSystemInfoSync();
const customInfo = getMenuButtonBoundingClientRect();
// 导航高度
const custonBarHeight = (customInfo.top - statusBarHeight) * 2 + customInfo.height + statusBarHeight;
// 左侧区域宽度
const leftWidth = windowWidth - customInfo.left;
// 中心区域宽度
const centerWidth = windowWidth - (windowWidth - customInfo.left) * 2;
const padLeft = windowWidth - customInfo.left - customInfo.width;

interface RenderProps {
  title?: string;
  leftSolt?: ReactNode;
  centerSolt?: ReactNode;
  background?: string;
  isOccupySpace?: boolean;
  isShowHome?: boolean;
  isShowSearch?: boolean;
  backColor?: boolean;
  logoTextWhite?: boolean;
  logoTextBlack?: boolean;
  logoPosition?: 'left' | 'center';
  textColor?: string;
  getCustomBarHeight?: (custonBarHeight: number) => void;
}

const NavBar: React.FC<RenderProps> = ({
  isOccupySpace = true,
  leftSolt,
  centerSolt,
  title = '',
  background = '#fff',
  isShowHome = false,
  isShowSearch = false,
  backColor = false,
  logoTextWhite = false,
  logoTextBlack = false,
  logoPosition = 'center',
  textColor = '',
  getCustomBarHeight,
}) => {
  const pagesLength = getCurrentPages().length;
  const leftArrow = pagesLength > 1;
  useEffect(() => {
    if (typeof getCustomBarHeight === 'function') getCustomBarHeight(custonBarHeight);
  }, []);

  return (
    <>
      <View
        className={`${styles['nav-bar']}  ${styles['nav-bar__fix']}`}
        style={{ paddingTop: `${statusBarHeight}PX`, height: `${custonBarHeight}PX`, background: `${background}` }}
      >
        // 左侧
        <View className={styles['nav-bar-left']} style={{ width: `${leftWidth}PX`, paddingLeft: `${isShowHome && leftArrow ? padLeft + 'PX' : '32rpx'}` }}>
          {leftSolt ||
            (logoTextBlack && logoPosition == 'left' && <LogoTextBarBlack logoPosition={logoPosition} />) ||
            (logoTextWhite && logoPosition == 'left' && <LogoTextBarWhite />) ||
            (isShowSearch && <SearchBar />) ||
            (leftArrow && <LeftArrowBack isShowHome={isShowHome} backColor={backColor} />) || <HomeBar leftArrow={leftArrow} LeftArrowBack={LeftArrowBack} />}
        </View>
        // 中间
        <View className={`${styles['nav-bar-center']} ${textColor === 'white' && styles['white']}`} style={{ width: `${centerWidth}PX` }}>
          {centerSolt ||
            (logoTextBlack && logoPosition == 'center' && <LogoTextBarBlack logoPosition={logoPosition} />) ||
            (logoTextWhite && logoPosition == 'center' && <LogoTextBarWhite />) ||
            title}
        </View>
        // 右侧占位
        <View className={styles['nav-bar-right']} style={{ width: `${leftWidth}PX` }}></View>
      </View>
      // 导航占位
      {isOccupySpace && <View style={{ height: `${custonBarHeight}PX` }}></View>}
    </>
  );
};

export default memo(NavBar);

const LeftArrowBack = ({ isShowHome, backColor }) => {
  return (
    <>
      {isShowHome ? (
        <View className={styles['nav-bar-left__btn']} style={{ height: `${customInfo.height}PX` }}>
          <View className={styles['back_icon']} onClick={() => navigateBack()}>
            <Image mode="widthFix" src={IMG_URL + 'left.svg'} />
          </View>
          <View className={styles['back_line']}></View>
          <View className={styles['back_home']} onClick={() => reLaunch('/pages/index/index')}>
            <Image mode="widthFix" src={IMG_URL + 'home.svg'} />
          </View>
        </View>
      ) : (
        <View className={styles['nav-bar-left__btn__back']} style={{ height: `${customInfo.height}PX` }}>
          <View className={styles['back_icon']} onClick={() => navigateBack()}>
            <Image className={styles['back_icon-img']} mode="widthFix" src={IMG_URL + `${backColor ? 'left_white.svg' : 'left.svg'}`} />
          </View>
        </View>
      )}
    </>
  );
};

const HomeBar = ({ leftArrow, LeftArrowBack }) => {
  return (
    <>
      {leftArrow ? (
        <LeftArrowBack />
      ) : (
        <View className={styles['nav-bar-left__btn__search']} onClick={() => reLaunch('/pages/index/index')}>
          <View className={styles['search_icon']}>
            <Image mode="widthFix" src={IMG_URL + 'home.svg'} />
          </View>
        </View>
      )}
    </>
  );
};

const SearchBar = () => {
  return (
    <View className={styles['nav-bar-left__btn__search']} onClick={() =>{}}>
      <View className={styles['search_icon']}>
        <Image mode="widthFix" src='search.svg'} />
      </View>
    </View>
  );
};

const LogoTextBarWhite = () => {
  return (
    <View className={styles['nav-logo']}>
      <View className={styles['logo_icon']} onClick={() =>{}}>
        <Image mode="widthFix" src='logo-white.svg' />
      </View>
    </View>
  );
};

const LogoTextBarBlack = ({ logoPosition }) => {
  return (
    <View className={styles['nav-logo']} onClick={() =>{}}>
      <View className={`${styles['logo_icon']} ${logoPosition === 'left' && styles['logo-left']}}`}>
        <Image mode="widthFix" src="" />
      </View>
    </View>
  );
};

css
.nav-bar {
  display: flex;
  align-items: center;
  flex-shrink: 0;

  &.nav-bar__fix {
    position: fixed;
    width: 100vw;
    left: 0;
    top: 0;
    z-index: 9;
  }

  &-left {
    width: 25%;
    display: flex;
    align-items: center;

    &__btn {
      width: 174rpx;
      height: 64rpx;
      display: flex;
      align-items: center;
      justify-content: center;
      border-radius: 64rpx;
      border: 1PX solid rgba(151, 151, 151, 0.201002);
      .back_icon{
        width: 40rpx;
        height: 40rpx;
      }
      .back_line{
        background: rgba(0, 0, 0, 0.198907);
        width: 1PX;
        height: 36rpx;
        margin: 0 18rpx;
      }
      .back_home{
        width: 40rpx;
        height: 40rpx;
      }
    }
    .nav-bar-left__btn__search{
      background: rgba(255, 255, 255, 0.3);
      border: 1PX solid rgba(151, 151, 151, 0.201002);
      width: 64rpx;
      height: 64rpx;
      border-radius: 50%;
      display: flex;
      align-items: center;
      justify-content: center;
      .search_icon{
        width: 36rpx;
      }
    }
    .nav-bar-left__btn__back{
      width: 64rpx;
      height: 64rpx;
      border-radius: 64rpx;
      border: 1PX solid rgba(151, 151, 151, 0.201002);
      display: flex;
      align-items: center;
      justify-content: center;
      .back_icon{
        width: 40rpx;
        height: 40rpx;
        .back_icon-img{
          margin-left: -2rpx;
        }
      }
    }
  }
  &-left-home {
    width: 122rpx;;
    display: flex;
    align-items: center;

    &__btn {
      width: 84rpx;
      display: flex;
      align-items: center;
      justify-content: center;
    }
  }

  .nav-logo{
    .logo_icon{
      width: 172rpx;
    }
    .logo-left {
      width: 142rpx;
    }
  }
  &-center {
    width: 50%;
    text-align: center;
    color: #000;
    font-weight: 500;
    font-size: 36rpx;
    display: flex;
    align-items: center;
    justify-content: center;
    &.white {
      color: #fff;
    }
  }
  &-center-home {
    flex:1;
    text-align: center;
    color: #fff;
    font-weight: 500;
    font-size: 32rpx;
  }

  &-right {
    width: 25%;
  }
}