uniapp再次封装uni-nav-bar导航栏组件

news2025/3/29 3:06:39
<!-- components/custom-nav-bar/custom-nav-bar.vue -->
<template>
  <view class="custom-nav" :style="{ backgroundColor: bgColor }">
    <!-- 状态栏占位 -->
    <view class="status-bar" :style="{ height: statusBarHeight + 'px' }"></view>
    
    <!-- 导航栏内容区 -->
    <view class="nav-content" :style="navContentStyle">
      <view class="nav-left" @click="onClickLeft">
        <slot name="left">
          <view v-if="leftIcon" class="left-icon">
            <uni-icons :type="leftIcon" size="20" color="#333"></uni-icons>
          </view>
        </slot>
      </view>
      
      <view class="nav-center">
        <slot name="center">
          <text class="nav-title" :style="{ color: titleColor }">{{ title }}</text>
        </slot>
      </view>
      
      <view class="nav-right">
        <slot name="right">
          <view v-if="rightIcon" class="right-icon" @click="onClickRight">
            <uni-icons :type="rightIcon" size="20" color="#333"></uni-icons>
          </view>
        </slot>
      </view>
    </view>
  </view>
  
  <!-- 占位,防止内容被遮挡 -->
  <view v-if="fixed" class="nav-placeholder" :style="placeholderStyle"></view>
</template>

<script>
export default {
  name: 'CustomNavBar',
  props: {
    // 标题
    title: {
      type: String,
      default: ''
    },
    // 标题颜色
    titleColor: {
      type: String,
      default: '#333333'
    },
    // 左侧图标
    leftIcon: {
      type: String,
      default: 'left'
    },
    // 右侧图标
    rightIcon: {
      type: String,
      default: ''
    },
    // 背景颜色
    bgColor: {
      type: String,
      default: '#FFFFFF'
    },
    // 是否固定在顶部
    fixed: {
      type: Boolean,
      default: true
    }
  },
  
  data() {
    return {
      statusBarHeight: 0, // 状态栏高度
      navBarHeight: 44, // 导航栏高度
      menuButtonInfo: null // 胶囊按钮信息
    }
  },
  
  computed: {
    // 导航栏内容样式
    navContentStyle() {
      let style = {
        height: this.navBarHeight + 'px'
      }
      
      // #ifdef MP-WEIXIN
      if (this.menuButtonInfo) {
        style = {
          ...style,
          height: (this.menuButtonInfo.height + 8) + 'px',
          paddingTop: (this.menuButtonInfo.top - this.statusBarHeight) + 'px',
          paddingRight: (this.systemInfo.windowWidth - this.menuButtonInfo.left) + 'px'
        }
      }
      // #endif
      
      return style
    },
    
    // 占位符样式
    placeholderStyle() {
      return {
        height: (this.statusBarHeight + this.navBarHeight) + 'px'
      }
    }
  },
  
  created() {
    this.initNavBar()
  },
  
  methods: {
    // 初始化导航栏
    initNavBar() {
      // 获取系统信息
      const systemInfo = uni.getSystemInfoSync()
      this.systemInfo = systemInfo
      this.statusBarHeight = systemInfo.statusBarHeight
      
      // #ifdef MP-WEIXIN
      // 获取胶囊按钮信息
      this.menuButtonInfo = uni.getMenuButtonBoundingClientRect()
      this.navBarHeight = (this.menuButtonInfo.height + 8)
      // #endif
      
      // #ifdef APP-PLUS
      // 判断是否是全面屏
      const isIphoneX = this.isIphoneX(systemInfo)
      if (isIphoneX) {
        this.navBarHeight = 48
      }
      // #endif
    },
    
    // 判断是否是全面屏
    isIphoneX(systemInfo) {
      const model = systemInfo.model.toLowerCase()
      const isIphoneX = model.includes('iphone x') || 
                       model.includes('iphone 11') ||
                       model.includes('iphone 12') ||
                       model.includes('iphone 13') ||
                       model.includes('iphone 14') ||
                       model.includes('iphone 15')
      return isIphoneX
    },
    
    // 左侧点击事件
    onClickLeft() {
      this.$emit('clickLeft')
    },
    
    // 右侧点击事件
    onClickRight() {
      this.$emit('clickRight')
    }
  }
}
</script>

<style lang="scss">
.custom-nav {
  position: relative;
  
  &.fixed {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    z-index: 999;
  }
}

.status-bar {
  width: 100%;
}

.nav-content {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 15px;
  box-sizing: border-box;
  
  .nav-left, .nav-right {
    min-width: 44px;
    height: 100%;
    display: flex;
    align-items: center;
  }
  
  .nav-center {
    flex: 1;
    text-align: center;
    
    .nav-title {
      font-size: 16px;
      font-weight: 500;
    }
  }
  
  .left-icon, .right-icon {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 44px;
    height: 100%;
  }
}

/* #ifdef MP-WEIXIN */
.custom-nav {
  padding-right: var(--window-right, 0);
  
  .nav-content {
    .nav-left {
      padding-left: 10px;
    }
    
    .nav-right {
      padding-right: 10px;
    }
  }
}
/* #endif */

/* #ifdef APP-PLUS */
.custom-nav {
  .nav-content {
    padding: 0 12px;
  }
}
/* #endif */
</style>

使用示例

<!-- pages/index/index.vue -->
<template>
  <view class="page">
    <!-- 基础用法 -->
    <custom-nav-bar 
      title="页面标题"
      @clickLeft="handleBack"
    />
    
    <!-- 自定义样式 -->
    <custom-nav-bar 
      title="自定义导航栏"
      titleColor="#FFFFFF"
      bgColor="#007AFF"
      rightIcon="more"
      @clickLeft="handleBack"
      @clickRight="handleMore"
    />
    
    <!-- 自定义内容 -->
    <custom-nav-bar>
      <template #left>
        <view class="custom-left">返回</view>
      </template>
      
      <template #center>
        <view class="custom-center">
          <image src="/static/logo.png" mode="aspectFit" />
        </view>
      </template>
      
      <template #right>
        <view class="custom-right">
          <button size="mini">操作</button>
        </view>
      </template>
    </custom-nav-bar>
    
    <!-- 页面内容 -->
    <view class="content">
      页面内容
    </view>
  </view>
</template>

<script>
export default {
  methods: {
    handleBack() {
      uni.navigateBack({
        delta: 1
      })
    },
    
    handleMore() {
      uni.showToast({
        title: '点击了更多'
      })
    }
  }
}
</script>

<style lang="scss">
.page {
  min-height: 100vh;
  background-color: #f5f5f5;
}

.content {
  padding: 15px;
}

.custom-left {
  font-size: 14px;
  color: #333;
}

.custom-center {
  height: 30px;
  
  image {
    height: 100%;
    width: auto;
  }
}

.custom-right {
  button {
    margin: 0;
  }
}
</style>

组件的主要特点:

  1. 自适应状态栏高度
  1. 支持自定义标题、图标和颜色
  1. 支持自定义左中右三个插槽
  1. 适配微信小程序胶囊按钮
  1. 适配 iPhone 全面屏
  1. 支持固定顶部

使用方法:

  1. 将组件文件放入项目的 components 目录
  2. 在页面中引入并注册组件

    本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2322124.html

    如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

    相关文章

    【STM32】知识点介绍二:GPIO引脚介绍

    文章目录 一、概述二、GPIO的工作模式三、寄存器编程 一、概述 GPIO&#xff08;英语&#xff1a;General-purpose input/output&#xff09;,即通用I/O(输入/输出)端口&#xff0c;是STM32可控制的引脚。STM32芯片的GPIO引脚与外部设备连接起来&#xff0c;可实现与外部通讯、…

    【AI】NLP

    不定期更新&#xff0c;建议关注收藏点赞。 目录 transformer大语言模型Google Gemma疫情网民情绪识别 整体框架 baseline构建 模型调参、模型优化、其他模型 数据trick、指标优化、magic feature 数据增强、伪标签、迁移学习 模型融合sklearn中TFIDF参数详解 频率阈值可以去掉…

    Go 代理爬虫

    现在注册&#xff0c;还送15美金注册奖励金 --- 亮数据-网络IP代理及全网数据一站式服务商 使用代理服务器&#xff0c;通过 Colly、Goquery、Selenium 进行网络爬虫的基础示例程序 本仓库包含两个分支&#xff1a; basic 分支包含供 Go Proxy Servers 这篇文章改动的基础代码…

    【NLP 43、大模型技术发展】

    目录 一、ELMo 2018 训练目标 二、GPT-1 2018 训练目标 三、BERT 2018 训练目标 四、Ernie —— baidu 2019 五、Ernie —— Tsinghua 2019 六、GPT-2 2019 七、UNILM 2019 八、Transformer - XL & XLNet 2019 1.模型结构 Ⅰ、循环机制 Recurrence Mechanism Ⅱ、相对位置…

    在普通用户下修改root用户密码

    1 从普通用户切换到root用户 sudo -s 再输入密码。 2 输入passwd ,会提醒你输入当前用户密码&#xff0c;验证后会提醒你输入root用户密码。 3 切换到root用户&#xff0c;使用修改过的密码登陆。 4 成功进入root用户。

    SPPAS安装及问题汇总

    SPPAS下载地址 文件找不到&#xff0c;可能是MAC的自动化操作问题&#xff0c;解决方案有二&#xff1a; 方案一&#xff1a; 直接查看SPPAS中的readme&#xff0c;运行sppas.command 方案二&#xff1a; 在自动化脚本中添加 export PATH/usr/local/bin:$PATH

    LINUX基础 [三] - 进程创建

    目录 前言 进程创建的初次了解&#xff08;创建进程的原理&#xff09; 什么是fork函数&#xff1f; 初识fork函数 写时拷贝 fork函数存在的意义 fork调用失败的原因 进程终止 运行完毕结果不正确 main函数返回 库函数函数exit 系统调用接口_exit 进程异常终止 进…

    【day1】数据结构刷题 链表

    一 反转链表 206. 反转链表 给你单链表的头节点 head &#xff0c;请你反转链表&#xff0c;并返回反转后的链表。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,4,5] 输出&#xff1a;[5,4,3,2,1]示例 2&#xff1a; 输入&#xff1a;head [1,2] 输出&#xff1a;[2,1]…

    鼠标在客户区内按下左键和双击右键

    书籍&#xff1a;《Visual C 2017从入门到精通》的2.6鼠标 环境&#xff1a;visual studio 2022 内容&#xff1a;【例2.44】鼠标在客户区内按下左键和双击右键 1.创建一个单文档程序 一个简单的单文档程序-CSDN博客https://blog.csdn.net/qq_20725221/article/details/1463…

    c++ map和vector模板类

    在这一章中C语法之模板函数和模板类-CSDN博客 我们学习了怎样写模板函数和模板类&#xff0c;接下来我们来学习系统给我们写好的两个模板类:map和vector。 我相信有了上文的基础&#xff0c;能帮助我们更好的理解这些模板类。 map和vector 是C STL(标准模板库) 中的一部分&a…

    hn航空app hnairSign unidbg 整合Springboot

    声明: 本文章中所有内容仅供学习交流使用&#xff0c;不用于其他任何目的&#xff0c;抓包内容、敏感网址、数据接口等均已做脱敏处理&#xff0c;严禁用于商业用途和非法用途&#xff0c;否则由此产生的一切后果均与作者无关&#xff01; 逆向分析 学习unidbg补环境。先弄一个…

    Arm Linux ceres库编译

    由于工作需要&#xff0c;需在国产化系统上编译ceres库&#xff0c;手上有一块树莓派&#xff0c;就在树莓派上面进行测试编译ceres库&#xff0c;总体来说比较顺利。只出现了一点小问题 参考链接&#xff1a; Ceres中文教程-安装 Ceres官方网站&#xff08;英文&#xff09; …

    矩阵补充,最近邻查找

    矩阵补充&#xff0c;最近邻查找 矩阵补充是向量召回最简单的一种方法&#xff0c;现在不常用&#xff0c;学习矩阵补充是为了更好的理解后面学到的双塔模型 下图&#xff0c;输入用户ID和物品ID后从Eebedding层拿到对应的向量做内积&#xff0c;内积的结果就是矩阵补充 模型…

    gradio调用多个CSS的HTML页

    很多博客介绍的gradio读取html和css比较简单&#xff0c;如果要做很细致的前端页面优化&#xff0c;比如丰富的响应式的cssjs&#xff0c;至少要有html多个css&#xff0c;是暂不能实现的。bootstrap、font-awesome、jquery等 方案一当然是直接更换htmlcss为主的部署方式&#…

    NVIDIA NeMo 全面教程:从入门到精通

    NVIDIA NeMo 全面教程&#xff1a;从入门到精通 文章目录 NVIDIA NeMo 全面教程&#xff1a;从入门到精通目录框架介绍NeMo的核心特点NeMo的架构NeMo与其他框架的比较NeMo的模型集合NeMo的工作流程NeMo 2.0的新特性 安装指南系统要求使用Docker容器安装步骤1&#xff1a;安装Do…

    Thales靶机攻略

    1.下载导入VBox&#xff0c;并启动靶机 靶机地址&#xff1a;https://download.vulnhub.com/thales/Thales.zip 解压后&#xff0c;在VBox中导入虚拟电脑。包含所有网卡的MAC地址。 导入完成&#xff0c;设置网卡模式为仅主机网络。开启靶机。 kali网卡更改为桥接模式。点击工…

    尝试使用Tauri2+Django+React项目(2)

    前言 尝试使用tauri2DjangoReact的项目-CSDN博客https://blog.csdn.net/qq_63401240/article/details/146403103在前面笔者不知道怎么做&#xff0c;搞了半天 笔者看到官网&#xff0c;原来可以使用二进制文件&#xff0c;好好好 嵌入外部二进制文件 | Taurihttps://v2.taur…

    6.1 模拟专题:LeetCode 1576. 替换所有的问号

    1. 题目链接 LeetCode 1576. 替换所有的问号 2. 题目描述 给定一个仅包含小写字母和问号 ? 的字符串 s&#xff0c;要求将所有 ? 替换为任意小写字母&#xff0c;使得替换后的字符串中 没有相邻的两个字符相同。 示例&#xff1a; 输入&#xff1a;s "?zs" →…

    Linux安装go环境

    安装一个lazydocker&#xff0c;根据文档需要先安装go环境 https://github.com/jesseduffield/lazydocker 官方文档解析 https://go.dev/doc/install 文档内容如下&#xff0c;一共三步 1.删除先前安装的go&#xff0c;解压下载的go压缩包到/usr/local目录 2.添加环境变量&…

    卡特兰数在数据结构上面的运用

    原理 Catalan数是一个数列&#xff0c;其第n项表示n个不同结点可以构成的二叉排序树的数量。Catalan数的第n项公式为&#xff1a; &#xfffc; 其中&#xff0c;&#xfffc;是组合数&#xff0c;表示从2n个元素中选择n个元素的组合数。 Catalan数的原理可以通过以下方式理解&…