uni-app小程序沉浸式导航实现的全过程

目录
  • 1. 开始
  • 2. page的样式
  • 3. onPageScroll
  • 4. 性能问题
  • 5. 方案
  • 6. 代码
  • 7. 注意事项
  • 总结

1. 开始

项目要在多个页面上加自定义导航栏,还要有渐变效果,就是随着页面上滑,导航栏透明度由0逐渐变为1。这里面有几个基本点需要注意下。

2. page的样式

page 不能是height: 100%,可以设置height: auto,这样才可以触发 onPageScroll。

3. onPageScroll

只有 page 才有 onPageScroll 事件。试验发现,mixin 和页面内都写了 onPageScroll 的话,都会触发。

如果把它放在 mixin 中,写成下面这样,可能会有问题:

data() {
  return {
    pageScrollTop: 0,
  };
},
onPageScroll({ scrollTop }) {
  this.pageScrollTop = scrollTop || 0;
},

因为自定义导航栏不一定要在页面级组件上,很多页面都是写在子组件里,而 mixin 是各个组件各自维护了一份data,所以无法传递。这也是Vue组件和小程序组件的不同之处。

解决方法有多个:

  • 将 onPageScroll 写在页面级组件上,然后获取到 scrollTop 后传给子组件,这种方法太麻烦
  • onPageScroll 依然写在 mixin 中,保存 scrollTop 到 vuex 的 state 中,然后在页面或者组件中获取这个 state

4. 性能问题

这里面还有两个性能相关的点要注意下:

  • 只有页面级组件或者个别组件需要用的数据,不要放在 mixin 的 data/computed 中。因为 mixin 是所有组件的混入,并且 uni-app 中所有 data 和 computed 都会作为渲染依赖(不管用没用到),可能会引起很多性能开销。
  • onPageScroll 中不要做复杂逻辑,不要频繁调用 setData,在 uni-app 中就是不要频繁更新 data。因为小程序是双线程通信,逻辑层更改数据要先到 native层,再传到渲染层,中间可能还有 JSON.stringify 等操作。

5. 方案

综上,目前采用的方案是:

  • mixin中,监听 onPageScroll,因为这个在只会在当前页面触发,子组件会被忽略,所以写在这里并不影响性能。
  • vuex 中保存 pageScrollTop、mpHeaderHeight,及一个衍生变量 mpHeaderBg。
  • 然后,需要使用 mpHeaderBg 的页面,去引用 vuex 中的变量。
  • 如果想要在一个新页面加上渐变导航,只需要引用 vuex 中的 mpHeaderBg 即可。

6. 代码

// 某个页面
<template>
  <MatchHeaderMp
    :header-bg="mpHeaderBg"
  />
</template>
<script>
computed: {
  mpHeaderBg() {
    // getMpHeaderBg 方法来自于 mixin
    return this.getMpHeaderBg();
  },
}
</script>
// mixin
export const uniSystemInfoMixin = {
  data() {
    return {
      // page-meta上设置的根标签字体大小
      mixinRootFontSize: 50,
    };
  },
  mounted() {
    // 设置根字体大小
    this.onSetFontSize();
  },
  onPageScroll({ scrollTop }) {
    const mpHeaderHeight = this.$store.state.wxHeader.mpHeaderHeight || 44;
    const pageScrollTop =  this.$store.getters.['wxHeader/pageScrollTop'] || 44;
    const parsedScrollTop = scrollTop > mpHeaderHeight ? mpHeaderHeight : scrollTop;

    // 如果滑动值大于 mpHeaderHeight,就不再更新 data
    if (parsedScrollTop === mpHeaderHeight && pageScrollTop === mpHeaderHeight) {
      return;
    }
    this.$store.commit('wxHeader/setPageScrollTop', parsedScrollTop);
  },
  beforeDestroy() {
    if (this.mpType === 'page') {
      this.$store.commit('wxHeader/setPageScrollTop', 0);
    }
  },
  methods: {
    getMpHeaderBg() {
      const pageScrollTop = this.getMpPageScrollTop();
      const mpHeaderHeight = this.$store.state.wxHeader.mpHeaderHeight || 44;
      return `rgba(255, 255, 255, ${Math.min(1, pageScrollTop / mpHeaderHeight)})`;
    },
    getMpPageScrollTop() {
      const curPageName = this.getCurPageName();
      const pageScrollTopMap = this.$store.state.wxHeader.pageScrollTopMap || {};
      return pageScrollTopMap[curPageName] || 0;
    },
    getCurPageName() {
      const pages = getCurrentPages();
      return pages[pages.length - 1].route;
    },
    onSetFontSize() {
      // 宽度 375 时(iphone6),rootFontSize为50,则一份为 375/50=7.5
      const screenNumber = 7.5;
      const that = this ;

      if (that.mpType === 'page') {
        // 窗体改变大小触发事件
        uni.onWindowResize((res) => {
          if (res.size.windowWidth) {
            that.mixinRootFontSize = parseFloat(res.size.windowWidth) / screenNumber;
          }
        });

        // 打开获取屏幕大小
        uni.getSystemInfo({
          success(res) {
            const fontsize = res.screenWidth / screenNumber;
            that.mixinRootFontSize = fontsize;
            const mpHeaderHeight = res.statusBarHeight + 44;
            that.$store.commit('wxHeader/setMpHeaderHeight', mpHeaderHeight);
          },
        });
    }
    },
  },
};
// store/modules/wx-header.js
const wxHeaderStore = {
  namespaced: true,
  state: () => ({
    // 存放多个页面的pageScrollTop
    pageScrollTopMap: {},
    // 状态栏高度
    mpHeaderHeight: 44,
  }),
  mutations: {
    setPageScrollTop(state, pageScrollTop = 0) {
      const curPageName = getCurPageName();
      state.pageScrollTopMap = {
        ...state.pageScrollTopMap,
        [curPageName]: pageScrollTop,
      };
    },
    setMpHeaderHeight(state, mpHeaderHeight) {
      state.mpHeaderHeight = mpHeaderHeight;
    },
  },
};

7. 注意事项

  • 不要多个页面共享同一个变量,会存在多个页面互相影响的可能。
  • 小程序重新进入某个页面,都会重新回到顶部,包括page和所有scroll view,所以要在beforeDestroy中重置pageScrollTop

总结

到此这篇关于uni-app小程序沉浸式导航实现的文章就介绍到这了,更多相关uni-app小程序沉浸式导航内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 如何用uni-app实现顶部导航栏显示按钮和搜索框

    最近公司准备做app,最终决定使用uni-app框架开发,但是当把设计图给我的时候我心里有点没底,因为他的设计图顶部长成这个样子: 因为这个功能在小程序是根本无法实现的,可能受这个影响,我感觉好像实现不了,但是我还是回头看了看文档,才发现,这个功能是可以实现的,只需要在pages.json中做一些配置即可 这个在官方称作app-plus,可以自定义导航区域,具体配置如下: "pages": [ { "path": "pages/index/index&qu

  • uni-app 自定义底部导航栏的实现

    这是我目前发现较好的uni-app 自定义底部导航栏方法,其他方法的缺点主要是在切换时,要么会闪烁,要么会每点击一下,都会请求一次数据.如果有其他更好的方法,欢迎评论留言,最近才开始用uni-app写项目,之前只是看了下文档. 1. tabbar 组件 <template> <view class="tabbar-container"> <view :style="{ color: currentIndex == index ? '#007EFF

  • uni-app自定义导航栏按钮|uniapp仿微信顶部导航条功能

    最近一直在学习uni-app开发,由于uniapp是基于vue.js技术开发的,只要你熟悉vue,基本上很快就能上手了. 在开发中发现uni-app原生导航栏也能实现一些顶部自定义按钮+搜索框,只需在page.json里面做一些配置即可.设置app-plus,配置编译到App平台的特定样式.dcloud平台对app-plus做了详细说明:app-plus配置,需注意 目前暂支持H5.App端,不支持小程序. 在page.json里配置app-plus即可 { "path": "

  • uni-app自定义导航栏右侧做增加按钮并跳转链接功能

    目录 1.先看效果图 2.实现思路 3.pages.json文件中配置 4.page的代码 5.点击按钮后跳转事件 uni-app自定义导航栏右侧做增加按钮并跳转链接 uni-app 在页面上的导航栏右侧做一个增加的图标 并实现跳转 1. 先看效果图 2. 实现思路 使用阿里图标库的字体图标, 下载放入本地文件 pages页面引入即可 这里说一句 uni-app 不支持在线图标 所以需要下载下来 引入到本地项目中 3. pages.json文件中配置 如果是要放在左边 改float : left

  • uni-app小程序沉浸式导航实现的全过程

    目录 1. 开始 2. page的样式 3. onPageScroll 4. 性能问题 5. 方案 6. 代码 7. 注意事项 总结 1. 开始 项目要在多个页面上加自定义导航栏,还要有渐变效果,就是随着页面上滑,导航栏透明度由0逐渐变为1.这里面有几个基本点需要注意下. 2. page的样式 page 不能是height: 100%,可以设置height: auto,这样才可以触发 onPageScroll. 3. onPageScroll 只有 page 才有 onPageScroll 事件

  • 微信小程序MUI侧滑导航菜单示例(Popup弹出式,左侧滑动,右侧不动)

    本文实例讲述了微信小程序MUI侧滑导航菜单.分享给大家供大家参考,具体如下: 实现的目标MUI的off canvas效果 点击列表 -- 右侧展示页面不动,左侧导航滑动 -- 点击右侧遮罩层或者左侧选项 -- 左侧还原,右侧去掉遮罩层 实现方案2:左右分上下两层,左侧滑动,右侧不动 WXML <view class="page"> <view class="page-top {{open ? 'page-top-show' : ''}}">

  • 微信小程序MUI侧滑导航菜单示例(Popup弹出式,左侧不动,右侧滑动)

    本文实例讲述了微信小程序MUI侧滑导航菜单.分享给大家供大家参考,具体如下: 实现的目标--YDUI的Popup组件 点击列表图标--左侧的菜单栏显示--点击关闭按钮或者右侧的遮罩层--左侧菜单栏关闭 实现方案1:左侧菜单和右侧展示页面分为上下两层 wxml <view class="page"> <----下层左侧导航---> <view class="page-bottom"> <view class="pag

  • Android实现沉浸式导航栏实例代码

    废话不多说了,直接给大家贴代码了,具体代码如下所示: private SystemBarTintManager tintManager; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // getWindow().addFlags(WindowManager.Layo

  • 微信小程序中顶部导航栏的实现代码

    微信小程序中顶部导航栏的实现 实例代码: <view class="swiper-tab"> <view class="swiper-tab-list {{currentTab==0 ? 'on' : ''}}" data-current="0" bindtap="swichNav">11</view> <view class="swiper-tab-list {{curre

  • 微信小程序tabBar底部导航中文注解api详解

    微信小程序tabBar底部导航中文注解api,信小程序tabBar就是app底部的那个导航栏,可以放1-5导航链接,这里对微信小程序底部导航tabbar的中文解释. 微信小程序tabBar是在全局app.json文件里面配置的. 小程序tabBar配置代码注解 { "pages":[ "pages/index/index", "pages/detail/detail" ], "window":{ "navigatio

  • 详解微信小程序设置底部导航栏目方法

    详解微信小程序设置底部导航栏目方法 小程序底部想要有一个漂亮的导航栏目,不知道怎么制作,于是百度找到了本篇文章,分享给大家. 好了 小程序的头部标题 设置好了,我们来说说底部导航栏是如何实现的. 我们先来看个效果图 这里,我们添加了三个导航图标,因为我们有三个页面,小程序最多能加5个. 那他们是怎么出现怎么着色的呢?两步就搞定! 1. 图标准备 阿里图标库  http://www.iconfont.cn/collections/show/29 我们进入该网站,鼠标滑到一个喜欢的图标上面  点击下

  • 微信小程序自定义头部导航栏和导航栏背景图片 navigationStyle问题

    这两天因为要做一个带背景的小程序头,哭了,小程序导航栏有背景也就算了,还得让导航栏上的背景顺下来,心态小崩.现在可以单独设置一个页面的小程序头了,但是前提是要微信7.0以上的版本,考虑到兼容性问题,还是不要贸然的上了,所以用老版本的替换所有页面的小程序头来做. ​ 参考了其他篇的文章,但是没有解决自定义背景的和返回按钮的颜色的问题,还有因为IOS的橡皮筋效果,对IOS端不太友好,屏幕会乱划.所以针对性的改动了这些功能,因为才学小程序两三天,所以其中踩了很多坑,但好在最后效果还是达到了. 下面是效

  • 微信小程序自定义底部导航带跳转功能

    本文实例为大家分享了微信小程序实现底部导航带跳转功能的具体代码,供大家参考,具体内容如下 index.wxml <!--底部导航 --> <view class='footer'> <view class='footer_list' data-id='{{index}}' catchtap='Navigation' wx:for="{{listInfo}}" data-current="{{index}}" wx:key="t

  • 微信小程序自定义头部导航栏(组件化)

    本文实例为大家分享了微信小程序自定义头部导航栏的具体代码,供大家参考,具体内容如下 效果图 支持 导航栏自定义背景颜色.背景图片 支持返回文字自定义 支持导航标题自定义 首先在app.json window配置项添加 "window": { "navigationStyle": "custom" } 自定义头部导航栏代码 wxml部分 <view class="cu-custom" style="height:

随机推荐