1.数据绑定
数据绑定的运行与逻辑
小程序里面都是通过数据绑定的形式进行显示数据
小程序的数据只有出现在data中的数据才能进行数据绑定,才能进行数据显示
小程序只能单向数据绑定(自动)
就是页面上的值改动,不能自动改变JS。但是可以通过其他方式进行改变,比如事件的方式
一般是页面加载时就要从服务器去取数据了也就是在onLoad函数里。setData函数的作用是把从服务器获取的数据复制到data里边,这样才能实现数据绑定。this.setData()
以下将展示小程序提供的更加多元化的复杂的数据绑定方式。
index.wxml
<!--数据绑定--内容-->
<view>{{message}}</view>
<!--数据绑定--组件属性-->
<view id="item-{{id}}">组件属性id-{{id}}</view>
<!--数据绑定---控制属性-->
<view wx:if="{{condition}}">控制属性{{condition}}</view>
<!--数据绑定---三元运算-->
<view hidden="{{flag ? true : false}}">Hidden--{{flag}}</view>
<!--数据绑定---算数运算-->
<view>{{a + b}} + {{c}} + d</view>
<!--数据绑定---逻辑判断-->
<view wx:if="{{length > 5}}">6</view>
<!--数据绑定---字符串运算-->
<view>{{"Hello " + name}}</view>
<!--数据绑定---数组组合-->
<view wx:for="{{[zero, 1, 2, 3, 4, 5, 6]}}">{{item}}</view>
<!--数据绑定---对象-->
<!--最终组合成的对象是{for: 1, bar: 2}-->
<template is="objectCombine" data="{{for: x, bar: y}}"></template>
<!--数据绑定---扩展运算符 ... 来将一个对象展开-->
<!--最终组合成的对象是{a: 1, b: 2, c: 3, d: 4, e: 5}-->
<template is="objectCombine" data="{{...obj1, ...obj2, e: 5}}"></template>
<!--数据绑定---对象的 key 和 value 相同-->
<!--最终组合成的对象是{foo: 'my-foo', bar:'my-bar'}-->
<template is="objectCombine" data="{{foo, bar}}"></template>
index.js
Page({
data:{
//内容
message:'Hello MINA!',
//组件属性
id: 0,
//控制属性
condition: true,
//三元运算
flag:false,
//算数运算
a: 1,
b: 2,
c: 3,
//逻辑判断
length: 6,
//字符串运算
name: 'MINA',
//数组组合
zero: 0,
//对象
x: 0,
y: 1,
//对象展开
obj1: {
a: 1,
b: 2
},
obj2: {
c: 3,
d: 4
},
e: 5,
//对象key和value相同
foo: 'my-foo',
bar: 'my-bar'
},
})
附注:小程序中的true/false
vertical = 'false'
vaertical = '{{false}}'
JS补充知识:引号说明值是字符串,字符串’false’值会被判定是true,非空字符串在js中判定是true。 如果要用的话加上’{{false}}’。 例如 vertical = ‘{{false}}’
2.调试工具 AppData panel
微信小程序调试工具:Wxml Panel、Sources Panel、AppData Panel、Storage Panel、Network Panel、Console Panel、Sensor Panel
AppData panel 用于显示当前项目运行时小程序 AppData 具体数据,实时地反映项目数据情况,可以在此处编辑数据,并及时地反馈到界面上。
3.缓存
本地数据缓存是小程序存储在当前设备上硬盘上的数据,本地数据缓存有非常多的用途,我们可以利用本地数据缓存来存储用户在小程序上产生的操作,在用户关闭小程序重新打开时可以恢复之前的状态。我们还可以利用本地缓存一些服务端非实时的数据提高小程序获取数据的速度,在特定的场景下可以提高页面的渲染速度,减少用户的等待时间。
缓存的作用是为了加快数据的访问,小程序里面可以设置缓存(本地),设置缓存后,如果没有手动清除缓存的话,就会一直存在。大小不能超过10M。
设置缓存:
wx.setStorageSync('key','value'):同步
wx.setStorage({key:'key',data:'value'}):异步
wx.setStorageSync('icessun','2018/2/14') // 同步设置缓存
wx.setStorage({key:'跳一跳',data:'666'}) // 异步设置缓存
同步设置缓存,缓存值可以为一个字符串,也可以为一个对象,当第一个参数值相同的时候,后面的会覆盖前面的。异步也一样。
wx.setStorageSync('key',{
game: "跳一跳",
gold: "666"
})
获取缓存
获取缓存的方法很简单,把对应设置缓存的set变为get就行。
wx.getStorageSync('key'):同步 直接返回获取到的值
wx.getStorage({key:'key',callback}):异步 通过回调函数返回获取的值
wx.setStorageSync('key', {
game: "跳一跳",
gold: "666"
})
var a=wx.getStorageSync('key');
console.log(a); // {game: "跳一跳", gold: "666" }
读取/写入本地数据缓存
Sync后缀的接口表示是同步接口,执行完毕之后会立马返回。
wx.getStorage/wx.getStorageSync读取本地数据缓存
wx.getStorage({
key: 'key1',
success: function(res) {
// 异步接口在success回调才能拿到返回值
var value1 = res.data
},
fail: function() {
console.log('读取key1发生错误')
}
})
try{
// 同步接口立即返回值
var value2 = wx.getStorageSync('key2')
}catch (e) {
console.log('读取key2发生错误')
}
wx.setStorage/wx.setStorageSync写入本地数据缓存
// 异步接口在success/fail回调才知道写入成功与否
wx.setStorage({
key:"key",
data:"value1"
success: function() {
console.log('写入value1成功')
},
fail: function() {
console.log('写入value1发生错误')
}
})
try{
// 同步接口立即写入
wx.setStorageSync('key', 'value2')
console.log('写入value2成功')
}catch (e) {
console.log('写入value2发生错误')
}
现在看一些缓存示例:
page.js利用本地缓存提前渲染界面
Page({
onLoad: function() {
var that = this
var list =wx.getStorageSync("list")
if (list) { // 本地如果有缓存列表,提前渲染
that.setData({
list: list
})
}
wx.request({
url: 'https://test.com/getproductlist',
success: function (res) {
if (res.statusCode === 200) {
list = res.data.list
that.setData({ // 再次渲染列表
list: list
})
wx.setStorageSync("list",list) // 覆盖缓存数据
}
}
})
}
})
利用本地缓存持久存储用户登陆态SessionId
//page.js
var app = getApp()
Page({
onLoad: function() {
// 调用wx.login获取微信登录凭证
wx.login({
success: function(res) {
// 拿到微信登录凭证之后去自己服务器换取自己的登录凭证
wx.request({
url: 'https://test.com/login',
data: { code: res.code },
success: function(res) {
var data = res.data
// 把 SessionId 和过期时间放在内存中的全局对象和本地缓存里边
app.globalData.sessionId =data.sessionId
wx.setStorageSync('SESSIONID',data.sessionId)
// 假设登录态保持1天
var expiredTime = +new Date() +1*24*60*60*1000
app.globalData.expiredTime =expiredTime
wx.setStorageSync('EXPIREDTIME',expiredTime)
}
})
}
})
}
})
利用本地缓存恢复用户登陆态SessionId
//app.js
App({
onLaunch: function(options) {
var sessionId =wx.getStorageSync('SESSIONID')
var expiredTime =wx.getStorageSync('EXPIREDTIME')
var now = +new Date()
if (now - expiredTime <=1*24*60*60*1000) {
this.globalData.sessionId = sessionId
this.globalData.expiredTime = expiredTime
}
},
globalData: {
sessionId: null,
expiredTime: 0
}
})
4.Template模板的使用
wxml/wxss/js模块的复用,更好的封装ui和业务逻辑,增加复用性。
当一块区域需要在多个地方使用的时候,可以把这个区域做成一个模版,在使用的时候调用这个模版即可,这样即减少重复代码的编写,又易于维护,让代码整洁。
// post-item/post-item-template.wxml
<template name="postItem">
<view class="post-container">
<view class="post-author-date">
<image class="post-author" src="{{avatar}}"></image>
<text class="post-date">{{date}}</text>
</view>
<text class="post-title">{{title}}</text>
<image class="post-image" src="{{imgSrc}}"></image>
<text class="post-content">{{content}}</text>
<view class="post-like">
<image class="post-like-image" src="/images/icon/chat.png"></image>
<text class="post-like-font">{{collection}}</text>
<image class="post-like-image" src="/images/icon/view.png"></image>
<text class="post-like-font">{{reading}}</text>
</view>
</view>
</template>
// posts/post.wxml
<import src="post-item/post-item-template.wxml" />
<view>
<swiper catchtap='onSwiperTap' indicator-dots='true' interval='5000' autoplay='true'>
<swiper-item>
<image id="7" src="/images/wx.png" data-postId="3"></image>
</swiper-item>
<swiper-item>
<image src="/images/vr.png" data-postId="4"></image>
</swiper-item>
<swiper-item>
<image src="/images/iqiyi.png" data-postId="5"></image>
</swiper-item>
</swiper>
<block wx:for="{{posts_key}}" wx:for-item="item">
<!--template和block都会在编译后,消失,也就是源代码中没有-->
<view catchtap='onPostTap' data-postID='{{item.postId}}'>
<!--...相当于把之前一个item里面的数据进行展开和平铺了,所以模板里面不需要item了,因为是item里面的内容了-->
<template is="postItem" data="{{...item}}"></template>
</view>
</block>
</view>
项目结构如下:
为了方便管理我们的模版文件,可以在pages文件夹下面,新建一个模版文件,里面存放编写的模版;我们要使用标签template来包裹代码,并且要给其加一个name属性,当然也要编写对应的样式,和正常写样式的方法没有区别。
新建的模版文件里面只能存放模版的wxml和wxss文件,目前小程序的模版文件里面放入其他的文件类型不起作用,不能进行复用,虽然不报错,比如js文件。
template标签只是一种占位符,告诉编译器这个地方是加载模版代码的,当页面编译完成,这个标签就消失,所以要对与模版文件响应事件,我们就需要在加载模版文件的区域,使用一个可以添加事件的标签把其模版文件包裹起来,比如:view / block
<view bindtap=” ....”> template模版代码 </view>
使用模板
编写好了模版代码,怎么样在需要加载模版代码的地方使用呢?
首先,模版代码是在其他文件夹中,使用它,就必然要引入该模版文件,
一般在对应要引入模版文件的文件开头部分引入:
// 在对应的wxml文件中开头引入
<import src = '模版wxml文件路径' />
// 在对应的wxss文件中开头引入,注意末尾的分号
@import '模版wxss文件路径' ;
然后在引入模版文件的wxml文件,适当位置使用
<template is = '模版的名字' data="{{要绑定到模版的数据}}"
到此,简单的模版引入和模版数据的绑定就完成,当我们要循环模版的时候,只需要如下,在外面加一层标签即可:
// bolck标签的作用是作用事件到template模版上面
<block wx:for=" 服务器获取的数据集" wx:for-item='item' wx:for-index='index' >
<template is = '模版的名字' data="{{要绑定到模版的数据,一般是服务器获取的一个数据对象item}}"
</block>
模板循环:
前一篇文章说了一下数据的循环,借用属性wx:for=’ ',通过默认得到的item / index可以知道对应的子对象数据和其索引值;但是我们发现,每一个模版绑定的数据项前面都要使用item.属性值(子对象的属性值)来绑定数据,item是多余的,有没有办法去简化?当然有!
<view wx:for='{{datesArry}}' wx:for-item='item' wx:for-index='idx'>
// 在对应的item的前面加上 ... 三个点
<template is='postItem' data='{{...item}}' />
// <view>{{idx}}</view>
</view>
在循环的子对象item前面加上…三个点,就行。简单的一行代码就实现了下图的页面。
前面加三个小点的作用:相当于把子对象给平铺,直接展开了里面的属性值,就可以直接在模版里面绑定这些属性值,不需要在模版里面指定其数据源(这就是…的作用)
5.自定义属性
我们先看怎么使用:
//wxml
<view class='zright' bindtap='choseCoupon' data-info='{{item}}' data-id='{{index}}'>
//js
choseCoupon: function (e) {
console.log(e.currentTarget.dataset.id)
console.log(e.currentTarget.dataset.info)
}
自定义属性一般说来都是使用data-开头,绑定一些我们需要存储的信息,传递到其他地方,比如点击的页面文章索引。
设置自定义属性
设置自定义属性很简单,但是要注意一点的是,在操作模版的时候,一定要在其外面包裹一层view,才能进行操作;原因是template标签只是一个占位符,编译后就消失。
<view wx:for='{{datesArry}}' wx:for-item='item' data-postId='{{item.postId}} wx:for-index='idx' catchtap='onPostTap' '>
<template is='postItem' data='{{...item}}' />
</view>
item.postId是从服务器上面获取的,是数据源中的一个属性。
获取自定义属性
获取自定义属性
获取自定义属性,当然是通过事件去获取
onPostTap:function(event){
var postId=event.currentTarget.dataset.postid;
var postIdData = event.currentTarget.dataset;
console.log(postId); // 1
console.log(postIdData);
}
event.currentTarget.dataset.postid:获取的自定义属性值
event事件对象
event.currentTarget:当前点击的目标元素
event.currentTarget.dataset:目标元素上面的自定义属性集合
自定义属性应用:通过获取到的自定义属性,可以作为一个参数绑定一个链接上面,达到不同栏位的点击跳转到不同的页面
onPostTap:function(event){
var postId=event.currentTarget.dataset.postid;
wx.navigateTo({
url: 'xxxx?id='+postId,
})
}
上面只是说明了在同一个页面之间获取自定义属性,要是在不同页面之间怎么获取自定义属性,达到传递值的作用呢?
wx.navigateTo({
url: 'xxxx?id='+postId,
})
通过上面的方法把参数postId,传递出去,然后在要接收的页面中使用options.id
来获取
onLoad: function (options) {
var postId = options.id;
console.log(options);
}
options.id
就是通过wx.navigateTo传递过去的postId
参考文章:
https://developers.weixin.qq.com/ebook?action=get_post_info&docid=000a2c7c9f4a981b0086bd31e5b40a#_ftn9
https://developers.weixin.qq.com/miniprogram/dev/api/storage/wx.getStorageSync.html
https://segmentfault.com/a/1190000013298922#articleHeader3
https://segmentfault.com/a/1190000013513917
https://blog.youkuaiyun.com/zeroyulong/article/details/79984582
https://blog.youkuaiyun.com/woshihaiyong168/article/details/54633441