在uniapp中实现不同身份用户查看不同 TabBar 和页面内容的解决方案

在开发过程中,我们需要根据不同身份的用户展示不同的页面内容和 TabBar。为了实现这一点,首先我们可以选择使用 uniapp 提供的官方 API 来实现,但是在实践中,我们也可以尝试使用其他方法来优化开发流程和提升灵活性。以下是我的实现过程,从一开始的失败尝试到最终解决方案。


1. 使用官方 API 的解决方案

首先,我考虑使用 uniapp 官方的 API 来为不同身份的用户展示不同的页面内容和 TabBar。通过 uni.switchTabuni.navigateTo 配合 vue 的条件渲染,我们可以根据用户身份来动态切换页面和 TabBar 内容。这个方法是官方推荐的,但它有一定的局限性,特别是在需要灵活展示不同身份用户的页面时,手动切换组件和页面的方式比较繁琐,且不容易维护。


2. 尝试使用 WebView

作为一种更灵活的方案,我尝试使用 uniappWebView 组件来加载不同的页面内容。WebView 可以方便地在同一个应用内展示不同的网页内容,并且支持跨平台兼容。

<template>
  <view>
    <web-view :src="webviewUrl"></web-view>
  </view>
</template>

<script setup>
  const webviewUrl = 'https://example.com/page'
</script>

但是,使用 WebView 过程中遇到了问题:页面加载速度慢,并且对于不同身份的用户,WebView 的内容不能很好地与本地组件进行交互,导致用户体验较差。因此,WebView 解决方案并没有达到预期的效果。

失败原因:

  • WebView 的加载速度较慢,特别是在移动端。
  • 无法直接与 uniapp 页面中的本地组件进行交互。
  • 对于不同身份的用户动态展示内容时,难以高效地管理页面和 TabBar 的切换。

3. 尝试使用动态组件引入

在尝试了 WebView 后,我决定改用动态组件的方式加载页面内容。动态组件可以通过 vue<component :is="..."> 来动态切换显示不同的页面组件。

为了实现动态加载组件,我创建了一个 pageList 数组,并用箭头函数将每个页面组件传入。初步代码如下:

<template>
  <view>
    <component :is="pageList[value].page" />
    <uv-tabbar :value="value" :fixed="true" @change="change" :border="false">
      <uv-tabbar-item text="首页" icon="home"></uv-tabbar-item>
      <uv-tabbar-item text="我的" icon="account"></uv-tabbar-item>
    </uv-tabbar>
  </view>
</template>

<script setup>
  import homeVue from '../home/home.vue'
  import mineVue from '../mine/mine.vue'

  const value = ref(0)
  const pageList = ref([
    { icon: 'home', title: '首页', page: () => homeVue },
    { icon: 'account', title: '我的', page: () => mineVue }
  ])

  const change = (index) => {
    value.value = index
  }
</script>

报错原因:

当我运行这段代码时,Vue 报错了,提示:

[Vue warn]: Invalid VNode type: undefined (undefined)

这个错误出现在 <component :is="pageList[value].page" /> 这一行。原因是 Vue 期望 pageList[value].page 是一个有效的组件对象,但由于我用箭头函数 (() => homeVue) 返回了一个组件对象,Vue 无法正确解析这个动态组件,导致了错误。

4. 修正组件引入响应式问题

在分析了报错原因后,我发现是因为 pageList 数组中的组件被放入了 ref 中,Vue 会将其变为响应式对象。homeVuemineVue 组件不应该被标记为响应式,因为它们不需要在运行时发生变化。

解决方案:

我使用了 Vue 的 markRaw 来避免 Vue 对组件进行响应式处理。markRaw 是 Vue 提供的一个 API,用于标记对象为非响应式对象,这样 Vue 在处理这些组件时不会进行额外的响应式转换,避免了性能问题。

修改后的代码如下:

import { markRaw } from 'vue'
import homeVue from '../home/home.vue'
import mineVue from '../mine/mine.vue'

const pageList = ref([
  { icon: 'home', title: '首页', page: markRaw(homeVue) },
  { icon: 'account', title: '我的', page: markRaw(mineVue) }
])

报错原因:

原来的报错是因为 ref 会使传入的对象变为响应式,Vue 会在渲染时期重新解析这些组件。为了解决这个问题,我们使用 markRaw 来标记组件,确保它们不被 Vue 的响应式系统所处理,从而避免不必要的性能开销。


5. 成功实现解决方案

通过使用 markRaw,我成功避免了性能开销,并且动态加载页面组件的功能得以实现。最终的代码如下:

<template>
  <view>
    <component :is="pageList[value].page" />
    <uv-tabbar :value="value" :fixed="true" @change="change" :border="false">
      <uv-tabbar-item text="首页" icon="home"></uv-tabbar-item>
      <uv-tabbar-item text="我的" icon="account"></uv-tabbar-item>
    </uv-tabbar>
  </view>
</template>

<script setup>
  import { markRaw, ref } from 'vue'
  import homeVue from '../home/home.vue'
  import mineVue from '../mine/mine.vue'

  const value = ref(0)
  const pageList = ref([
    { icon: 'home', title: '首页', page: markRaw(homeVue) },
    { icon: 'account', title: '我的', page: markRaw(mineVue) }
  ])

  const change = (index) => {
    value.value = index
  }
</script>

<style>
/* 根据需求添加样式 */
</style>

6. 总结

在本次开发过程中,我遇到的主要问题是如何根据不同身份用户展示不同的 TabBar 和页面内容。虽然使用 uniapp 官方 API 是一种简单的解决方案,但当需要动态加载和切换多个组件时,代码会变得冗长且难以维护。

我尝试了 WebView 和动态组件加载,前者由于性能和交互问题无法满足需求,后者在引入组件时出现了响应式报错。通过合理使用 markRaw 来优化组件加载,我成功实现了在同一页面内根据选中的 Tab 动态切换页面内容,避免了冗长的代码和不必要的性能开销。

亮点总结

  1. 动态组件加载:
    通过 Vue 的 <component :is="..."> 标签动态加载不同的页面组件,避免了为每个 Tab 写重复的组件引入代码。这种方式不仅简洁,而且非常灵活,适用于需要根据不同身份展示不同内容的场景。

  2. 优化性能:
    在动态加载组件时,通过 markRaw 来避免 Vue 自动将组件对象转换为响应式。这不仅避免了性能开销,还减少了不必要的渲染操作,确保页面性能的流畅性和稳定性。

  3. 可维护性和扩展性:
    使用数组 pageList 来管理 Tab 和对应的页面组件,使得代码更加模块化,易于维护和扩展。以后增加新的 Tab 只需要在 pageList 中添加新项,而不需要修改大量的代码。

  4. 避免 WebView 缺陷:
    尝试过使用 WebView,但因为性能和与本地组件的交互问题未能成功。最终通过 Vue 的动态组件方案解决了这一问题,避免了 WebView 的局限性。

  5. 代码简洁且可复用:
    将页面组件和 Tab 内容集中管理,通过动态绑定组件来实现不同用户身份的内容展示。这使得页面内容和 TabBar 的切换更加灵活,减少了重复代码的编写。

  6. 响应式优化:
    通过 markRaw 标记页面组件为非响应式,避免了响应式处理带来的性能问题。这样,组件的渲染更加高效,提升了应用的整体性能。

总结起来,这个解决方案通过动态组件加载和优化 Vue 响应式的方式,在保持代码简洁的同时,确保了高效的性能和良好的用户体验,特别适合需要根据不同身份或条件切换页面内容的应用场景。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值