小程序:双向数据绑定、父子传参、上拉加载更多、如何使用vant

本文详细介绍了小程序的双向数据绑定、父子组件间的参数传递以及上拉加载更多的实现方法。同时,文章提供了 vant UI 库在小程序中的安装与使用步骤,包括 npm 安装、配置修改、组件引入和使用示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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 默认为 miniprogrampackage.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.jsonindex.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目录的项目就可以预览示例了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值