在项目中,大致代码大概如下:

1、初始化对象:

getCategory().then(res=>{
        // 1.获取分类数据
        this.categories=res.data.category.list
        // 2.初始化每个类别的子数据
        for (let i=0;i<this.categories.length;i++){
          this.categoryData[i]={
            subcategories:{},
            categoryDetail:{
              'pop':[],
              'new':[],
              'sell':[]
            }
          }
        }
        // 3.请求第一个分类的数据
        this._getSubcategories(0)

 2、向对象中添加数据:

getSubcategory(mailKey).then(res=>{
        this.categoryData[index].subcategories=res.data
        this.categoryData={...this.categoryData}
        this._getCategoryDetail(POP)
        this._getCategoryDetail(SELL)
        this._getCategoryDetail(NEW)
      })
_getCategoryDetail(type){
      // 获取请求的minWallKey
      const minWallkey=this.categories[this.currentIndex].miniWallkey
      // 发送请求
      getCategoryDetail(minWallkey,type).then(res=>{
        // 3.将获取的数据保存下来
        this.categoryData[this.currentIndex].categoryDetail[type]=res
        this.categoryData={...this.categoryData}
      })
    }

对于上述添加数据中存在疑惑的地方:即为什么this.categoryData[this.currentIndex].categoryDetail[type]=res中已经改变对象的值,还要采用this.categoryData={...this.categoryData}再进行一次赋值

如果不再进行一次赋值,则在computed中则出现无法获取对象中的数据的错误【即在如下代码中,console.log(this.categoryData), console.log(this.categoryData[this.currentIndex])

中均获取完整数据,而console.log(this.categoryData[this.currentIndex].subcategories)获取数据为空】:

 computed:{
    showSubcategory() {
      if (this.currentIndex===-1) return {}
      // console.log(this.categoryData[this.currentIndex])
      console.log(this.categoryData)
      console.log(this.categoryData[this.currentIndex])
      console.log(this.categoryData[this.currentIndex].subcategories)
      return this.categoryData[this.currentIndex].subcategories
    },
    showCategoryDetail() {
      if (this.currentIndex===-1) return []
      return this.categoryData[this.currentIndex].categoryDetail[this.currentType]
    }
  },

浏览器打印结果如下【因为异步原因,所以初始时subcategories值为空】所示:

原因如下所示:

一、获取数据为空问题

浏览器打印问题,这是console在浏览器的一个问题,简单来说就是chrome在console输出时还是原样,但是展开时却是获取数据后的状态。【如果想要显示当时的信息可以用JSON.stringify(obj)把对象处理成JSON进行输出,就可以看到初始和修改后的】

例子如下所示【JSON例子不做阐述】:

window.onload=function (){
      var obj={
        a:123,
        b:[1,2,3],
        c:{
          name:'',
          age:0
        }
      }
      console.log(obj)
      console.log(obj.b[0])
      console.log(obj.c.age)
      obj.a=333
      obj.b[0]=1111
      obj.c.name='Alice'
      obj.c.age=10
    }

在该例子中浏览器的打印如下所示:

 在打印出来的结果中可以看出,console.log(obj)输出的数组属性和对象属性的值均为修改后的,但是console.log(obj.b[0])和console.log(obj.c.age)获取到的值均为修改前的。【后面发现,浏览器暂停时获取数据准确,一段时间后获取的获取到了异步数据,当我们查看时已经获取到了数据,从而造成一开始查看即是获取到数据后的数组】

由此可以解释项目中的console.log(this.categoryData[this.currentIndex].subcategories)获取数据为空得问题。

二、为什么要采用拓展运算符进行再次赋值

采用拓展运算符进行再次赋值是为了及时改变computed中的showCategoryDetail()和showSubcategory()中获取的值并反馈。

解析如下:

因为计算属性的结果会被缓存,除非依赖的响应式属性变化才会重新计算。注意,如果某个依赖 (比如非响应式属性) 在该实例范畴之外,则计算属性是不会被更新的。

其透露信息如下所示:

  • computed 会搜集并记录依赖。
  • 依赖发生了变化才会重新计算 computed ,由于 computed 是有缓存的,所以当依赖变化之后,第一次访问 computed 属性的时候,才会计算新的值。
  • 只能搜集到响应式属性依赖,无法搜集到非响应式属性依赖。
  • 无法搜集到当前 vm 实例之外的属性依赖。

对于项目中的响应式实现:

1、向响应式的数组或者对象中修改已有的属性的方法,对于在data中声明了的基本数据类型而言,一般都是响应式的。但是对于数组和对象而言,不一定是响应式的。

【原因:Object.defineProperty虽然实现是双向绑定,但是只能对对象的属性进行劫持,会深度遍历整个对象,不管层级多深。但是只要数组中嵌套了对象,就只能监听到对象的数据变化,无法监听到数组的变化,因而出现响应式问题】

  data(){
    return{
      categories:[],
      categoryData:{},
      currentIndex:-1,
    }
  },

2、如果在data声明时对象、数组就带有的属性,后面改变的时候会触发响应式。但如果是如项目中所示,在后面的代码中添加的初始化对象、数组属性,当该属性发生变化时,该对象/数组不会实现响应式。

getCategory().then(res=>{
        // 1.获取分类数据
        this.categories=res.data.category.list
        // 2.初始化每个类别的子数据
        for (let i=0;i<this.categories.length;i++){
          this.categoryData[i]={
            subcategories:{},
            categoryDetail:{
              'pop':[],
              'new':[],
              'sell':[]
            }
          }
        }
        // 3.请求第一个分类的数据
        this._getSubcategories(0)

3、要使不在data中生命的对象属性或者数组实现响应式,则需要对这个对象/数组进行整体的替换,使其保持响应式。

        向响应式的数组和对象替换为新的响应式数据可以采用扩展运算符、或直接进行复制。因为data中声明的数据已经添加了访问器属性setter,当重新赋值一个堆内存地址时,该数组或者对象也会循环遍历添加访问器属性,从而实现响应式。当向响应式的数组或者对象中新增一个响应式的属性可以使用方法this.$set()或者数组变异方法。

getSubcategory(mailKey).then(res=>{
        this.categoryData[index].subcategories=res.data
        this.categoryData={...this.categoryData}
        this._getCategoryDetail(POP)
        this._getCategoryDetail(SELL)
        this._getCategoryDetail(NEW)
      })
_getCategoryDetail(type){
      // 获取请求的minWallKey
      const minWallkey=this.categories[this.currentIndex].miniWallkey
      // 发送请求
      getCategoryDetail(minWallkey,type).then(res=>{
        // 3.将获取的数据保存下来
        this.categoryData[this.currentIndex].categoryDetail[type]=res
        this.categoryData={...this.categoryData}
      })
    }

【文中查阅了一部分网上资料,并进行使用】

Logo

前往低代码交流专区

更多推荐