微信小程序之observer属性

1,785 阅读4分钟

前言

  新春佳节、一篇推文都没更新、实属懒惰. 这周正式进入搬砖状态, 继续加油ヾ(◍°∇°◍)ノ゙。
若不想看太多废话的话, 建议直接跳转到结尾看总结即可, 本文主要还是个人对问题的产生到解决的简单复盘.

问题来了

最近在接手个新需求, 因还在开发中的功能, 故简单借用了下面的例子来说明.
假设在小程序入口页(假定为index为入口页)存在如下业务流程、思考下如何实现呢? 前置条件:
1、新人弹窗&专属福利弹窗对用户身份信息敏感、故每次页面显示的时候都需要更新最新状态.
2、专属福利弹窗依赖新人弹窗才决定是否要展示
考虑点:
1、判断是否新人依赖接口A&&业务相对独立, 适合放在compA组件内去实现;
2、判断是否有专属福利依赖接口B&业务相对独立, 适合放在compB组件内实现;

根据业务的独立性&为便于简单描述, 分别封装成独立的业务组件, 暂时将新人弹窗组件命名为compA, 专属福利弹窗命名为compB.
接下来我们看看技术实现!
上图对整体的技术实现有了个流程梳理, 接下来可对照流程去看下面的代码.
compA的主要代码如下:

// wxml
<view>我是新人弹窗组件</view>
// js
Component({
  pageLifetimes: {
    show: function() {
      // 这里放请求接口
    this.triggerEvent('showB', {showB: true})
    },
  }
})

index的主要代码如下:

// wxml
<compA bindshowB="showB"></compA>
<compB canSee="{{canSee}}"></compB>
<view bindtap="hideIndex">跳转到其它页面</view>

//js
const app = getApp()

Page({
  data: {},
  showB: function (e) {
   const { detail: {showB } }= e
   this.setData({
    canSee: showB
   })
  },
  hideIndex: function(){
    wx.navigateTo({
      url: '/logs/logs'  // logs页面是为了模拟从index页面跳转到其它页面、再回来的场景
    })
  }
})

compB的主要代码如下:

//wxml
<view>我是专属福利弹窗组件</view>

//js
Component({
  properties: {
    canSee: {
      type: Boolean,
      value: false,
      observer: function(newval, oldval){
        if(newval){
          // 若需要展示compB, 这里还需要调接口实时获取专属福利组件相关展示信息
          console.log('properties-observer', newval)
        }
      }
    }
  }
})

重点来了

步骤1: 进入index页面,假定compA向上传递的showB的值是true[这里很关键] 观察console.log控制台输出如下: 步骤2: 点击跳转到其它页面按钮, 然后再点击头部返回键, 观察console.log控制台输出如下: 经对比发现, 当properties属性值没发生变化时, 使用observer属性是没法做到监听的.

差异点: 希望从某一页面返回到当前页面、仍能及时更新compB的状态。

解决方案

将compB的js文件替换成如下内容:

Component({
  properties: {
    canSee: {
      type: Boolean,
      value: false,
      observer: function(newval, oldval){
        if(newval){
          // 若需要展示compB, 这里还需要调接口实时获取专属福利组件相关展示信息
          console.log('properties-observer', newval)
        }
      }
    }
  },
  observers: {
    'canSee': function(canSee){
      if(canSee){
        console.log('observers', canSee)
      }
    }
  },
})

重复上面的步骤1,你会发现: 重复上面的步骤2,你更会发现: 至此,你会发现采用observers属性可以实现需求点.

===========================华丽丽的的分割线、来个总结===========================
上面主要演示的是值为基本数据类型时的触发情况,不知道引用类型的表现是否一致呢? 我们接着往下看, 替换index文件如下

// wxml
<compA bindshowB="showB"></compA>
<compB canSee="{{canSee}}" obj="{{obj}}"></compB>
<view bindtap="hideIndex">跳转到其它页面</view>

// js
const app = getApp()

Page({
  data: {},
  showB: function (e) {
   const obj = {
     name: "name"
   }
   this.setData({
    obj
   })
  },
  hideIndex: function(){
    wx.navigateTo({
      url: '/logs/logs'  // logs页面是为了模拟从index页面跳转到其它页面、再回来的场景
    })
  }
})

替换compB的js文件如下:

Component({
  properties: {
    obj: {
      type: Object,
      value: null,
      observer: function(newval, oldval){
        if(newval){
          // 若需要展示compB, 这里还需要调接口实时获取专属福利组件相关展示信息
          console.log('properties-observer-obj', newval)
        }
      }
    }
  },
  observers: {
    'obj': function(obj){
      if(obj){
        console.log('observers-obj', obj)
      }
    }
  },
})

重复步骤1、结果如下: 重复步骤2、结果如下: 经过对比你会发现如下结论:

properties-> observer属性跟 observers属性就传入值的数据类型的表现方面, 存在差异 具体差异点如下:

你以为这2个属性只有这个不同么,当然不是,让我们接着往下看看~

扩展

为更简单易懂地描述该知识点,故只替换index跟compB即可, 先来看看死循环 index文件替换如下:

// wxml
<compB canSee="{{canSee}}" ></compB>
<view bindtap="setDemo">演示扩展用</view>

// js
Page({
  data: {},
  setDemo: function(){
    this.setData({
      canSee: true,
     })
  }
})

compB文件替换如下

// wxml
<view>我是专属福利弹窗组件</view>

// js
Component({
  properties: {
    canSee: {
      type: Boolean,
      value: false,
      observer: function(newval, oldval){
        if(newval){
          console.log('properties-observer', newval)
        }
      }
    },
  },
  data: {
    age: 20
  },
  observers: {
    'canSee': function(canSee){
      if(canSee){
       console.log('observers-properties外传属性', canSee)
        // 演示数据监听器可以监听setData数据的变化
        this.setData({
          age: 20
        })
        // 演示死循环
        // this.setData({
        //  canSee: true
        // })
      }
    },
    "age": function(age){
      console.log('observers-内部setData属性', age)
    }
  },
})

你尝试下把上述注释掉的代码打开, 你会发现你的开发者工具卡死不动了~
这也是官网提到的需要特别注意的地方, 详细介绍如下:

同时你会发现:
observers数据监听器支持监听属性或内部数据的变化;
observer是当定义的属性变量的值发生改变才会触发监听;

总结