如何在原生微信小程序中实现数据双向绑定
作者:Mora
在原生小程序开发中,数据流是单向的,无法双向绑定,但是要实现双向绑定的功能还是蛮简单的!
下文要讲的是小程序框架 minapp 中实现双向绑定的原理,在 minapp 中,你只需要在 wxml 模板中给组件的属性名后加上
.sync就可以实现双向绑定。下面为了解释其原理,过程可能会说的稍微复杂些,但其实 minapp 框架已经处理了那些繁杂的细节!
首先,要使数据双向绑定,应该避免过多的数据源。
在数据从上到下自然流动的情况下,如果每个组件中都维护它们自己的数据,而又要保持它们数据值的一致,这虽然可以做到,但实现过程并不会简单。
但是也没必要说为了有一个统一的数据源就使用 mobx 或 redux 来全局管理数据,这就有点杀鸡用牛刀的感觉了。
由于双向绑定只存在于父子组件之间,而数据又是从父到子传递的,所以可以优先使用父组件中的数据为数据源,
子组件每次更新数据并不更新它自己内部的数据,而是通过事件机制触发父组件更新它的数据,而父组件更新数据后又会将更新的数据自然地传给子组件,
由此达到数据的双向流动!
并不是所有数据都需要双向绑定,也并不是所有数据都是对外的,子组件还可以有它自己的一个内部数据。所以这就涉及到我们要说的第二个问题:区分哪些数据需要双向绑定,哪些数据又需要子组件自己维护。
用过 vue 的应该都知道,在 vue 中要实现双向绑定,需要在模板中做特殊处理。比如要将父组件的 parentAttr 双向绑定到子组件的 childAttr 上,需要在父组件的模板中这样写:
<child childAttr.sync="parentAttr" />
但是小程序并没有这样的简单的语法,小程序的 wxml 语言的属性名中甚至都不允许出现 " . " 这样的字符。回到我们的问题上来,子组件需要知道哪些属性需要双向绑定,哪些属性需要自己维护,
给模板加个字段(syncAttrMap)专门来告诉子组件需要双向绑定的数据集合不就行了么。如,可以将上面的示例写成微信小程序支持的写法:
<child childAttr="{{parentAttr}}" syncAttrMap="childAttr=parentAttr" />
<!--
如果同时存在多个双向绑定和不需要双向绑定的属性时,可以写成下面这样:
p1, p2 分别双向绑定到子组件的 c1, c2,而 p3 单向绑定到 c3 上
-->
<child c1="{{p1}}" c2="{{p2}}" c3="{{p3}}" syncAttrMap="c1=p1&c2=p2" />
接着,就需要处理子组件数据更新的问题了,在子组件中有两部分数据,一部分是内部数据,另一部分是父组件中的数据,
子组件可以通过读取属性 syncAttrMap 来得到哪些数据是内部的数据,哪些数据是父组件的数据,并且可以知道对应
的父组件中的数据的键名是什么。由于原生的组件方法 setData 不会管你是内部数据,还是父组件中的数据,只要
你调用它去更新数据,它只会更新内部的数据。所以需要另外实现一个新的方法,来自动判断数据源,如果是内部数据,
则直接调用 setData ;如果是双向绑定中的父组件数据,则可以触发一个事件去通知父组件去更新对应的值。
所以根据上面的描述,父组件需要有个监听函数,子组件需要有个智能的 setData 函数。不防将父组件的监听函数
命名为 onSyncAttrUpdate,将子组件的智能 setData 函数命名为 setDataSmart,则可以有如下代码:
// 父组件
Component({
methods: {
onSyncAttrUpdate(e) {
this.setData(e.detail) // 子组件传来的需要更新的数据
}
}
})
<!-- 父组件的模板 -->
<child childAttr="{{parentAttr}}" syncAttrMap="childAttr=parentAttr" bind:syncAttrUpdate="onSyncAttrUpdate" />
// 子组件
Component({
properties: {
childAttr: String,
syncAttrMap: String
},
methods: {
// 子组件更新数据时,只要调用此方法即可,而不是 `setData`
setDataSmart(data) {
// splitDataBySyncAttrMap 函数的实现过程就不说了,只是将对象拆分,大家应该都能实现
let {parentData, innerData} = splitDataBySyncAttrMap(data, this.data.syncAttrMap)
// 内部数据使用 setData 更新
if (Object.keys(innerData).length) {
this.setData(innerData) // setData 中还支持 callback 的回调,为了简化代码,这里不讨论
}
// 双向绑定的父组件数据触发事件让父组件自己去更新
if (Object.keys(parentData).length) {
this.triggerEvent('syncAttrUpdate', parentData)
}
}
}
})
到此,一个简单的双向绑定功能就完成了。但是由于子组件也有可能包含其它组件,也就是说子组件也可以是父组件,而父组件同样也
可以是子组件。所以上面的 onSyncAttrUpdate setDataSmart 函数需要在每个组件中都实现,所以不防
定义一个公共对象 BaseComponent 来实现上面的所有功能,如:
// BaseComponent
const BaseComponent = {
properties: {
syncAttrMap: String
},
methods: {
setDataSmart() {
// ...
},
onSyncAttrUpdate() {
// ...
}
}
}
然后将 BaseComponent minin 到每个组件的对象上去就可以了;另外小程序中还有一个特殊的组件:Page,虽然 Page 和 Component 结构是两样的,
但它也应该算是一个组件,不过它一定是父组件,不可能是别的组件的子组件,所以还需要将 onSyncAttrUpdate 方法写了所有的 Page 定义中。
所有这些就是 minapp 的双向绑定的基本原理了。
等等,最后还有一件事:wxml 模板,不能让用户每次写双向绑定的时候都要写那么复杂语句吧?当然不用,minapp 在编译时,会将模板做个简单的转化:
<child childAttr.sync="parentAttr" />
<!-- 由于属性名 syncAttrMap 是固定的,所以完全可以通过编译手段,将上面的模板转成下面这个模板 -->
<child childAttr="{{parentAttr}}" syncAttrMap="childAttr=parentAttr" />
谢谢,文章到此结束,欢迎关注 minapp:重新定义微信小程序的开发
如何在原生微信小程序中实现数据双向绑定的更多相关文章
- 微信小程序中如何使用WebSocket实现长连接(含完整源码)
本文由腾讯云技术团队原创,感谢作者的分享. 1.前言 微信小程序提供了一套在微信上运行小程序的解决方案,有比较完整的框架.组件以及 API,在这个平台上面的想象空间很大.腾讯云研究了一番之后,发现 ...
- 全栈开发工程师微信小程序-中(中)
全栈开发工程师微信小程序-中(中) 开放能力 open-data 用于展示微信开放的数据 type 开放数据类型 open-gid 当 type="groupName" 时生效, ...
- Taro -- 原生微信小程序转taro
微信小程序转Taro (转发https://nervjs.github.io/taro/docs/taroize.html) Taro 可以将你的原生微信小程序应用转换为 Taro 代码,进而你可以 ...
- 原生微信小程序数据渲染
一直在写vue,第一次接触微信小程序,还是原生,最开始做的时候真的很闹心啊啊啊啊啊啊啊啊啊啊啊啊!!所以最近大概更新的都是微信小程序原生的内容了~~么么哒!!一定会继续努力的!!tips:在小程序项目 ...
- 一招解决微信小程序中的H5缓存问题
一招解决微信小程序中的H5缓存问题1.问题描述开发过程中,为了更新代码方便,往往会在小程序中嵌入H5页面.但问题来了,小程序原生代码更新版本后,简单的从微信中删除或者代码强刷就可以解决缓存问题,但小程 ...
- 网页或微信小程序中使元素占满整个屏幕高度
在项目中经常要用到一个容器元素占满屏幕高度和宽度,然后再在这个容器元素里放置其他元素. 宽度很简单就是width:100% 但是高度呢,我们知道的是height:100%必须是在父元素的高度给定了的情 ...
- 在微信小程序中使用富文本转化插件wxParse
在微信小程序中我们往往需要展示一些丰富的页面内容,包括图片.文本等,基本上要求能够解析常规的HTML最好,由于微信的视图标签和HTML标签不一样,但是也有相对应的关系,因此有人把HTML转换做成了一个 ...
- 微信小程序中发送模版消息注意事项
在微信小程序中发送模版消息 参考微信公众平台Api文档地址:https://mp.weixin.qq.com/debug/wxadoc/dev/api/notice.html#模版消息管理 此参考地址 ...
- 微信小程序中placeholder的样式
通常,现代浏览器大多支持::placeholder选择器,用于设置placeholder的样式,但是在微信小程序中并不支持这种方式,而是提供了一个专门的属性(placeholder-class)来处理 ...
随机推荐
- WinXP系统下Opencms的安装与配置
1.WinXP系统下安装opencms (1)mysql已安装5.1.40 cmd命令行:mysql -uroot -proot (2)OpenCMS在安装时要求MySQL系统变量“max_al ...
- poj Hotel 线段树
经典线段树的题. 每个节点存储的信息:左端点连续空房间的长度,右端点连续空房间长度,连续空房间的最大长度. 由于要求每次必须从尽量靠左边的位置进行居住,那么搜索时应尽量让区间起始位置更小: 1.如果当 ...
- 在浏览器地址栏输入URL,按下回车后究竟发生了什么?
1.DNS 在浏览器中输入URL后,首先要进行DNS解析,DNS解析的顺序为: 浏览器缓存 本地hosts文件 系统缓存 路由器缓存 DNS服务器迭代查询 2.发送请求 通过DNS得到目标的IP地址后 ...
- R实践 第二篇:创建数据集
准备数据是数据分析的第一步,由数据构成集合,我们称作数据集,数据集的结构是行列式的,行表示观测,列表示变量.把数据读入到R中,转换为合适的数据结构,能够提高数据分析的效率.在数据分析中,常用的存储数据 ...
- WireShark过滤解析HTTP/TCP
过滤器的使用: 可利用“&&”(表示“与”)和“||”(表示“或”)来组合使用多个限制规则, 比如“(http && ip.dst == 64.233.189.104) ...
- 普通权限拿webshell
普通权限拿webshell: 1.0day拿webshell:这个不多说.可以去网上搜索一些, 比如你找到你搞的网站cms是discz的,你可以搜索一些相 关0day直接拿 2.修改网站上传类 ...
- 使用CXF和spring搭建webService服务
虽然下一个项目需要使用xfire,但是在查资料的过程中还是看到有不少地方都说cxf比xfire更好,cxf继承了xfire,但是不仅仅包含xfire,因此便也一起来尝试尝试.大概是有了xfire的经验 ...
- PowerManager和PowerManager.WakeLock详解
最近在做项目过程中,有一个LocalPush的需求,需要保持屏幕点亮一段时间,并且在这个时间里,启动Service来执行请求服务器的操作,拿到热点的数据.所以,就找了一下相关的android开源项目. ...
- Oracle SQL Developer中SQL语句格式化快捷键
Oracle SQL Developer中SQL语句格式化快捷键 格式化SQL语句:Ctrl+F7
- 致IT同仁 — IT人士常犯的17个职场错误
记得刚参加工作时(那是97年),中国的IT刚刚兴起,那时,作为一个IT人士是一件很光荣的事,而那时的我正在做电气和电子相关的工作.99年第一次跳槽,进入了IT行业做软件开发.至今,中国的IT已经走过了 ...