uni-app框架 微信小程序页面显示正常,但安卓页面样式显示异常

问题

今天在继续复习uni-app项目时,使用模拟器运行时,突然发现封装的search组件样式无法正常显示,但是小程序页面又是正常的,打包后真机也是一样的结果。在uni-app的控制台报如下错误:
[Vue warn]: Error in render: “TypeError: Cannot read property ‘children’ of undefined”
TypeError: Cannot read property ‘children’ of undefined

问题截图

小程序界面搜索样式正常

安卓界面运行异常
在这里插入图片描述

问题分析

这是分类页面中的源码,其中my-search组件即为上方图中的固定定位搜索框

<template>
  <view>
    <my-search ></my-search>
    <view class="scrollContainer" >
      <scroll-view scroll-y="true" class="leftScrollContainer" :style="{height: scrollHeight + 'px' }" :scroll-top="leftScrollTop"> 
        <view :class="'firstCateItem ' + (index===currentSelectedIndex? 'active' :'') " v-for="(item1,index) in cateList" :key="index" @click="changeSelectedIndex(index)">
          {{item1.cat_name}}
        </view>
      </scroll-view>
    <scroll-view scroll-y="true" class="rightScrollContainer" :style="{height: scrollHeight + 'px'}" :scroll-top="rightScrollTop">
        <view class="childCateContainer" v-for="(item2,index2) in cateList[currentSelectedIndex].children " :key="index2">
          <view>
           <text class="secondCate">/ {{item2.cat_name}} /</text>
        <view class="thirdCateContainer" >
             <view class="thirdCateItem" v-for="(item3,index3) in item2.children" :key="index3" @click="goToGoodList(item3)">
               <image :src="item3.cat_icon" mode=""></image>
               <text>{{item3.cat_name}}</text>
             </view>
           </view>
          </view>
        </view>
      </scroll-view>
    </view>
  </view>
</template>
<script>
import bus from "@/utils/bus";
  export default {
    data() {
      return {
        scrollHeight:'',
        cateList:[],
        currentSelectedIndex:0,
        rightScrollTop:0,
        leftScrollTop:0,
      };
    },
    created(){
      bus.on('resetScroll', () => {
        this.currentSelectedIndex = 0
        this.leftScrollTop = this.leftScrollTop ? 0 : 1
        this.rightScrollTop = this.rightScrollTop === 0 ? 1 : 0
      })
    },
    onUnload: () => {
      bus.off('resetScroll')
    },
    onLoad() {
      this.getViewUsedHeight()
      this.getCateList()
      console.log("哈哈哈",this.cateList);
    },
    methods:{
      goToGoodList(item3){
        console.log(item3);
        uni.navigateTo({
          url:'/subpkg/goods_list/goods_list?cid=' + item3.cat_id
        })
      },
      changeSelectedIndex(index){
        this.currentSelectedIndex = index
        // this.secondCateList = this.cateList[index].children
        this.rightScrollTop = this.rightScrollTop === 0 ? 1 : 0
      },
      getViewUsedHeight(){
        uni.getSystemInfo({
          success: (res) => {
            console.log("这是获取到的设备信息:",res);
            if(res.errMsg === "getSystemInfo:ok" && res.windowHeight){
              uni.$showMsg("窗口可用高度为"+res.windowHeight)
              this.scrollHeight = res.windowHeight - 60
            }else{
              return uni.$showMsg("获取当前屏幕高度失败!")
            }
          },fail: (err) => {
            console.log("获取屏幕高度失败,信息为:",err);
          }
        })
      },
      async getCateList(){
        const {data:res} = await uni.$http.get('/api/public/v1/categories')
        console.log("这是获取到的分类数据:",res);
        if(res.meta.status !== 200) return uni.$showMsg("没有成功获取到分类数据!")
        this.cateList = res.message
        console.log("获取分类的请求已经结束了!!!");
        // this.secondCateList = this.cateList[0].children
        console.log(this.cateList);
      }
    }
  }
</script>

在控制台中报了这样的错误:

[Vue warn]: Error in render: “TypeError: Cannot read property ‘children’ of undefined”
TypeError: Cannot read property ‘children’ of undefined

之前第一次写的时候也没问题,就没处理,但这次出了问题,只好从这个提示入手。

分析过程:

1.根据提示显然是使用v-for循环页面渲染二级和三级分类使用一级分类cateList对象里面的数据即cateList[currentSelectedIndex].children 时出了问题,但是思考了半天没找到问题所在,我在请求数据的时候就已经将获取到的数据赋值给了data函数中的cateList身上,currentSelectedIndex也在data函数中默认给了定值0。

2.查阅网上资料说是,页面在第一次渲染时数据还没有拿到造成的,使用v-if,判断要渲染的页面数据
是否存在,不存在时不渲染,根据提示我使用了v-if将cateList[currentSelectedIndex].children放在了class="rightScrollContainer"的scroll-view标签上,但是依然无效,报错依旧。

3.后面查阅了项目文档,确实是Vue在第一次渲染页面时拿不到数据导致。于是我修改了使用属性嵌套进行页面渲染的方法,将cateList[currentSelectedIndex].children改为变量名secondCateList声明在data函数中,并在onLoad函数中调用this.getCateList()方法获取分类数据后,将cateList[0].children的值赋值给sendCondList的变量放到页面去渲染,但是报错依旧。

4.后面联想到了Vue的声明周期,并且根据AI的提示,我尝试在onLoad函数中打印请求返回的数据this.cateList值的情况,主要源码和运行截图如下:

    onLoad() {
      this.getViewUsedHeight()
      this.getCateList()
      console.log("这是onLoad函数中当前this.cateList的值:",this.cateList);
    },
    async getCateList(){
        const {data:res} = await uni.$http.get('/api/public/v1/categories')
        console.log("这是获取到的分类数据:",res);
        if(res.meta.status !== 200) return uni.$showMsg("没有成功获取到分类数据!")
        this.cateList = res.message
        console.log("获取分类的请求已经结束了!!!");
      }

在这里插入图片描述
可以看到,在onLoad函数中的请求方法this.getCateList()运行结束之前,onLoad函数体中的最后一行打印语句就已经执行了,这也解释了为什么我在请求函数"结束"之后修改值依然无效,页面渲染报前面提到的错的原因。

解决方法:

知道了原因,我们就可以将二级分类数据secondCateList声明在computed之中,并且使用三元表达式判断它的值是否存在,不存在时返回一个空数组,这样Vue在页面首次加载时就不会去渲染了,报错消失后,这个小程序页面样式正常,安卓样式异常的问题就解决了。

修改后的页面源码和运行截图如下:

<template>
  <view>
    <my-search ></my-search>
    <view class="scrollContainer" >
      <scroll-view scroll-y="true" class="leftScrollContainer" :style="{height: scrollHeight + 'px' }" :scroll-top="leftScrollTop"> 
        <view :class="'firstCateItem ' + (index===currentSelectedIndex? 'active' :'') " v-for="(item1,index) in cateList" :key="index" @click="changeSelectedIndex(index)">
          {{item1.cat_name}}
        </view>
      </scroll-view>
    <scroll-view scroll-y="true" class="rightScrollContainer" :style="{height: scrollHeight + 'px'}" :scroll-top="rightScrollTop">
        <view class="childCateContainer" v-for="(item2,index2) in secondCateList " :key="index2">
          <view>
           <text class="secondCate">/ {{item2.cat_name}} /</text>
        <view class="thirdCateContainer" >
             <view class="thirdCateItem" v-for="(item3,index3) in item2.children" :key="index3" @click="goToGoodList(item3)">
               <image :src="item3.cat_icon" mode=""></image>
               <text>{{item3.cat_name}}</text>
             </view>
           </view>
          </view>
        </view>
      </scroll-view>
    </view>
  </view>
</template>

<script>
import bus from "@/utils/bus";
  export default {
    data() {
      return {
        scrollHeight:'',
        cateList:[],
        currentSelectedIndex:0,
        rightScrollTop:0,
        leftScrollTop:0,
      };
    },
    computed:{
      secondCateList(){
        //必须要设置一个空数组,在第一次渲染的时候,this.cateList是没有的,再调用它的子属性children会报错,虽然小程序不影响结果,但是安卓上会导致页面样式渲染出现异常
        return this.cateList[this.currentSelectedIndex] ? this.cateList[this.currentSelectedIndex].children : []
      }
    },
    created(){
      bus.on('resetScroll', () => {
        this.currentSelectedIndex = 0
        this.leftScrollTop = this.leftScrollTop ? 0 : 1
        this.rightScrollTop = this.rightScrollTop === 0 ? 1 : 0
      })
    },
    onUnload: () => {
      bus.off('resetScroll')
    },
    onLoad() {
      this.getViewUsedHeight()
      this.getCateList()
      console.log("这是onLoad函数中当前this.cateList的值:",this.cateList);
    },
    methods:{
      goToGoodList(item3){
        console.log(item3);
        uni.navigateTo({
          url:'/subpkg/goods_list/goods_list?cid=' + item3.cat_id
        })
      },
      changeSelectedIndex(index){
        this.currentSelectedIndex = index
        // this.secondCateList = this.cateList[index].children
        this.rightScrollTop = this.rightScrollTop === 0 ? 1 : 0
      },
      getViewUsedHeight(){
        uni.getSystemInfo({
          success: (res) => {
            console.log("这是获取到的设备信息:",res);
            if(res.errMsg === "getSystemInfo:ok" && res.windowHeight){
              uni.$showMsg("窗口可用高度为"+res.windowHeight)
              this.scrollHeight = res.windowHeight - 60
            }else{
              return uni.$showMsg("获取当前屏幕高度失败!")
            }
          },fail: (err) => {
            console.log("获取屏幕高度失败,信息为:",err);
          }
        })
      },
      async getCateList(){
        const {data:res} = await uni.$http.get('/api/public/v1/categories')
        console.log("这是获取到的分类数据:",res);
        if(res.meta.status !== 200) return uni.$showMsg("没有成功获取到分类数据!")
        this.cateList = res.message
        console.log("获取分类的请求已经结束了!!!");
      }
    }
  }
</script>

在这里插入图片描述

总结
刚学完uni-app时,看到有人说这个框架就是一端运行多端报错还有点怀疑,这下不得不信了。不过也有原因在于我当时没有去处理复杂对象中的嵌套数据在页面渲染错误所导致的,同时也重新认识了下onLoad函数体语句和异步请求方法的执行顺序问题。总而言之,在使用接口返回的复杂数据渲染页面时,优先使用computed计算属性,结合三元表达式去判断要渲染的数据源是否已经存在,不存在应给定空数组或对象,以避免一端运行,多端报错的可能。

  • 17
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: uni-app-template是一款基于uni-app框架建立的通用模板,可以为开发者提供一个基础的项目结构和功能模块,减少开发的时间和工作量。 该模板的优势在于跨平台性能良好,支持同时开发多个平台的应用程序,并且可以达到近乎原生的用户体验。 在使用uni-app-template时,开发者可以选择不同的开发方式,如HBuilder X、VS Code等,也可以选择不同的UI框架和组件库进行二次开发。该模板还提供了常用的API,如ajax、storage、toast、loading等,方便开发者快速构建应用界面。 总之,uni-app-template是一款十分实用的通用模板,开发者可以通过基于此模板的项目,快速开发出高性能、跨平台的应用程序。 ### 回答2: uni-app-template是一个能够快速构建uni-app项目的通用模板。uni-app是一款跨平台开发框架,可以将一份代码同时转化为多个平台的应用程序,如微信小程序App Store和Google Play应用商店,以及各种移动设备。 uni-app-template的特点主要体现在以下几个方面: 1.简单易用 uni-app-template是一个基于uni-app的通用模板,具有简单易用的特点,可以轻松构建平台适配性高、UI风格统一的app。 2.多平台适配 uni-app-template支持多种平台适配,不仅可以生成微信小程序应用,还可以生成iOS和Android应用,无需重新编写代码。因此,采用uni-app-template开发应用程序可以大大提高开发效率和代码复用率。 3.模块化开发 模板支持应用程序的模块化开发,可以将功能实现的代码封装在一个模块中,方便开发者进行管理和维护,并提高代码的可重用性和可维护性。 4.灵活配置 uni-app-template支持灵活配置,可以根据不同的需求选择不同的UI组件、主题颜色、字体、字号等参数,还可以根据具体平台的特点进行适配。 总之,uni-app-template是一个开发者在uni-app框架下快速构建多端应用程序的好选择。借助它,可以迅速构建高效、稳定、具备多端适配能力的app,大大提高开发效率和使用体验。 ### 回答3: Uni-app-template是一种用于uni-app框架的通用模板。uni-app是最近非常受欢迎的移动端应用开发框架,它可以一次编写,多端发布,不仅能够开发微信小程序,还可以开发iOS和安卓应用,还支持H5。 Uni-app-template能够提供一个通用的模板,以便开发者更加高效地完成开发工作。这个模板内置了一些常用的功能,例如页面布局,样式设置,组件引用等。开发者在使用这个模板时,可以根据自己的需要,逐步添加或修改代码,来实现自己的功能。 Uni-app-template中已经内置了很多通用的组件,例如tab栏、navbar、搜索栏等,这些组件可供开发者直接使用,以减少重复开发的工作量。 此外,Uni-app-template还内置了一些常用的插件,例如uni-ui(一个类似于Element UI的移动端UI组件库)、uview(一个为uni-app量身定制的UI库)等,这些插件可以帮助开发者更简单地进行开发工作。 Uni-app-template的另一个优点是它的兼容性。一旦应用开发完成,它将能够直接在各个平台上运行,包括微信小程序、iOS和安卓应用,以及H5网页应用。由于Uni-app框架Uni-app-template具有良好的兼容性,使得开发者的工作更加高效和简单。 总之,Uni-app-template是一个非常实用和方便的开发工具,它能够帮助开发者更加快速、高效地完成应用程序。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值