数据操作

如无特殊说明,下述 this 都是指代 Page 或者 Component 实例上下文

准备工作

默认情况下,框架并没有提供下述提供的数据操作方法,因此需要修改构建配置,在构建配置 framework 选项里加上 data 支持,以启用该扩展:

  1. {
  2. framework: ['data']
  3. }

初始化

默认情况下,data 的初始化同原生小程序, data 也支持定义成 function ,但由于小程序实现机制限制,data 定义的 function 上下文不是组件实例的上下文,而是组件定义导出的对象,因此不建议在该方法里去访问实例提供的方法。

  1. export default {
  2. data: {
  3. num: 2
  4. },
  5. data() { // function 也是支持的,但当前上下文 `this` 非组件实例上下文,无法访问当前实例的任何 API
  6. return {
  7. num: 2
  8. };
  9. }
  10. };

!> 为了实现数据操作响应式,对于用到的 data 根属性,必须预先声明好,动态添加的根数据属性或者动态添加的对象属性,是不支持响应式变更。如果想动态添加对象属性,可以参考下面对象操作说明。

基本操作

原生小程序通过 setData getData API 来修改、获取数据,setData API 会引起视图层的自动更新;
okam 提供 this.xxx 方式直接访问数据,以及直接赋值来进行数据修改,并提供一些扩展数据操作方法,同 Vue。

  • get 数据

this.xxx 等价于原生 this.getData('xxx'), 数据 xxx 需为 dataprops 中定义的数据字段。

  • set 数据

this.xxx = value 等价于原生 this.setData('xxx', value) 或者 this.setData({xxx: value}), 数据属性需为 dataprops 中定义的数据

注意: 微信小程序对于数据操作 API 语法上跟百度小程序有些不同,比如没有 getData API,setData 只支持传入对象形式,如果考虑同时支持微信和百度小程序,可以使用扩展的数据操作语法,不使用原生语法保证兼容性,或者在使用原生语法上注意规避不兼容的语法。快应用 默认就提供了 Vue 数据操作方法,此外为了跟原生小程序对齐,也提供了一个类似的 setData API 操作,但其 callback 执行时机可能不准确,由于原生没有相应 API 能获知该变更完成的能力。

对象操作

修改对象数据,可以直接按 JS 操作对象方式进行直接修改,e.g., this.obj.name = 'xxx',等价于原生 this.setData('obj.name', 'xxx')

注意: 对于动态的对象属性,为了支持响应式,可以使用如下方式:

  1. export default {
  2. data: {
  3. obj: {
  4. a: 1
  5. }
  6. },
  7. methods: {
  8. onClick() {
  9. // 动态添加响应式属性
  10. this.obj = Object.assign({}, this.obj, {
  11. b: 2,
  12. c: 'str'
  13. });
  14. }
  15. }
  16. }

数组操作

提供一组数据操作变异方法,为了能实现数组数据修改能自动触发视图更新,变异方法同 Vue,变异 API 使用同原生的 Array API

  • push: 在数组末尾插入一条数据
  • shift: 在数组开始弹出一条数据
  • unshift: 在数组开始插入一条数据
  • pop: 在数组末尾弹出一条数据
  • splice: 向数组中添加或删除项目
  • sort: 对数组中数据进行排序
  • reverse: 对数组中数据进行反序

注意:

以下两种操作,不能直接触发视图自动更新,即数据修改不是响应式的:

  1. this.arr[0] = 23;
  2. this.arr.length = 2;

针对第一种操作,你可以使用 splice API 实现等价操作:

  1. this.arr.splice(0, 1, 23);

针对第二种操作,同样你也可以使用 splice API 实现等价操作:

  1. this.arr.splice(2);
  • 数组操作扩展的 API (如果考虑对齐 Vue 使用方式,快应用 不支持,需要避开该方式使用)

    • setItem(idx, value): 如果想替换某个数组项,除了上面的 splice 方式,还可以使用该扩展 API: arr.setItem(idx, newValue)
    • getItem(idx): 如果想对数组项内容进行修改用于数组项为对象情况下,可以这么修改:arr.getItem(idx).show = false

计算属性

当某数据项的值由其他数据项计算得来时可通过 computed 定义实现;代码中可通过 this.计算属性名 来引用,模板中也可通过{{ 计算属性名 }} 来绑定数据

!> okam-core@0.4.7 开始支持快应用 computed,依赖于原生的 $watch API,受限于 快应用 原生能力,如果依赖的数据属性是通过动态新增的根属性(使用 $set API 添加),是不支持的,由于快应用的 $watchhandler 必须预先声明好,不能动态添加。

  1. <template>
  2. <view>Hello: {{name}}</view>
  3. <button @click="onClick">Say Hi</button>
  4. <button @click="updateAPlusValue">更新: {{a}} - {{aPlus}}</button>
  5. </template>
  6. <script>
  7. export default {
  8. data: {
  9. firstName: 'Jack',
  10. lastName: 'Lee',
  11. a: 1
  12. },
  13. computed: {
  14. name() {
  15. // ...
  16. return this.firstName + ' ' + this.lastName;
  17. },
  18. // 也可以使用 arrow function
  19. myName: vm => (vm.firstName + ' ' + vm.lastName),
  20. // 支持定义 setter
  21. aPlus: {
  22. get: function () {
  23. return this.a + 1
  24. },
  25. set: function (v) {
  26. this.a = v - 1
  27. }
  28. }
  29. },
  30. methods: {
  31. onClick() {
  32. this.$api.showToast({
  33. title: `hi: ${this.name}`,
  34. duration: 3000
  35. });
  36. },
  37. updateAPlusValue() {
  38. this.aPlus = 9; // 设置计算属性的值
  39. }
  40. }
  41. }
  42. </script>

!> 计算数据的函数中目前可以依赖 data prop 定义的数据项的值,访问方式必须 this.xxx,不能用原生小程序方式 this.data.xxx,否则会无法收集到依赖,不能在该方法变更其它状态的数据,即 set 组件数据

监听器

为了使用监听器功能,需要修改构建配置,在构建配置 framework 选项里加上 watch 选项,以启用该扩展,该扩展是依赖 data 扩展,因此需要同时加上 data 扩展:

  1. {
  2. framework: ['data', 'watch']
  3. }

!> okam-core@0.4.7 开始支持快应用 watch,依赖于原生的 $watch API。

一般情况下,使用 computed 基本能解决大部分业务场景问题,如果存在某些数据依赖需要异步去拉取数据更新,可以使用 watch 属性和 $watch API:

  • watch 属性

    • watch key 为对应 watch 的表达式,e.g., ‘obj.a’
    • watch key 的 value 支持如下几种类型
      • string: watch 回调的处理器名,需要在该组件实例上下文定义,e.g, {watch: {arr: 'handleArrChange'}}
      • function(newVal, oldVal): watch 的回调处理器,执行上下文为组件实例,注意: 对于 数组 或者 对象newValoldVal 是指向同一引用,如果只是内部值变化的情况下
      • Object: 对应的结构 {handler: Function, deep: boolean, immediate: boolean}handler 对应的 watch 回调,deepimmediate$watch API 见下述 options 定义
  • $watch(expressOrFunc, callback, options):Function:返回 unwatch 接口可以用来移除对表达式或者自定义 function 的 watch

    • expressOrFunc: 要观察的表达式或者自定义 function
    • callback: watch 到变化执行的回调
    • options: watch 选项

      • options.deep: boolean 默认 false,如果需要 watch 对象内部值变化,需要设为 true数组不需要快应用 不支持数组索引的 watch,不能 watch 到数组元素值变更,e.g., arr[0].xx = xx 不能变更,需要改成数组 API 的操作: arr.splice(0, 1, Object.assign({}, arr[0], {xx: xx})) 才能 watch 到变更)
      • options.immediate: boolean 默认 false,如果设为 true,会立即触发 callback 执行
  1. export default {
  2. data: {
  3. arr: [],
  4. obj: {
  5. a: 3,
  6. b: {
  7. c: 'str'
  8. }
  9. },
  10. },
  11. computed: {
  12. subObj() {
  13. return this.obj.b;
  14. }
  15. },
  16. watch: {
  17. arr: 'handleArrChange',
  18. subObj: {
  19. handler(newVal, oldVal) {
  20. // do sth.
  21. },
  22. immediate: true
  23. },
  24. obj: {
  25. handler(newVal, oldVal) {
  26. // do sth.
  27. },
  28. deep: true
  29. },
  30. 'obj.a': {
  31. handler(newVal, oldVal) {
  32. // do sth.
  33. }
  34. }
  35. },
  36. created() {
  37. // using $watch API
  38. this.$watch('arr', function (newVal, oldVal) {
  39. // do sth.
  40. });
  41. // add watch options
  42. this.$watch('obj', function (newVal, oldVal) {
  43. // do sth.
  44. }, {deep: true, immediate: true});
  45. // using watch function
  46. this.$watch(function () {
  47. return this.obj.b.c;
  48. }, function (newVal, oldVal) {
  49. // do sth.
  50. }, {deep: true, immediate: true});
  51. },
  52. methods: {
  53. handleArrChange(newVal, oldVal) {
  54. // do sth.
  55. }
  56. }
  57. };

$nextTick

组件数据变更后,将在下一个时钟周期更新视图;如果你修改了某些数据,想要在 DOM 更新后做某些事情,可以使用 $nextTick 方法

!> 快应用不支持

  1. {
  2. methods: {
  3. myFn() {
  4. this.name = 'Tom';
  5. // DOM 还未更新
  6. this.$nextTick(() => {
  7. // DOM 更新
  8. // todo
  9. });
  10. }
  11. }
  12. }