项目场景(错误示例):

<template>
    ...
    <!-- 服务中心 -->
	<view class="service-option">
		<view class="title">
			<view class="left">
				<text class="tt">服务中心</text>
				<image src="https://www.pengpaicoding.com.cn/static/app/home/title-star.png" class="w-[44rpx] h-[44rpx] tt-bg"></image>
		    </view>
		</view>
		<view class="mt-3">
			<cl-row :gutter="12">
				<template v-for="(e,ei) in services" :key="ei">
					<cl-col :span="6" @click="handelServiceNav(e)">
						<view class="flex justify-center items-center mb-2">
							<cl-image :src="e.icon" width="72rpx" height="72rpx" />
							<text class="text-[#666666] text-[28rpx] mt-1">{{e.label}}</text>
						</view>
					</cl-col>
				</template>
			</cl-row>
		</view>
	</view>
    ...
</template>

// js部分:
/* 服务中心 */
	const servicesBase : ServiceItem[] = [
		{
			label: '用户协议',
			icon: 'https://www.pengpaicoding.com.cn/static/app/user/yhxy.png',
			show: () => true,
			logined: false,
			to: '/pages/article/index',
			params: { code: 'user' }
		},
		{
			label: '隐私协议',
			icon: 'https://www.pengpaicoding.com.cn/static/app/user/ysxy.png',
			show: () => true,
			logined: false,
			to: '/pages/article/index',
			params: { code: 'secret' }
		},
		{
			label: '收货地址',
			icon: 'https://www.pengpaicoding.com.cn/static/app/user/shdz.png',
			show: () => true,
			logined: true,
			to: '/pages/user/address/index'
		},
		{
			label: '联系客服',
			icon: 'https://www.pengpaicoding.com.cn/static/app/user/lxkf.png',
			show: () => true,
			logined: false,
			to: '/pages/user/contact/index'
		},
		{
			label: '医院入驻',
			icon: 'https://www.pengpaicoding.com.cn/static/app/user/yyrz.png',
			show: () => userInfo.value?.userType != '02',
			logined: true,
			to: '/pages/hospital/apply'
		},
		{
			label: '我的团队',
			icon: 'https://www.pengpaicoding.com.cn/static/app/user/wdtd.png',
			show: () => userInfo.value?.userType == '02',
			logined: true,
			to: '/pages/hospital/teams'
		},
		{
			label: '我的服务',
			icon: 'https://www.pengpaicoding.com.cn/static/app/hospital/my-service.png',
			show: () => userInfo.value?.userType == '02',
			logined: true,
			to: '/pages/hospital/service'
		},
		{
			label: '认证详情',
			icon: 'https://www.pengpaicoding.com.cn/static/app/user/rzxq.png',
			show: () => userInfo.value?.userType == '02',
			logined: true,
			to: ''
		}
	];

原因分析:

在 uni-app x 的 App 端(Android / iOS / 鸿蒙)里,页面是 uvue,运行时是原生渲染,对响应式数据的“读取时机”与 H5 端不同
H5 端仍然走了 Web 渲染,Vue 的响应式系统可以在模板渲染时再去执行 e.show(),此时 userInfo.value 已经拿到;而 App 端在渲染那一帧就把 e.show() 的结果“固化”了,如果当时 userInfo 还是 undefineduserInfo.value?.userType === '02' 就返回 false,于是那几项就被直接移除,后面即使 userInfo 再变成医院用户,也不会重新触发 v-if 的更新。


解决方案:

  1. 先把数据准备好再渲染列表
    在拿到 userInfo 之后再给 services 赋值,或者用一个计算属性包裹 services,确保 userInfo 已经就绪。

    // 伪代码
    const services = computed<ServiceItem[]>(() => {
      if (!userInfo.value) return []          // 没拿到用户信息先不渲染
      return [
        ... // 这里放原来的数组
      ]
    })
    
  2. 强制重新渲染
    如果仍想保留“先渲染后拿数据”的写法,可以在拿到 userInfo 后给 <cl-row> 加一个 v-if 或 :key,让它整行重新挂载,从而再次执行 e.show()

    <cl-row :gutter="12" v-if="userInfo">
      ...
    </cl-row>
    
  3. 把 show 改成普通布尔值
    把 show: () => userInfo.value?.userType === '02' 改成在拿到 userInfo 后手动算出的布尔值,也能避免函数在渲染时被提前执行。

    const services = computed(() => {
      const isHospital = userInfo.value?.userType === '02'
      return [
        { label: '我的团队', show: isHospital, ... },
        ...
      ]
    })
Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐