作者 | 随笔川迹
ID | suibichuanji
前言
撰文:川川
在小程序中各个页面之间是相互独立的,一个页面分为渲染层(视图层 webview),逻辑层(JavaScript),系统层(底层)
在架构上,WebView
和 JavascriptCore
都是独立的模块,并不具备数据直接共享的通道
换而言之,若要将逻辑层中的data
的数据渲染到页面中,他们之间是无法直接通信的,往往需要系统层作为中间角色
我们都知道视图层的数据来源于逻辑层 data,而视图图层若想要改变逻辑层 data 的数据,需要借助setData
这个方法去触发,以达到更新视图层的数据,具体的工作过程是怎么样的?
· 正 · 文 · 来 · 啦 ·
01
setData是什么?
定义: 设置数据,更改数据
作用: setData函数用于将数据从逻辑层发送到视图层(异步),同时改变对应的 this.data的值(同步)
仔细细品这句话,会包含了很多信息
从上面的这张图中就可以看到,当逻辑层data数据渲染到界面的时候,逻辑层的数据需要经过系统层,当系统层接收到这个逻辑层的数据后
系统层在把数据转发给渲染层,然后在渲染层展示出来,在这个过程当中是异步的
视图层和逻辑层的数据传输,实际上通过两边提供的 JavScript Core所实现,即用户传输的数据,需要将其转换为字符串形式传递
同时把转换后的数据内容拼接成一份 JS 脚本,再通过执行 JS 脚本的形式传递到两边独立的环境
02
setData两个重要的参数
从官方文档中看到这句Page.prototype.setData(Object data, Function callback),得知,setData方法是挂载当前页面实例Page原型下一个公用实例方法
也就是说,Page 下面的任何一个方法内,都可以使用 setData 方法,它接收两个参数
为了便于理解,在小程序中创建一个 page 页面,名为setdata,如下是逻辑层 js 文件
// miniprogram/pages/setdata/setdata.js
Page({
/**
* 页面的初始数据
*/
data: {
name: "itclanCoder"
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
}
})
而 wxml 文件如下
<!--miniprogram/pages/setdata/setdata.wxml-->
<text>{{name}}</text>
在Web 开发中,开发者使用JavaScript通过Dom接口来完成界面的实时更新。而在小程序中,使用WXML语言所提供的数据绑定功能,来完成此项功能
在小程序中是没有DOM,BOM的那一套东西的,没有document.getElementById等的
小程序是数据驱动视图的,逻辑层中的 data 数据改变了,视图层 view 也会跟着改变,它是单向数据流的,如果想要触发视图中数据的更新,那么就需要借助setData这个方法
上面的WXML通过{{变量名}}来绑定 WXML文件和对应的JavaScript文件中的data对象属性
在上面的示例中,页面会显示itclanCoder,那如何更改逻辑层的数据呢
在下面的示例中,演示了如何更改逻辑层的数据,在 wxml 中新增了一个按钮,用bindtap绑定了一个handleChangeName方法,触发按钮,改变 data 下的数据
<!--miniprogram/pages/setdata/setdata.wxml-->
<text>{{name}}</text>
<button type="primary" bindtap="handleChangeName">更改data中数据</button>
而在逻辑层 JS
// miniprogram/pages/setdata/setdata.js
Page({
/**
* 页面的初始数据
*/
data: {
name: "itclanCoder"
},
// 改变data的方法
handleChangeName() {
console.log("name开始的数据", this.data.name); // itclanCoder
this.setData({
name: "川川"
})
console.log("name经过setData后的数据", this.data.name); // 川川
}
})
在上面的示例代码中,更改data下面的name字段值,使用的是setData方法,这个方法接收了一个参数,第一个参数是对象,这个Object 以 key: value 的形式表示,将 this.data中的 key对应的值改变成 value
注意
这个key可以以数据路径的形式给出,支持改变数组中的某一项或对象的某个属性,如 array[2].message,a.b.c.d,并且不需要在 this.data中预先定义,但凡是页面要显示的变量数据,最好先挂载在data下初始化定义,然后在使用
也就是说在更改setData下的变量时,直接写key名就可以了的,不用写this.data.属性,如下所示
this.setData({
// this.data.name: "川川" // 这样写是会报错的
name: "川川" // 正确的写法
})
而setData接收第二个参数,是一个Function callback
handleChangeName() {
console.log("name开始的数据", this.data.name); // itclanCoder
this.setData({
name: "川川"
}, () => { // 接收第二个回调函数
console.log("执行setData引起的界面更新渲染完毕后的回调函数");
})
console.log("name经过setData后的数据", this.data.name); // 川川
}
上面代码的执行顺序是
itclancoder
川川
执行setData引起的界面更新渲染完毕后的回调函数
此结果说明这个setData方法是异步的,等待主线程任务做完了,然后在去执行第二个参数,回调异步函数
03
如何更改某个对象下的属性
有时候,我们的接口数据类型是对象,并非是基本数据类型(number,boolean,string,null),但由于业务需求,我们往往需要改变对象下的某个属性
如下所示,我想改变person下的 age 属性值
// miniprogram/pages/setdata/setdata.js
Page({
/**
* 页面的初始数据
*/
data: {
person: {
name: "随笔川迹",
sex: "男神",
age: 20
}
},
handleChangeName() {
this.setData({
person: {
age: 24
}
})
}
})
在上面的代码中,的确可以更改person对象下的age属性,但是随之带来的问题是,person对象下除了age属性,其他属性都消失了
这非常令人郁闷
那如何解决这个问题?
this.setData({
"person.age": 24 // 注意要用双引号或单引号将属性给引起来
})
this.setData({
['person.age']: "川川" // 访问对象下的属性可以用.也可以用中括号,中间代表是一个变量,需要用引号引起来
})
如下所示
这个在以后的开发中,很有用,有时候,在需要更改对象下的某个属性值的时候,就可以使用这种方式
04
setData注意事项
结语
在本文中主要介绍了下setData的使用,它是用于修改挂载在 data 下面的数据的,当想要修改视图 view,那么需要借助 setData 函数,它接收两个参数,第一个参数时必传的,也就是要修改视图 view 层的对象,而第二个参数时非必传的
setData 将数据从逻辑层发送到视图层是异步,同时改变对应的this.data的值是同步,它并不是实时的,这也导致了必须要考虑性能的因素
从而介绍了 setData 的使用注意事项,值得注意的是,如何修改对象下的某个属性,这个在往后的开发中,是使用比较频繁的.
如果小伙伴们有问题,欢迎大家下面留言,一起学习讨论