原生小程序实现复杂对象的双向绑定(附代码可直接食用)

        在做项目的过程中,出现了和对象数组进行双向绑定的需求,如果是使用vue的话,只需要一个v-model就解决了,但是原生小程序就不行啦,但是这都是无法难住大佬们的,这次找到了一个大佬的解决方式,趁机学习学习。

 

一、原生小程序的双向绑定

官方文档地址:简易双向绑定 | 微信开放文档 (qq.com)

1、浅读微信小程序的官方文档,可以得到

  • 好消息:从基础库 2.9.3 开始,使用model可以实现简易的双向绑定
  • 坏消息:并不支持data.a的形式,也就是说,基本类型可以,但是复杂类型是打咩的

2、基本使用

使用的方式非常简单,在value的前面加上model:就可以啦

<input model:value="{{value}}" />

3、在自定义组件中传递双向绑定

(1)现在你有一个组件了,这是一个输入框,使用双向绑定

<input model:value="{{myValue}}" />
// custom-component.js
Component({
  properties: {
    myValue: String
  }
})

(2)你在使用模板的时候,只需要传入myValue的值就行

<custom-component model:my-value="{{pageValue}}" />

(3)如果你使用了setData

        setData会改变data中的数据,对应的,输入框中的数据也将会发生改变

二、实现复杂对象的双向绑定

来自Michaelfu的实现(双层对象):微信小程序实现双向绑定 - 掘)

1、实现思路

        通过输入框的输入事件,获取输入框的值,然后将这个值使用setData来进行更新。但是一个个获取值,然后使用setData更新太麻烦啦,所以将这个方法进行封装

module.exports = {
  inputgetName(e) {
    // 从事件对象 e 中获取输入框的 data-name 属性值
    let name = e.currentTarget.dataset.name;
    // 用于存储更新后的数据对象
    let nameMap = {};

    // 通过判断 name 是否包含点符号 . 来确定是否存在多层级的数据绑定关系
    if (name.indexOf('.') !== -1) {
      let nameList = name.split('.');
      // 判断多层级的第一个属性是否存在于 this.data 中,
         如果存在,将其保存到 nameMap 中,
         否则创建一个空对象并保存到 nameMap
      if (this.data[nameList[0]]) {
        nameMap[nameList[0]] = this.data[nameList[0]];
      } else {
        nameMap[nameList[0]] = {};
      }
      // 将输入框的值 e.detail.value 更新到 nameMap 中
      nameMap[nameList[0]][nameList[1]] = e.detail.value;
    } else {
      // 单层的数据直接更改
      nameMap[name] = e.detail.value;
    }
    this.setData(nameMap);
  }
};

2、使用方法

(1)为你的js找一个home,例如:我是放在了utils中,文件命名为binds.js

(2)将刚刚js代码复制进去(就是下面这个啦)

module.exports = {
  inputgetName(e) {
    // 从事件对象 e 中获取输入框的 data-name 属性值
    let name = e.currentTarget.dataset.name;
    // 用于存储更新后的数据对象
    let nameMap = {};

    // 通过判断 name 是否包含点符号 . 来确定是否存在多层级的数据绑定关系
    if (name.indexOf('.') !== -1) {
      let nameList = name.split('.');
      // 判断多层级的第一个属性是否存在于 this.data 中,
         如果存在,将其保存到 nameMap 中,
         否则创建一个空对象并保存到 nameMap
      if (this.data[nameList[0]]) {
        nameMap[nameList[0]] = this.data[nameList[0]];
      } else {
        nameMap[nameList[0]] = {};
      }
      // 将输入框的值 e.detail.value 更新到 nameMap 中
      nameMap[nameList[0]][nameList[1]] = e.detail.value;
    } else {
      // 单层的数据直接更改
      nameMap[name] = e.detail.value;
    }
    this.setData(nameMap);
  }
};

(3)在需要用到双向绑定的页面中引用

js文件:

// 引用公共app.js公共内容
var app = getApp();
// 引入双向绑定js
var binds = require('../../../utils/binds')

xml文件:


注意:控件需要bindinput绑定inputgetName方法,data-name属性也要与需要操作的变量匹配,否则会失效,这样就完成了。

三、扩展

        上面的方式几乎可以满足大多数的场景啦,如果是多层嵌套的情况,可以将js文件的代码替换为下面的:(注明:由于时间原因还没来得及测试这段代码,谨慎使用嗷)

module.exports = {
  inputgetName(e) {
    // 从事件对象 e 中获取输入框的 data-name 属性值
    let name = e.currentTarget.dataset.name;
    // 用于存储更新后的数据对象
    let nameMap = {};

    // 通过判断 name 是否包含点符号 . 来确定是否存在多层级的数据绑定关系
    if (name.indexOf('.') !== -1) {
      let nameList = name.split('.');
      // 判断多层级的第一个属性是否存在于 this.data 中,如果存在,将其保存到 nameMap 中,否则创建一个空对象并保存到 nameMap
      if (this.data[nameList[0]]) {
        nameMap[nameList[0]] = this.data[nameList[0]];
      } else {
        nameMap[nameList[0]] = {};
      }
      // 将输入框的值 e.detail.value 更新到 nameMap 中
      nameMap[nameList[0]][nameList[1]] = e.detail.value;
    } else {
      // 单层的数据直接更改
      nameMap[name] = e.detail.value;
    }
    this.setData(nameMap);
  }
};

四、总结

        以上是我的个人浅薄的见解,如果有问题请您指出~ 如果您读完本文有未解决的疑惑,可以在下方评论,我们一起解决。如果这篇文章对您有帮助,请点个赞给博主一点鼓励。

  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值