Django+微信小程序开发待办清单:数据存储

3425 views, 2022/01/22 updated   Go to Comments

通过前面几章的折腾,现在我们的 Todo-List 还是有些问题:数据没持久化,仅存在于当前页面的内存中;只要退出小程序,所有的数据也跟着消失了。这怎么行,赶紧搞定它。

写入数据

每个小程序都有自己的本地缓存,同一微信用户、同一小程序的存储上限为 10MB。A 用户无法读取到 B 用户的数据,不同小程序之间也无法互相读写数据,所以你可以对数据的安全性放心。

但是,缓存并不太可靠,它会在下面几种情况时会被系统清理:

  • 10MB 存储空间满了。
  • 小程序代码包被删除。

因此重要数据、体积过大的数据不适合放在本地缓存中。

大量的数据更适合以文件系统的形式存储。

不过对本项目来说,本地缓存是相当适合的。

要将数据写入缓存非常简单,只需要在 Todo-List 清单发生任何改变时,调用接口函数 wx.setStorage 就行了。

在逻辑层对应方法中新增代码:

// pages/index/index.js

Component({
  data: {
    // ...
  },
  methods: {
    inputSubmit() {
      // ...已有代码

      // 新代码
      // 将items存储到缓存
      wx.setStorage({
        key: "items",
        data: items,
      })
    },
    checkboxChange(e) {
      // ...已有代码

      // 新代码
      // 将items本地存储
      wx.setStorage({
        key: "items",
        data: items,
      })
    }
  },
})

wx.小程序内置通用接口,它有众多重要功能,比如这里的读写缓存、以及发送网络请求、路由、用户登录等能力。wx.setStorage() 就是写缓存的接口了,key 和 data 分别是要写入数据的键和值。

缓存只支持原生类型、Date、及能够通过 JSON.stringify 序列化的对象。

注意,小程序中很多接口均提供了同步和异步两种版本,这里的 .setStorage() 实际上是个异步函数。同步版本通常是在函数名尾部加 Sync 字样,比如 .setStorageSync.getStorageSync 等等。

读取数据

作为一个待办清单,我们希望它在启动时自动从缓存中加载数据。恰好 Component 构造器提供现成的生命周期函数

在逻辑层增加生命周期函数 attached() ,此函数会在小程序启动时自动执行:

// pages/index/index.js

Component({
  data: {
    // ...已有代码
  },

  // 新代码
  // 生命周期函数“们”
  lifetimes: {
    // 在组件实例进入页面节点树时执行
    attached() {
      // 从缓存中读取items
      const that = this;
      wx.getStorage({
        key: 'items',
        success(res) {
          that.setData({
            items: res.data
          })
        },
      })
    },
  },

  methods: {
    // ...已有代码
  },
})
  • lifetimes 中的方法都被称为生命周期函数,这些函数会在页面的某个阶段自动运行。比如这里的 attached() 会在组件实例进入页面节点树时执行,还有的会在页面转入后台时、被挂起时、被销毁时执行。见生命周期函数
  • 函数中用 .getStorage() 尝试获取缓存中的数据,若存在则将数据更新到页面中。

此外,上面的代码中这个 const that = this 是在搞什么飞机?为什么不直接使用 this ?这个就涉及到 Javascript 中 this 反直觉的指向问题了,要讲清楚能写一篇大文章了。这里就不探讨那些晕乎乎的理论了,你记住一条就行:在嵌套函数、闭包中,this 的指向可能会发生改变,因此在使用它之前先用 const that = this 将当前作用域的方法对象提前绑定到 that 上即可。

当然你也可以用箭头函数规避这个问题。将 wx.getStorage() 中的代码修改为:

wx.getStorage({
  key: 'items',
  success: res => {
    this.setData({
      items: res.data
    })
  },
})

就摆脱烦人的 that 了。

清理数据

仔细想想,我们定义了新增条目的方法,但是没有删除的手段啊。那岂不是清单会越用越大,铁定不行。

再一想,好像也没有必要手动去删除条目,只要在每次启动程序时,将未完成的条目筛选出来即可。

已完成的条目自然就被抛弃了。

既然上面讲到了 ES6 的箭头函数,那我们就再用用 ES6 里的新特性。修改 attached() 函数如下:

attached() {
  wx.getStorage({
    key: 'items',
    success: res => {
      this.setData({
        // 只改了这一行
        items: res.data.filter(v=>v.checked===false)
      })
    },
  })
},

数组的 .filter() 方法将返回一个新数组,新数组的元素全部来自的原始数组并满足 .checked===false 这个条件。也就是将已完成的条目给过滤掉了。

这样就差不多了,测试下输入些条目:

dwt-50-1

重新进入小程序后,“老王”那条已完成的条目就不再显示了:

dwt-50-2

而未完成的条目从缓存中恢复了出来。尝试下再新增其他条目,应该也能如愿存储到缓存中,相当完美。

小程序 vs. Vue

如果你学过 Vue ,可能会感觉:小程序这玩意儿看起来和 Vue 这不是完全一样的吗?

确实很像,但是还是有差别,比如:

  • 小程序的数据是单向绑定,而 Vue 是双向的。
  • 小程序数据绑定支持的模板表达式简单,而 Vue 则是全功能的 JS 表达式。
  • 小程序必须手动调用 setData 接口明确指明同步哪些键值,视图层才会触发更新。而 Vue 对数据对象进行了监听,只要有更改就可以并且会立即触发视图层的更新。

引起这些区别的根本原因是小程序的逻辑层与视图层分散在两个不同的上下文环境中,数据对象在两层间没有共享、并且同步通信的成本较高,因此微信采取了这种折中方案。而 Vue 就没有类似的问题,因此直观上数据绑定得更彻底。

逻辑层与视图层分散在不同的上下文,所引起的另一个特点是:小程序中很多内置接口都是异步的。开发时要小心,不清楚的要通过官方文档确认。

总结

我们用了非常少、容易理解的代码,做出一个完成度很高的 Demo ,希望你体会到开发小程序的乐趣。

但教程还没结束。下集预告:开发 小程序 + Django 的 Web 版本 Todo-List 。

点赞 or 吐槽?来博客GitHub评论区!




本文作者: 杜赛
发布时间: 2022年01月22日 - 19:50
最后更新: 2022年01月22日 - 19:50
转载请保留原文链接及作者