您现在的位置是:首页 > 编程语言学习 > 其他编程语言 > 文章正文 其他编程语言

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

2022-10-09 10:01:31 其他编程语言

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

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

1. page的样式

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

2. onPageScroll

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

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

  1. data() { 
  2.   return { 
  3. pageScrollTop: 0, 
  4.   }; 
  5. }, 
  6. onPageScroll({ scrollTop }) { 
  7.   this.pageScrollTop = scrollTop || 0; 
  8. }, 

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

解决方法有多个:

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

3. 性能问题

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

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

4. 方案

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

  • mixin中,监听 onPageScroll,因为这个在只会在当前页面触发,子组件会被忽略,所以写在这里并不影响性能。

  • vuex 中保存 pageScrollTop、mpHeaderHeight,及一个衍生变量 mpHeaderBg。

  • 然后,需要使用 mpHeaderBg 的页面,去引用 vuex 中的变量。

  • 如果想要在一个新页面加上渐变导航,只需要引用 vuex 中的 mpHeaderBg 即可。

5. 代码

  1. // 某个页面 
  2. <template> 
  3.   <MatchHeaderMp 
  4. :header-bg="mpHeaderBg" 
  5.   /> 
  6. </template> 
  7. <script> 
  8. computed: { 
  9.   mpHeaderBg() { 
  10. // getMpHeaderBg 方法来自于 mixin 
  11. return this.getMpHeaderBg(); 
  12.   }, 
  13. </script> 
  14. // mixin 
  15. export const uniSystemInfoMixin = { 
  16.   data() { 
  17. return { 
  18.   // page-meta上设置的根标签字体大小 
  19.   mixinRootFontSize: 50, 
  20. }; 
  21.   }, 
  22.   mounted() { 
  23. // 设置根字体大小 
  24. this.onSetFontSize(); 
  25.   }, 
  26.   onPageScroll({ scrollTop }) { 
  27. const mpHeaderHeight = this.$store.state.wxHeader.mpHeaderHeight || 44; 
  28. const pageScrollTop =  this.$store.getters.['wxHeader/pageScrollTop'] || 44; 
  29. const parsedScrollTop = scrollTop > mpHeaderHeight ? mpHeaderHeight : scrollTop; 
  30.  
  31. // 如果滑动值大于 mpHeaderHeight,就不再更新 data 
  32. if (parsedScrollTop === mpHeaderHeight && pageScrollTop === mpHeaderHeight) { 
  33.   return
  34. this.$store.commit('wxHeader/setPageScrollTop', parsedScrollTop); 
  35.   }, 
  36.   beforeDestroy() { 
  37. if (this.mpType === 'page') { 
  38.   this.$store.commit('wxHeader/setPageScrollTop', 0); 
  39.   }, 
  40.   methods: { 
  41. getMpHeaderBg() { 
  42.   const pageScrollTop = this.getMpPageScrollTop(); 
  43.   const mpHeaderHeight = this.$store.state.wxHeader.mpHeaderHeight || 44; 
  44.   return `rgba(255, 255, 255, ${Math.min(1, pageScrollTop / mpHeaderHeight)})`; 
  45. }, 
  46. getMpPageScrollTop() { 
  47.   const curPageName = this.getCurPageName(); 
  48.   const pageScrollTopMap = this.$store.state.wxHeader.pageScrollTopMap || {}; 
  49.   return pageScrollTopMap[curPageName] || 0; 
  50. }, 
  51. getCurPageName() { 
  52.   const pages = getCurrentPages(); 
  53.   return pages[pages.length - 1].route; 
  54. }, 
  55. onSetFontSize() { 
  56.   // 宽度 375 时(iphone6),rootFontSize为50,则一份为 375/50=7.5 
  57.   const screenNumber = 7.5; 
  58.   const that = this ; 
  59.  
  60.   if (that.mpType === 'page') { 
  61. // 窗体改变大小触发事件 
  62. uni.onWindowResize((res) => { 
  63.   if (res.size.windowWidth) { 
  64. that.mixinRootFontSize = parseFloat(res.size.windowWidth) / screenNumber; 
  65.   } 
  66. }); 
  67.  
  68. // 打开获取屏幕大小 
  69. uni.getSystemInfo({ 
  70.   success(res) { 
  71. const fontsize = res.screenWidth / screenNumber; 
  72. that.mixinRootFontSize = fontsize; 
  73. const mpHeaderHeight = res.statusBarHeight + 44; 
  74. that.$store.commit('wxHeader/setMpHeaderHeight', mpHeaderHeight); 
  75.   }, 
  76. }); 
  77. }, 
  78.   }, 
  79. }; 
  80. // store/modules/wx-header.js 
  81. const wxHeaderStore = { 
  82.   namespaced: true
  83.   state: () => ({ 
  84. // 存放多个页面的pageScrollTop 
  85. pageScrollTopMap: {}, 
  86. // 状态栏高度 
  87. mpHeaderHeight: 44, 
  88.   }), 
  89.   mutations: { 
  90. setPageScrollTop(state, pageScrollTop = 0) { 
  91.   const curPageName = getCurPageName(); 
  92.   state.pageScrollTopMap = { 
  93. ...state.pageScrollTopMap, 
  94. [curPageName]: pageScrollTop, 
  95.   }; 
  96. }, 
  97. setMpHeaderHeight(state, mpHeaderHeight) { 
  98.   state.mpHeaderHeight = mpHeaderHeight; 
  99. }, 
  100.   }, 
  101. }; 

6. 注意事项

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

相关文章

站点信息