1、双向数据绑定
单向绑定语法
1.普通的属性的绑定是单向的。例如:
<input value="{{value}}" />
解析:
如果使用
this.setData({ value: 'leaf' })
来更新 value ,this.data.value 和输入框的中显示的值都会被更新为leaf
;
但如果用户修改了输入框里的值,却不会改变this.data.value
。
双向绑定语法
对应属性前加入model:
前缀:
<input model:value="{{value}}" />
用户输入的同时改变 this.data.value
局限性:
与vue相比,暂不支持表达式形式,如下
<input model:value="{{ a.b }}" />
data: {
a:{b:'hello'}
}
2、父子传参
自定义组件(子组件)向父组件传参数
双向绑定同样可以使用在自定义组件上
自定义组件的js文件,接收父组件传递的数据myValue
// custom-component.js
Component({
properties: {
myValue: String
}
})
自定义组件的wxml文件,修改父组件传来的数据myValue
<!-- custom-component.wxml -->
<input model:value="{{myValue}}" />
父组件中使用自定义组件custom-component
<custom-component model:my-value="{{pageValue}}" />
当输入框的值变更时,自定义组件的
myValue
属性会同时变更,父组件页面的this.data.pageValue
也会同时变更,页面 WXML 中所有绑定了pageValue
的位置也会被一同更新。
自定义组件(子组件)还可以这样向父组件传参数
// custom-component.js
Component({
properties: {
myValue: String
},
methods: {
update: function() {
// 更新 myValue
this.setData({
myValue: 'leaf'
})
}
}
})
父组件传参到子组件
<custom-component model:my-value="{{pageValue}}" />
当自定义组件(子组件)使用 setData
更新 myValue
时,父组件页面的 this.data.pageValue
也会同时变更,页面 WXML 中所有绑定了 pageValue
的位置也会被一同更新。
3、上拉加载更多
无论是微信小程序还是其他前端框架,都会遇到上拉加载(懒加载)和下拉刷新这种问题。其实理清楚什么时候请求数据、请求返回的几种情况,那么做这个懒加载就很简单了。
一、首先,固定一个包含列表数据的view高度,让它里面列表的数据溢出可以滚动:
<scroll-view scroll-y lower-threshold="100" bindscrolltolower="scrollToLower" style="height: 100vh;">
<view wx:for="{{listData}}" wx:key="{{index}}" style="height: 40px;line-height: 40px;border-bottom: 1px solid #f4f4f4;">
Item{{item}}
</view>
</scroll-view>
二、那么列表的数据请求就会分成两种情况:一种是初始化页面加载的第一页的数据;一种是滚动到底部请求的下一页的数据。所以我们在请求时要分成两种情况,若是第一页,isPage=false
,下一页的数据isPage=true
:
//请求数据
getData(isPage) {
console.log("需要拼接数据:", Network.pageData);
let params = {
pageNum: this.data.pageNo,
pageSize: 30
}
//请求
Network.pageData(params,(res,err)=>{
if (isPage) {
//下一页的数据拼接在原有数据后面
this.setData({
listData: this.data.listData.concat(res.result)
})
} else {
//第一页数据直接赋值
this.setData({
listData: res.result
})
}
})
},
三、步骤一提到的固定高度的view
,它在往上滚动的时候,滚动到一定的位置便请求下一页的数据。我这里设置了当view
距离到底部还有100px
时,触发请求下一页的数据:
//到达底部
scrollToLower: function (e) {
this.setData({
pageNo: this.data.pageNo + 1
})
this.getData(true);
},
四、以上便是基本的上拉加载。通过以上步骤会出现几个问题,下面提供解决方法:
1、滚动离底部<100px
之后,继续往底部滚动会一直发起请求。我们需要在view
距离到底部还有100px
时,设置一个全局变量loading
,告诉大家我已经发起请求了,等我请求返回的数据展示到页面之后才可以再次发起请求。将步骤三的代码改成以下:
//到达底部
scrollToLower: function (e) {
if (!this.data.loading){
this.setData({
loading: true,
pageNo: this.data.pageNo + 1
})
this.getData(true);
}
},
步骤二的代码改为:
//请求数据
getData(isPage) {
console.log("需要拼接数据:", Network.pageData);
let params = {
pageNum: this.data.pageNo,
pageSize: 30
}
//请求
Network.pageData(params,(res,err)=>{
this.setData({
loading: false
})
if (isPage) {
//下一页的数据拼接在原有数据后面
this.setData({
listData: this.data.listData.concat(res.result)
})
} else {
//第一页数据直接赋值
this.setData({
listData: res.result
})
}
})
},
2、如果最后一页的数据都请求完了,再继续往下滚动还会发起请求。设置一个全局变量noMore,当我请求返回的数组长度为0时,滚动到底部就不用再发起请求了。将步骤三的代码改成以下:
//到达底部
scrollToLower: function (e) {
if (!this.data.loading && !this.data.noMore){
this.setData({
loading: true,
pageNo: this.data.pageNo + 1
})
this.getData(true);
}
},
步骤二的代码改为:
//请求数据
getData(isPage) {
console.log("需要拼接数据:", Network.pageData);
let params = {
pageNum: this.data.pageNo,
pageSize: 30
}
//请求
Network.pageData(params,(res,err)=>{
this.setData({
loading: false
})
if (isPage) {
//下一页的数据拼接在原有数据后面
this.setData({
listData: this.data.listData.concat(res.result)
})
} else {
//第一页数据直接赋值
this.setData({
listData: res.result
})
}
//如果返回的数据为空,那么就没有下一页了
if (res.result.length == 0) {
this.setData({
noMore: true
})
}
})
},
五、我们接下来完善请求失败的情况,步骤二的代码改为:
//请求数据
getData(isPage) {
console.log("需要拼接数据:", Network.pageData);
let params = {
pageNum: this.data.pageNo,
pageSize: 30
}
//请求
Network.pageData(params,(res,err)=>{
this.setData({
loading: false
})
if (err) {//返回失败
this.setData({
loadingFailed: true
})
return false;
}
if (res.code == 0) {
if (isPage) {
//下一页的数据拼接在原有数据后面
this.setData({
listData: this.data.listData.concat(res.result)
})
} else {
//第一页数据直接赋值
this.setData({
listData: res.result
})
}
//如果返回的数据为空,那么就没有下一页了
if (res.result.length == 0) {
this.setData({
noMore: true
})
}
} else {
//返回失败
this.setData({
loadingFailed: true
})
}
})
},
步骤一的HTML代码修改如下:
<scroll-view scroll-y lower-threshold="100" bindscrolltolower="scrollToLower" style="height: 100vh;">
<view wx:for="{{listData}}" wx:key="{{index}}" style="height: 40px;line-height: 40px;border-bottom: 1px solid #f4f4f4;">
Item{{item}}
</view>
<view style="text-align: center;margin: 10px;">
<view wx:if="{{loading}}">加载中...</view>
<view wx:if="{{noMore}}">没有更多了</view>
<view wx:if="{{loadingFailed}}">数据加载失败,请重试</view>
</view>
</scroll-view>
4、小程序如何使用vant
1)安装
步骤一 通过 npm 安装
使用 npm 构建前,请先阅读微信官方的 npm 支持
# 通过 npm 安装
npm i @vant/weapp -S --production
# 通过 yarn 安装
yarn add @vant/weapp --production
# 安装 0.x 版本
npm i vant-weapp -S --production
步骤二 修改 app.json
将 app.json 中的"style": "v2"
去除,小程序的新版基础组件强行加上了许多样式,难以覆盖,不关闭将造成部分组件样式混乱。
步骤三 修改 project.config.json
开发者工具创建的项目,miniprogramRoot
默认为 miniprogram
,package.json
在其外部,npm 构建无法正常工作。
需要手动在 project.config.json
内添加如下配置,使开发者工具可以正确索引到 npm 依赖的位置。
{
...
"setting": {
...
"packNpmManually": true,
"packNpmRelationList": [
{
"packageJsonPath": "./package.json",
"miniprogramNpmDistDir": "./miniprogram/"
}
]
}
}
注意: 由于目前新版开发者工具创建的小程序目录文件结构问题,npm构建的文件目录为miniprogram_npm,并且开发工具会默认在当前目录下创建miniprogram_npm的文件名,所以新版本的miniprogramNpmDistDir配置为’./'即可
步骤四 构建 npm 包
打开微信开发者工具,点击 工具 -> 构建 npm,并勾选 使用 npm 模块 选项,构建完成后,即可引入组件。
步骤五 typescript 支持
如果你使用 typescript 开发小程序,还需要做如下操作,以获得顺畅的开发体验。
安装 miniprogram-api-typings
# 通过 npm 安装
npm i -D miniprogram-api-typings
# 通过 yarn 安装
yarn add -D miniprogram-api-typings
在 tsconfig.json 中增加如下配置,以防止 tsc 编译报错。
请将path/to/node_modules/@vant/weapp
修改为项目的node_modules
中 @vant/weapp 所在的目录。
{
...
"compilerOptions": {
...
"baseUrl": ".",
"types": ["miniprogram-api-typings"],
"paths": {
"@vant/weapp/*": ["path/to/node_modules/@vant/weapp/dist/*"]
},
"lib": ["ES6"]
}
}
2)示例工程
我们提供了一个示例工程,示例工程会帮助你了解如下内容:
- 基于 Vant Weapp 搭建小程序应用
- 样式覆盖方案
3)使用
引入组件
以 Button 组件为例,只需要在app.json
或index.json
中配置 Button 对应的路径即可。
所有组件文档中的引入路径均以 npm 安装为例,如果你是通过下载源代码的方式使用 @vant/weapp,请将路径修改为项目中 @vant/weapp 所在的目录。
// 通过 npm 安装
// app.json
"usingComponents": {
"van-button": "@vant/weapp/button/index"
}
// 通过下载源码使用 es6版本
// app.json
"usingComponents": {
"van-button": "path/to/@vant/weapp/dist/button/index"
}
// 通过下载源码使用 es5版本
// app.json
"usingComponents": {
"van-button": "path/to/@vant/weapp/lib/button/index"
}
使用组件
引入组件后,可以在 wxml 中直接使用组件
<van-button type="primary">按钮</van-button>
4)其他
在开发者工具中预览示例小程序
# 将项目克隆到本地
git clone git@github.com:youzan/vant-weapp.git
# 安装项目依赖
cd vant-weapp && npm install
# 执行组件编译
npm run dev
接着打开微信开发者工具,导入example
目录的项目就可以预览示例了。