【微信小程序实战教程】之微信小程序核心组件详解

微信小程序核心组件

组件化开发并不是小程序所特有的,一些其他编程语言中都有组件化的概念,准确来讲,只有UI视图层的展示,就必定要用到组件化。组件是UI视图层的最基本组成单元,组件中包含了一些基础功能和基础样式,一个组件就类似于一个自定义的标签。

小程序框架为开发者提供了一系列基础组件,开发者可以通过组合这些基础组件进行快速开发,那么微信小程序提供的基础组件肯定是要完成小程序开发的基础功能与微信风格保持一致的样式。

1 视图容器组件

视图容器组件主要用于控制页面的内容,与HTML中的<div>标签功能类似,可以把小程序的容器组件理解为一个盒子容器,可以将其他组件填充在该容器组件中。小程序提供的视图容器组件主要包括以下几种:

  • view 视图容器,这是在开发中最常用的一种容器组件;
  • scroll-view 可滚动视图容器;
  • swiper 轮播组件;
  • movable-view 可移动容器;
  • cover-view 覆盖在原生组件之上的文本视图。

小程序提供的视图容器组件除了上述的一些常用组件之外,还有其他的组件,例如 cover-image、match-media、page-container等。每个组件的应用场景不同,但是在实际开发中,最常用的只有视图容器view组件、滑块视图容器swiper组件、可滚动视图容器 scroll-view 组件、可移动视图容器 movable-view 组件、原生视图容器 cover-view 组件等五大视图容器组件。

1.1 视图容器

view作为小程序最基础的视图容器组件,其被使用的机会非常多。view组件的作用和HTML代码中的 <div> 容器标签相似,都是用于管理页面中的元素。

view视图容器组件上可以定义以下属性:

  • hover-class,值为字符串类型,用于指定组件被按下时的样式;
  • hover-stop-propagation,值为boolean类型,用于指定是否阻止本节点的祖先节点出现点击状态;
  • hover-start-time,值为数字类型,用于指定按住后多久出现点击状态,单位为毫秒;
  • hover-stay-time,值为数字类型,用于指定手指松开后点击状态保留的时长,单位为毫秒;

view组件可以和WXSS配合,完成页面布局效果,示例代码如例1所示。

【例1】view实现宫格布局

// index.wxml
<view class="row">
    <view class="col">A</view>
    <view class="col">B</view>
    <view class="col">C</view>
    <view class="col">D</view>
    <view class="col">E</view>
    <view class="col">F</view>
</view>
// index.wxss
.row{
  display: flex;
  flex-wrap: wrap;
}
.col{
  border: 1px solid #000;
  min-height: 150rpx;
  width: 30%;
  margin: 10rpx;
  display: flex;
  align-items: center;
  justify-content: center;
}

上面示例代码运行后的效果如图1所示。
在这里插入图片描述
图1 view实现宫格效果

1.2 滑块视图容器

很多购物商城类小程序中,经常会在首页放置一些轮播图的特效,用于循环播放热销商品信息,小程序基础组件中的swiper滑块视图容器就可以实现这种图片轮播的效果。swiper滑块视图容器组件的属性如表1所示。

在这里插入图片描述

swiper滑块组件容器组件中要放置swiper-item组件,否则将无法实现轮播效果,每个swiper-item组件为轮播中的一个滑块元素,宽高默认均为100%。在swiper-item组件上可以定义两个属性:

  • 一个是item-id,表示该swiper-item的唯一标识符;
  • 另一个属性是skip-hidden-item-layout,值为boolean类型,用于表示是否跳过未显示的滑块布局,如果值为 true时,可以优化复杂情况下的滑动性能,但会丢失隐藏状态滑块的布局信息。

swiper滑块容器组件上除了上述的一些属性之外,还可以定义三个事件,分别是:

  • bindchange事件,当组件上的current属性改变时触发该事件;
  • bindtransition事件,当swiper-item的位置发生改变时触发该事件;
  • bindanimationfinish事件,当动画结束时会触发该事件。

组件上的change事件函数有两个默认参数,一个是current,表示当前改变的current属性值;另一个参数是source,表示导致变更的原因,原因的值又存在三种情况:

  • 值为autoplay,表示由于自动播放导致swiper的current属性发生改变;
  • 值为touch,表示用户手动滑动屏幕导致swiper发生变化;
  • 值为空字符串,由于其他原因引起的swiper发生变化;

如果在bindchage的事件回调函数中使用setData()函数改变current的值,会导致setData()函数不停的被调用,引起程序死循环。如果开发者想要通过代码来改变current的值,在调用setData()方法之前应该先检查一下source字段的值是否是由于用户触摸引起的,这样就可以避免程序死循环的情况出现。

在小程序页面中实现轮播图效果的示例代码如例2所示。

【例2】实现轮播图代码

// index.wxml
<view class="swiper-body">
    <swiper 
        indicator-dots
        autoplay
        circular
        indicator-color="#fff"
        indicator-active-color="#666"
    >
        <swiper-item class="swiper-item-a">A</swiper-item>
        <swiper-item class="swiper-item-b">B</swiper-item>
        <swiper-item class="swiper-item-c">C</swiper-item>
    </swiper>
</view>
// index.wxss
.swiper-body {
  color: #fff;
}
swiper-item {
  display: flex;
  justify-content: center;
  align-items: center;
}
.swiper-item-a {
  background-color: blue;
}
.swiper-item-b {
  background-color: pink;
}
.swiper-item-c {
  background-color: #ccc;
}

上面代码运行后的效果如图2所示。

在这里插入图片描述
图2 轮播效果

在例2的代码中,为swiper组件添加的indicator-dotsautoplaycircular三个属性没有设置属性值,如果当属性的值为boolean类型是,只要在组件中定义了该属性,即默认表示该属性的值为true。所以,swiper组件标签上添加的这三个属性,表示在轮播面板中显示滑块元素的指示点,并设置当前轮播为自动切换效果,采用衔接滑动的效果。然后又在swiper组件上定义了indicator-color属性和indicator-active-color属性,用于设置指示点的默认颜色值为“#fff”,当前选中的指示点颜色值为“#666”

1.3 可滚动视图容器

在传统的前端Web开发中,如果当页面内容元素过多时,超出了视图容器边界范围,可以通过CSS设置该元素超出范围的部分使用滚动样式,那么在小程序中同样可以使用滚动容器组件来实现这样的效果。小程序的视图容器组件中提供了scroll-view组件,表示可滚动的视图区域组件。
scroll-view组件为开发者提供了两种滚动的方式,一种是横向滚动,另一种是纵向滚动,可以通过scroll-view组件上的属性来进行控制。scroll-view组件的可用属性如表2所示。

在这里插入图片描述

scroll-view组件上还可以定义一系列事件,如表3所示。

在这里插入图片描述

在scroll-view组件被滚动时,系统会阻止页面的回弹,所以在scroll-view中滚动时无法触发在Page构造器参数中定义的onPullDownRefresh() 页面事件处理函数,即无法使用小程序提供的接口监听用户下拉刷新事件。如果需要在滚动视图容器中监听用户的下拉刷新行为,需要使用scroll-view组件提供的相关事件来监听。

如果开发者使用的是2.4.0以下版本的基础库,在scroll-view组件中不支持嵌套textarea、map、canvas、video等组件。使用scroll-view组件实现纵向滚动的示例代码如例3所示。

【例3】纵向滚动示例

// index.wxml
<view class="scroll-container">
    <scroll-view scroll-y bindscrolltolower="onScrollBottom">
        <view class="row-item" wx:for="{{nums}}" wx:key="index">
            {{item}}
        </view>
    </scroll-view>
</view>
// index.js
Page({
  data: {
    nums: 100
  },
  onScrollBottom() {
    // 滚动区域触底时触发
    wx.showToast({
      title: '已经触底了!',
    })
  }
})
// index.wxss
.scroll-container {
  background-color: #eee;
  height: 500rpx;
}
scroll-view {
  border: 1px solid #999;
  height: 100%;
}
.row-item {
  line-height: 60rpx;
  text-align: center;
}

上面代码运行后的效果如图3所示。

在这里插入图片描述
图3 scroll-view组件的区域滚动效果

在例3中,为scroll-view组件添加了bindscrolltolower事件来监听滚动区域触底行为,并在index.js文件中定义onScrollBottom() 事件方法。当滚动区域触底时,弹出Toast提示,效果如图4所示。

在这里插入图片描述
图4 scroll-view组件滚动触底时触发Toast提示

1.4 可移动视图容器

小程序除了提供一些常用的视图容器组件之外,还提供了一个可移动的视图容器movable-view组件,用户可以在页面中使用手指滑动实现组件的拖拽滑动。movable-view组件必须要放置在movable-area组件中,并且是其直接的子节点才能实现拖拽,否则将不能移动。

movable-area组件用于定义可移动区域,该组件上有一个scale-area属性,值为boolean类型,用于设置当movable-view为双指缩放时,是否将缩放手势生效区域修改为整个movable-area容器。而且movable-area组件必须设置width和height属性,如果不设置这两个属性的话,默认宽和高的值均为10px。当movable-view组件尺寸小于movable-area容器时,movable-view组件的移动范围是在movable-area容器内;当movable-view组件尺寸大于movable-area容器时,movable-view组件的移动范围必须包含movable-area容器。

movable-view组件的属性如表4所示。

在这里插入图片描述

movable-view组件的事件如表5所示。

在这里插入图片描述

movable-view组件上的bindchange事件函数有三个默认参数,分别是x、y、source,其中,参数x和y表示组件移动的坐标位置,source表示组件产生移动的原因,其原因包括以下几个范围值:

  • 当值为touch时,表示用户拖动;
  • 当值为touch-out-of-bounds时,表示超出了移动的范围;
  • 当值为out-of-bounds时,表示超出移动范围后的回弹;
  • 当值为friction时,表示移动时的惯性;
  • 当值为空字符串时,表示使用setData()函数修改了组件的位置。

在使用movable-view组件时,必须设置组件的width和height属性,如果不设置宽高属性的话,系统会默认设置movable-view组件的宽高为10px。movable-view组件默认为绝对定位,其top和left属性的值均为0px。基于movable-view组件实现页面元素的可拖拽功能示例代码如例4所示。

【例4】实现页面元素的可拖拽功能

// index.wxml
<movable-area>
    <movable-view 
        direction="all"
        inertia
        bindchange="onViewChange"
    >
        Hello
    </movable-view>
</movable-area>
// index.js
Page({
  onViewChange(options) {
    // 可移动容器位置改变事件
    const {x, y, source} = options.detail
    console.log("移动后X坐标:", x);
    console.log("移动后Y坐标:", y);
    console.log("移动原因:", source);
  }
})
// index.wxss
movable-area {
  border: 1px solid #000;
  width: 100%;
  height: 500rpx;
}
movable-view {
  width: 150rpx;
  height: 150rpx;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  background-color: #999;
  color: #fff;
}

上面代码运行后的效果如图5所示。

在这里插入图片描述
图5 页面元素拖拽后的效果

当拖拽页面元素时,会触发movable-view组件上的bindchange事件绑定的函数,在当前页面的Page构造器参数中定义了onViewChange() 方法,该方法上声明了options参数,可以通过该方法上的参数获取到拖拽后的坐标值以及元素移动的原因。onViewChange() 方法执行后,微信开发者工具控制台打印的效果如图6所示。

在这里插入图片描述
图6 元素拖拽后的参数打印效果

1.5 原生视图容器

小程序提供了cover-view和cover-image两个原生组件,帮助开发者实现对map、video、camera以及canvas等小程序原生组件的控制,可以使用cover-view和cover-image组件覆盖在其他原生组件上,从而修改这些原生组件的表现。

cover-view组件是覆盖在原生组件上的文本视图,cover-image组件是覆盖在原生组件之上的图片视图,两个组件都可以覆盖map、video、canvas、camera、live-player、live-pusher等原生组件。例如,我们可以使用cover-view组件与map组件,来实现地图上的自定义提示内容,示例代码如例5所示。

【例5】地图上的自定义提示

// index.wxml
<map
    latitude="{{latitude}}"
    longitude="{{longitude}}"
>
    <cover-view class="body">
        <cover-view class="tip">
            腾讯总部
        </cover-view>
    </cover-view>
</map>
// index.js
Page({
  data: {
    latitude: 23.099994,
    longitude: 113.324520,
  }
})
// index.wxss
map {
  width: 100%;
  height: 500rpx;
}
.body {
  height: 100%;
  width: 100%;
}
.tip {
  position: absolute;
  width: 250rpx;
  height: 80rpx;
  background: rgba(0, 0, 0, 0.4);
  color: #fff;
  bottom: 90rpx;
  left: 250rpx;
  display: flex;
  align-items: center;
  justify-content: center;
}

上面代码运行后的效果如图7所示。

在这里插入图片描述
图7 地图的自定义提示效果

2 基础组件

小程序提供的基础组件主要用于表示页面上的基础元素,一共有四种基础组件,包括text文本组件、rich-text富文本组件、progress进度条组件、icon图标组件。

2.1 文本组件

小程序的text文本组件提供了最基础的文本展示,与HTML中的 <span> 标签类似,属于行内元素。text文本组件提供了三个属性如表6所示。

在这里插入图片描述

在text文本组件的属性中,decode属性比较特殊,用于标签语言中转义字符文本的解码操作。由于各个操作系统的差异,某些转义字符的解析标准有所不同,例如空格的解析在各个系统中执行的标准不一致。decode属性可以解析以下常见的转移字符:

  • “&nbsp;”,表示半角的不断行空格
  • “&lt;”,表示左尖括号
  • “&gt;”,表示右尖括号
  • “&amp;”,表示特殊符号&
  • “&apos;”,表示单引号
  • “&ensp;”,表示半角的空格
  • “&emsp;”,表示全角的空格

text组件属于行内元素,与view组件不同,在text组件中只能嵌套text组件,不能嵌套view或其他组件。text文本组件的space属性有三个合法值,分别是ensp、emsp、nbsp,这三个值都是用来修饰文本中空格显示效果的,但是每个值显示的效果又不相同,具体可以参考decode转义字符中的“&ensp;”“&emsp;”“&nbsp;”

2.2 富文本组件

我们已经学习了view视图容器组件和text文本组件,这两个组件主要起到容器的作用,view相当于一个块级元素,text相当于一个行内元素,但是在开发过程中如果遇到了一些HTML中很常用的容器,而小程序基础组件中又没有定义的话,该如何实现呢?

在小程序中如果需要用到一些传统的HTML标签,例如使用到Table标签渲染一个表格,我们可以使用小程序基础组件提供的rich-text富文本组件来实现。rich-text富文本组件上有一个nodes属性,该属性的值有两种类型,一种是Array数组类型,一种是是String字符串类型。当值为Array数组类型时,数组中的元素是每个HTML节点对象,当值为String类型时,值的内容为字符串HTML标签。

当nodes属性的值为数组时,数组中的元素为node类型的节点对象,然后再通过rich-text富文本组件将node节点对象渲染成小程序的WXML组件。node节点对象有三个字段,分别是name(标签名)、attrs(属性)、children(子节点列表)。使用node节点对象渲染HTML的示例代码如例6所示。

【例6】使用node节点对象渲染HTML

// index.wxml
<view class="body">
    <view class="title">渲染后:</view>
    <rich-text nodes="{{nodes}}"></rich-text>
</view>
// index.js
Page({
  data: {
    nodes: [{
        name: 'div',
        attrs: {
          style: 'border: 1px dashed #000'
        },
        children: [
          { type: 'text', text: 'Hello World' }
        ]
    }]
  }
})
// index.wxss
.body {
  padding: 30rpx;
}
.title {
  margin-bottom: 30rpx;
}

上面代码运行后的效果如图8所示。

在这里插入图片描述
图8 使用node节点对象渲染HTML的效果

当rich-text富文本组件的nodes属性值为String字符串类型是,渲染 HTML的示例代码如例7所示。

【例7】渲染String类型的HTML

// index.wxml
<view class="body">
    <view class="title">渲染后:</view>
    <rich-text nodes="{{htmlSnip}}"></rich-text>
</view>
// index.js
Page({
  data: {
    htmlSnip: `
    <h3>表格标题</h3>
    <table style="border:1px dashed #000;" width="100%">
      <tr>
        <td class="table-td">A1</td>
        <td class="table-td">B1</td>
      </tr>
      <tr>
        <td class="table-td">A2</td>
        <td class="table-td">B2</td>
      </tr>
    </table>
    `
  }
})
// index.wxss
.body {
  padding: 30rpx;
}
.title {
  margin-bottom: 30rpx;
}
.table-td {
  border: 1px solid #000;
}

上面代码运行后的效果如图9所示。

在这里插入图片描述
图9 使用String类型渲染HTML的效果

2.3 进度条组件

在很多有文件上传和下载功能的页面中,当用户操作文件上传或下载时,需要在页面中以进度条的形式提醒用户当前文件上传或下载的进度。小程序的基础组件中也提供了progress进度条组件,组件属性的长度单位默认为px,从基础库版本2.4.0以后,长度单位开始支持rpx。progress进度条组件的属性如表7所示。

在这里插入图片描述

progress进度条组件的示例代码如例8所示。

【例8】progress进度条组件

// index.wxml
<view class="progress-box">
  <progress percent="20" show-info stroke-width="3"/>
</view>
<view class="progress-box">
  <progress percent="40" active stroke-width="3" />
  <icon class="progress-cancel" type="cancel"></icon>
</view>
<view class="progress-box">
  <progress percent="60" active stroke-width="3" />
</view>
<view class="progress-box">
  <progress percent="80" color="#10AEFF" active stroke-width="3" />
</view>
// index.wxss
.progress-box {
  padding: 20rpx;
  display: flex;
  margin: 20px 0rpx;
}
progress {
  width: 80%;
  margin-right: 20rpx;
}

运行上面代码后效果如图10所示。

在这里插入图片描述
图10 进度条组件效果

2.4 图标组件

小程序基础组件的icon图标组件是用法最为简单的一个组件,用于在页面中展示具有微信风格的一系列图标。在icon图标组件上可以通过type属性来设置图标的类型,type的值可以设置为:

  • success,成功,用于表示操作顺利完成;
  • success_no_circle,多选控件图标_已选择,用于多选控件中,表示已选择该项目;
  • info,提示,用于表示信息提示;也常用于缺乏条件的操作拦截,提示用户所需信息;
  • warn,警告,用于表示操作后将引起一定后果的情况;也用于表示由于系统原因而造成的负向结果;
  • waiting,等待,用于表示等待,告知用户结果需等待
  • cancel,停止或关闭,用于在表单中,表示关闭或停止
  • download,下载,用于表示可下载;
  • search,搜索,用于搜索控件中,表示可搜索;
  • clear,关闭,用法与cancel类似。

icon组件上还提供了size属性和color属性,使用这两个属性可以设置图标的尺寸大小和颜色,图标尺寸单位默认为px,从2.4.0版本基础库开始,图标尺寸单位也可以支持rpx。

小程序基础组件中提供的图标类型不算特别丰富,但是可以满足日常开发的基本图标使用需求,icon组件各种样式的图标使用代码如例9所示。

【例9】icon图标组件

// index.wxml
<view class="row">
    <icon type="success"></icon>
    <view class="icon-text">success,成功</view>
</view>
<view class="row">
    <icon type="success_no_circle"></icon>
    <view class="icon-text">success_no_circle,已选择</view>
</view>
<view class="row">
    <icon type="info"></icon>
    <view class="icon-text">info,信息</view>
</view>
<view class="row">
    <icon type="warn"></icon>
    <view class="icon-text">warn,警告</view>
</view>
<view class="row">
    <icon type="waiting"></icon>
    <view class="icon-text">waiting,等待</view>
</view>
<view class="row">
    <icon type="cancel"></icon>
    <view class="icon-text">cancel,关闭或停止</view>
</view>
<view class="row">
    <icon type="clear"></icon>
    <view class="icon-text">clear,关闭或停止</view>
</view>
<view class="row">
    <icon type="download"></icon>
    <view class="icon-text">download,下载</view>
</view>
<view class="row">
    <icon type="search"></icon>
    <view class="icon-text">search,搜索</view>
</view>
// index.wxss
.row {
  padding: 30rpx;
  display: flex;
}
.icon-text {
  margin-left: 20rpx;
}

上面代码运行后的效果如图11所示。

在这里插入图片描述
图11 小程序icon图标组件类型效果

3 表单组件

在购物网站中经常会遇到这种场景,当我们选购完商品后,提交订单时需要填写订单信息,例如收件人的收货信息,包括收件人姓名、电话、详细地址等。这些需要与用户交互的页面元素被称为表单元素,表单也是传统Web前端开发中很常见的一种交互方式,小程序也提供了表单类的组件,方便开发者实现用户交互的功能。

小程序提供的表单组件主要包括button(按钮)、checkbox(复选框)、input(输入框)、label(标签)、picker(滚动选择器)、radio(单选按钮)、switch(开关)、textarea(多行输入框)、slider(滑动选择器)、form(表单)等十个基础表单组件。但是在实际开发中,使用频率最高的是按钮、输入框、单选按钮、复选框等表单元素组件,下面对这几个最常用的表单元素组件做详细的介绍。

3.1 按钮

首先,我们先来看一下button按钮组件。按钮组件不仅可以使用在页面的表单中,实现数据提交的功能,还可以应用在很多场景中,例如作为触发某个功能的页面点击元素。
button按钮组件的属性如表8所示。

在这里插入图片描述

button按钮组件的事件如表9所示。

在这里插入图片描述

小程序表单组件提供的button按钮组件除了实现普通按钮的功能之外,还具有获取微信开发能力,通过设置组件上的open-type属性值来实现获取不同的微信开发能力。open-type属性的合法值有以下几种类型:

  • 当值为contact时,表示打开客服会话;
  • 当值为share时,表示触发用户转发;
  • 当值为getPhoneNumber,表示获取用户手机号;
  • 当值为getUserInfo时,表示获取用户信息;
  • 当值为launchApp时,表示打开App,通过app-parameter属性设定向APP传的参数;
  • 当值为openSetting时,表示打开授权设置页;
  • 当值为feedback时,表示打开“意见反馈”页面;
  • 当值为chooseAvatar时,表示获取用户头像。

开发者还可以通过button按钮组件上的属性设置按钮的风格样式,例如设置loading属性的值为true时,可以在按钮上添加loading加载的图标,表示当前处于加载状态。我们可以使用loading属性模拟小程序文件下载的效果,示例代码如例10所示。

【例10】动态设置按钮loading状态

// index.wxml
<button 
    loading="{{isLoading}}"
    type="primary"
    bindtap="onLoading"
>{{btnText}}</button>
// index.js
Page({
  data: {
    btnText: '点击下载',
    isLoading: false
  },
  onLoading() {
    this.setData({
      btnText: '下载中',
      isLoading: true
    }, () => {
      setTimeout(() => {
        this.setData({
          btnText: '下载完成',
          isLoading: false
        })
      }, 2000)
    })
  }
})

上面代码运行后的页面显示效果如图12所示。

在这里插入图片描述
图12 页面显示效果

在例10中,为页面的button组件定义了loading属性用于控制页面的加载状态显示,并且为组件定义了一个点击事件,当点击按钮时,触发Page构造器参数中的onLoading()方法,同时修改按钮的文本为“下载中”,修改按钮为加载状态。在onLoading()方法中添加了一个定时器,当点击按钮2秒之后,将按钮文本修改为“下载完成”,同时取消按钮的加载状态。按钮点击后的效果如图13所示,过2秒之后按钮的显示效果如图14所示。

在这里插入图片描述
图13 按钮点击后的效果

在这里插入图片描述
图14 点击2秒后的效果

3.2 输入框

input输入框组件是表单组件中非常重要,也是最基础的一个组件。input输入框是页面实现用户交互的常用组件,可以用户收集用户输入的信息。input输入框组件提供了非常多的属性和事件,方便开发者控制输入框的表现。
input输入框组件的属性如表10所示。

在这里插入图片描述

input输入框组件的事件如表11所示。

在这里插入图片描述

input输入框组件使用的示例代码如例11所示。

【例11】input输入框组件示例代码

// index.wxml
<view class="page-section">
    <view class="weui-cells__title">验证码</view>
    <view class="weui-cells weui-cells_after-title">
      <view class="weui-cell weui-cell_input">
        <input 
          class="weui-input"
          auto-focus
          placeholder="输入验证码"
          type="number"
          bindconfirm="onSubmit"
        />
      </view>
    </view>
  </view>
// index.js
Page({
  data: {
    qrCode: ''
  },
  onSubmit(event) {
    this.setData({
      qrCode: event.detail.value
    }, () => {
      console.log('用户输入验证码为:', this.data.qrCode);
    })
  }
})
// index.wxss
.page-section {
    background-color: #eee;
    height: 100rpx;
    display: flex;
    align-items: center;
}
.weui-cells__title {
    margin: 0rpx 20rpx;
}

在例11中,为input输入框组件添加了type属性,并将其值设置为“number”,然后点击工具栏中的“真机调试”按钮,在手机上显示的小程序效果如图15所示。

在这里插入图片描述
图15 小程序真机调试效果

当type属性值为number时,输入框获取焦点会自动弹出数字键盘,这也是input组件提供的特殊功能。type属性的合法值如下:

  • 当值为text时,表示文本输入键盘;
  • 当值为number时,表示数字输入键盘;
  • 当值为idcard时,表示身份证输入键盘;
  • 当值为digit时,表示带小数点的数字键盘;
  • 当值为safe-password时,表示 密码安全输入键盘指引;
  • 当值为nickname时,表示昵称输入键盘;

在例11的代码中,还为input组件添加了一个bindconfirm事件,当输入完成后点击确定按钮,会调用Page构造器参数中定义的onSubmit()事件方法,然后在微信开发者工具控制台打印相关结果,控制台输出效果如图16所示。

在这里插入图片描述
图16 控制台打印效果

3.3 单选按钮

radio单选框组件用于表单中的单选操作,在使用多个radio单选框组件时,需要将radio单选框组件嵌套在radio-group组件中,并且在radio-group组件上定义bindchange事件,用于监听单选框值的改变。
radio组件的属性相对比较简单,如表12所示。

在这里插入图片描述

radio组件上没有事件,一组radio单选框的数据改变,全都由radio-group组件的change事件进行监听并处理。小程序单选框组件的示例代码如例12所示。

【例12】radio单选框组件示例代码

// index.wxml
<view class="page-section">
  <view class="page-section-title">请选择年级</view>
  <view class="weui-cells">
    <radio-group bindchange="radioChange">
      <label class="weui-cell" wx:for="{{items}}" wx:key="index">
        <view class="weui-cell__hd">
          <radio value="{{item.value}}" />
        </view>
        <view class="weui-cell__bd">{{item.label}}</view>
      </label>
    </radio-group>
  </view>
</view>
// index.js
Page({
  data: {
    items: [
      { label: '一年级', value: '1'},
      { label: '二年级', value: '2'},
      { label: '三年级', value: '3'},
      { label: '四年级', value: '4'},
      { label: '五年级', value: '5'}
    ],
    activeItem: ''
  },
  radioChange(event) {
    this.setData({
      activeItem: event.detail.value
    }, () => {
      console.log('当前选中:', this.data.activeItem);
    })
  }
})
// index.wxss
.page-section {
    padding: 30rpx;
}
.page-section-title {
    font-weight: bold;
    margin-bottom: 30rpx;
}
.weui-cells {
    padding-left: 30rpx;
}
.weui-cell {
    display: flex;
    align-items: center;
    height: 130rpx;
    border-bottom: 1px solid #eee;
}
.weui-cell__bd {
    margin-left: 25rpx;
}

在例12中,为radio-group组件上添加了一个bindchange事件,当单选框被选中时,会触发Page构造器参数中定义的radioChange()事件方法,选中效果如图17所示。单选框组件选中事件触发后,会在微信开发者工具的控制台中打印相关的选择结果,控制台打印效果如图18所示。

在这里插入图片描述
图17 单选框选中效果

在这里插入图片描述
图18 控制台打印效果

3.4 复选框

checkbox复选框与radio单选框组件的使用方法很相似,也需要把多个checkbox组件的外层用checkbox-group组件包裹起来,checkbox-group组件上同样可以定义一个bindchange事件来监听复选框的改变。checkbox复选框组件上也有四个属性,如表13所示。

在这里插入图片描述

checkbox复选框组件的用法与radio单选框组件一样,示例代码如例13所示。

【例13】checkbox复选框组件示例代码

// index.wxml
<view class="page-section">
  <view class="page-section-title">选择体育特长:</view>
  <view class="weui-cells">
    <checkbox-group bindchange="checkboxChange">
      <label class="weui-cell" wx:for="{{items}}" wx:key="index">
        <view class="weui-cell__hd">
          <checkbox value="{{item}}" />
        </view>
        <view class="weui-cell__bd">{{item}}</view>
      </label>
    </checkbox-group>
  </view>
</view>
// index.js
Page({
  data: {
    items: ['篮球', '足球', '排球', '乒乓球', '羽毛球'],
    activeItem: []
  },
  checkboxChange(event) {
    this.setData({
      activeItem: event.detail.value
    }, () => {
      console.log('当前选中:', this.data.activeItem);
    })
  }
})
// index.wxss
.page-section {
    padding: 30rpx;
}
.page-section-title {
    font-weight: bold;
    margin-bottom: 30rpx;
}
.weui-cells {
    padding-left: 30rpx;
}
.weui-cell {
    display: flex;
    align-items: center;
    height: 130rpx;
    border-bottom: 1px solid #eee;
}
.weui-cell__bd {
    margin-left: 25rpx;
}

在例13中,为checkbox-group组件上添加了一个bindchange事件,当复选框被选中时,会触发Page构造器参数中定义的checkboxChange()事件方法,选中效果如图19所示。复选框组件选中事件触发后,会在微信开发者工具的控制台中打印相关的选择结果,控制台打印效果如图20所示。

在这里插入图片描述
图19 复选框选中效果

在这里插入图片描述
图20 控制台打印效果

3.5 选择器

微信小程序的表单组件提供了三种选择器,分别是picker滚动选择器组件、slider滑动选择器组件、switch开关选择器组件。
picker滚动选择是从底部弹起的可用手指上下滑动选项的一种选择器组件,其属性如表14所示。

在这里插入图片描述

除了上述通用的属性,对于不同的mode,picker拥有不同的属性,mode的可选值有:

picker滚动选择器组件提供了bindcancel事件,在用户取消选择时触发。picker滚动选择器组件的示例代码如例14所示。

【例14】picker滚动选择器示例代码

// index.wxml
<view class="section">
  <view class="section__title">选择热门城市:</view>
  <picker bindchange="bindPickerChange" value="{{city}}" range="{{array}}">
    <view class="picker">
      {{city ? city : '点击选择'}}
    </view>
  </picker>
</view>
// index.js
Page({
  data: {
    array: ['北京', '上海', '广州', '杭州', '西安', '武汉'],
    city: ''
  },
  bindPickerChange(event) {
    this.setData({
      city: this.data.array[event.detail.value]
    }, () => {
      console.log('当前选中:', this.data.city);
    })
  }
})
// index.wxss
.section {
    padding: 30rpx;
    display: flex;
}
.section__title {
    font-weight: bold;
    margin-bottom: 20rpx;
}

上面代码执行后页面显示的效果如图20所示。

在这里插入图片描述
图20 滚动选择器组件效果

slider滑动选择器组件通常用于数字的快速赋值与展示操作,用户可以通过手指滑动slider组件上的滑块实现数字的输入操作。其核心属性如表15所示。

在这里插入图片描述

可以通过slider滑块选择器组件上的bindchange事件监听用户滑动的结果,还可以用组件上的bindchanging事件来监听用户的滑动过程。slider滑块选择器组件的示例代码如例15所示。

【例15】slider滑块选择器示例代码

// index.wxml
<view class="section">
  <text class="section__title">设置屏幕亮度:</text>
  <view class="body-view">
    <slider 
      bindchange="sliderChange"
      show-value
      value="{{ defaultValue }}"
    />
  </view>
</view>
// index.js
Page({
  data: {
    defaultValue: 30,
    value: 0
  },
  sliderChange(event) {
    this.setData({
      value: event.detail.value
    }, () => {
      console.log('设置的值:', this.data.value);
    })
  }
})
// index.wxss
.section {
    padding: 30rpx;
}
.section__title {
    font-weight: bold;
    margin-bottom: 30rpx;
}

上面代码执行后页面显示的效果如图21所示。

在这里插入图片描述
图21 滑块选择器组件效果

switch开关选择器组件是三种选择器组件中最常用的一种组件,一般用于快速获取用户输入的boolean类型的值。switch开关选择器组件上有四个属性,如表16所示。

在这里插入图片描述

可以通过switch组件上的bindchange事件监听用户的操作,示例代码如例16所示。

【例16】switch开关选择器组件示例代码

// index.wxml
<view class="section">
  <text class="section__title">消息推送:</text>
  <view class="body-view">
    <switch checked="{{switchChecked}}" bindchange="switchChange"/>
    <text>{{ switchChecked ? '开启' : '关闭' }}</text>
  </view>
</view>
// index.js
Page({
  data: {
    switchChecked: true
  },
  switchChange(event) {
    this.setData({
      switchChecked: event.detail.value
    }, () => {
      console.log('设置的值:', this.data.switchChecked);
    })
  }
})
// index.wxss
.section {
    padding: 30rpx;
    display: flex;
}
.section__title {
    font-weight: bold;
    margin-bottom: 30rpx;
}

上面代码执行后页面显示的效果如图22所示。

在这里插入图片描述
图22 开关选择器组件效果

3.6 form 表单

微信小程序的表单组件中提供了form组件,用于提交页面中的所有表单元素数据,在form组件中可以嵌入所有的表单元素组件,例如输入框组件、复选框组件、单选框组件以及选择器组件等。form组件上提供了两个事件,一个是bindsubmit事件,用于触发表单数据的提交;另一个是bindreset事件,用于重置表单中所有元素组件的数据。

虽然form组件提供了bindsubmit事件用于获取完整的表单数据,但是对某些表单元素的值进行校验时,还需要在表单元素的组件上添加对应的监听事件。form表单的示例代码如例17所示。

【例17】form表单示例代码

// index.wxml
<view class="form-body">
    <view class="form-title">个人资料</view>
    <form catchsubmit="formSubmit" catchreset="formReset">
      <view class="form-item">
        <view class="form-item-title">姓名:</view>
        <input name="name" placeholder="请输入" bindinput="onNameInput" />
      </view>
      <view class="form-item">
        <view class="form-item-title">性别:</view>
        <radio-group name="sex" bindchange="onSexChange">
          <label><radio value="" checked/></label>
          <label><radio value=""/></label>
        </radio-group>
      </view>
      <view class="form-item">
        <view class="form-item-title">特长:</view>
        <checkbox-group name="hobby" bindchange="onHobbyChange">
          <label><checkbox value="运动"/>运动</label>
          <label><checkbox value="艺术"/>艺术</label>
          <label><checkbox value="科技"/>科技</label>
        </checkbox-group>
      </view>
      <view class="form-item">
        <view class="form-item-title">城市:</view>
        <picker bindchange="onCityChange" range="{{citys}}" name="city">
          <view class="picker">
            {{ user.city ? user.city : '点击选择'}}
          </view>
        </picker>
      </view>
      <view class="btn-area">
        <button type="primary" formType="submit">提交</button>
        <button formType="reset">重置</button>
      </view>
    </form>
  </view>
// index.js
Page({
  data: {
    user: {
      name: '',
      sex: '',
      hobby: [],
      city: ''
    },
    citys: ['北京', '上海', '广州', '杭州']
  },
  onNameInput(event) {
    const user = {...this.data.user}
    user.name = event.detail.value
    this.setData({ user })
  },
  onSexChange(event) {
    const user = {...this.data.user}
    user.sex = event.detail.value
    this.setData({ user })
  },
  onHobbyChange(event) {
    const user = {...this.data.user}
    user.hobby = event.detail.value
    this.setData({ user })
  },
  onCityChange(event) {
    const user = {...this.data.user}
    user.city = this.data.citys[event.detail.value]
    this.setData({ user })
  },
  formSubmit(event) {
    console.log('表单的数据:', event.detail.value)
  },
  formReset() {
    const user = {...this.data.user}
    user.city = ''
    this.setData({ user })
  }
})
// index.wxss
.form-body {
    padding: 30rpx;
}
.form-title  {
    font-weight: bold;
    text-align: center;
    margin-bottom: 30rpx;
}
.form-item {
    display: flex;
    align-items: center;
    height: 120rpx;
    border-bottom: 1px solid #eee;
}
.form-item-title {
    font-weight: bold;
    margin-right: 30rpx;
}
.btn-area button {
    margin: 30rpx 0rpx;
}
label {
    margin-right: 20rpx;
}

上面代码执行后页面显示的效果如图23所示。

在这里插入图片描述
图23 表单页面效果

当点击页面中的“提交”按钮时,会触发Page构造器参数中定义的formSubmit()事件方法,并且在微信开发者工具的控制台打印相关的内容,控制台打印效果如图24所示。

在这里插入图片描述
图24 控制台打印效果

4 导航组件

在浏览器的前端开发中,可以使用 <a> 标签实现页面之间的跳转,在小程序中提供了一个用于页面跳转的组件,就是navigator组件,用于创建页面链接。navigator组件上提供了一个target属性,用于设置跳转目标,在当前小程序页面中可以使用navigator组件跳转到其他页面中,也可以跳转到另一个小程序中。target属性有两个值,一个值是self,表示在当前小程序中跳转,另一个值是miniProgram,表示在其他小程序中跳转。

navigator组件的属性如表17所示。

在这里插入图片描述

在使用navigator组件实现页面跳转时,可以通过组件上的open-type属性来指定页面跳转的方式,open-type属性的合法值包括:

  • 当值为navigate时,表示保留当前页面,跳转到应用内的某个页面;
  • 当值为redirect时,表示关闭当前页面,跳转到应用内的某个页面;
  • 当值为switchTab时,表示跳转到 tabBar 页面,并关闭其他所有非 tabBar 页面;
  • 当值为reLaunch时,表示关闭所有页面,打开到应用内的某个页面;
  • 当值为navigateBack时,表示关闭当前页面,返回上一页面或多级页面;
  • 当值为exit时,表示退出小程序。

navigator组件还提供了三个事件,如表18所示

在这里插入图片描述

从小程序基础库 2.3.0 版本开始,如果使用navigator组件跳转到其他小程序,在跳转至其他小程序前,会在跳转前的页面中弹框提示,询问用户是否跳转,只有当用户确认后才可以跳转其他小程序。

使用navigator组件实现页面跳转的示例代码如例18所示。

【例18】navigator组件实现页面跳转

// pages/index/index.wxml
<view class="btn-area">
  <navigator 
    url="../my/my" 
    hover-class="navigator-hover" 
    open-type="navigate"
  >
    跳转
  </navigator>
</view>

// pages/my/my.wxml
<view>这是个人中心页面</view>

上面代码运行后会直接显示pages/index/index.wxml页面,显示效果如图25所示。

在这里插入图片描述
图25 首页显示效果

当点击小程序首页中的“跳转”文本时,会触发navigator组件的跳转事件,然后跳转到navigator组件上url属性指向的页面,跳转后的效果如图26所示。

在这里插入图片描述
图26 跳转后的页面

navigator组件上的open-type属性用于设置跳转的方式,如果没有声明该属性的话,会默认按照navigate方式跳转页面。

5 媒体组件

5.1 音视频

我们在日常生活中,经常会使用到手机上的音乐播放器听几首喜欢的歌曲,或者是打开某个视频播放软件看电视剧和电影等。在小程序中也提供了相关的组件,帮助开发者快速实现在小程序内的音视频播放功能。小程序提供了两个组件,分别实现音频播放和视频播放功能,这两个组件是audio音频组件和video视频组件。

小程序audio音频组件的属性如表19所示。

在这里插入图片描述

audio音频组件的事件如表20所示。

在这里插入图片描述

当音频播放发生错误时,会触发audio组件上的binderror事件,通过该事件上的默认参数中MediaError.code的值来判断发生错误的原因,不同错误码表示的意义如下:

  • 错误码为1时,表示获取资源被用户禁止;
  • 错误码为2时,表示网络错误;
  • 错误码为3时,表示解码错误;
  • 错误码为4时,表示不合适资源。

在小程序中添加音频控件的示例代码如例19所示。

【例19】audio音频组件示例代码

// index.wxml
<view class="audio-container">
    <audio 
        poster="{{poster}}" 
        name="{{name}}" 
        author="{{author}}" 
        src="{{src}}" 
        id="myAudio" 
        controls 
        loop
    />
    <view class="btns">
        <button type="primary" bindtap="audioPlay">播放</button>
        <button type="warn" bindtap="audioPause">暂停</button>
    </view>
</view>
// index.js
Page({
  onReady: function (e) {
    this.audioCtx = wx.createAudioContext('myAudio')
  },
  data: {
    poster: '/images/001.jpg',
    name: '小清新抒情背景音乐',
    author: '来源:网络',
    src: '/audio/123.mp3',
  },
  audioPlay: function () {
    this.audioCtx.play()
  },
  audioPause: function () {
    this.audioCtx.pause()
  }
})
// index.wxss
view {
  text-align: center;
}
.btns {
  display: flex;
  margin-top: 30rpx;
}

上面代码执行后的页面效果如图27所示。

在这里插入图片描述
图27 音频播放页面效果

例19中的音频文件引用的是项目本地的.mp3文件,也可以引用网络中的音频链接,代码中的配图文件引用方法与音频文件类似。

小程序中还提供了一个video组件用于在页面中播放视频文件,video组件的属性比音频组件的属性要复杂,video组件的部分属性如表21所示。

在这里插入图片描述

video视频组件的诗句如表22所示。

在这里插入图片描述

运行在不同系统平台上小程序对视频文件格式和视频编码格式的支持情况也是不一样的,相比较来说,iOS系统比Android系统支持的视频文件格式要多一些,但是对于视频的编码格式,Android系统全部支持,而iOS系统仅支持一部分编码格式。关于iOS和Android两大系统平台上的小程序对视频文件格式支持情况如表23所示。

在这里插入图片描述

iOS和Android两大系统平台的小程序对视频编码格式支持的情况如表24所示。

在这里插入图片描述

video视频组件在小程序页面中默认渲染的宽度为300px,默认高度为225px,开发者也可以通过WXSS设置视频控件的宽高。小程序中播放视频的示例代码如例20所示。

【例20】video视频组件的示例代码

// index.wxml
<view class="page-body">
  <view class="page-section tc">
    <video
      id="myVideo" 
      src="{{src}}" 
      danmu-list="{{danmuList}}" 
      enable-danmu 
      danmu-btn 
      show-center-play-btn='{{false}}' 
      show-play-btn="{{true}}" 
      controls
      picture-in-picture-mode="{{['push', 'pop']}}"
    ></video>
    <view class="message-body">
        <input
            class="weui-input"
            type="text"
            placeholder="输入你想说的话"
            bindinput="inputMessage"
        />
        <view
            bindtap="onSendDanmu"
            class="page-body-button"
            type="primary"
        >发送</view>
    </view>
  </view>
</view>
// index.js
Page({
  data: {
    src: 'http://wxsnsdy.tc.qq.com/105/20210/snsdyvideodownload?filekey=30280201010421301f0201690402534804102ca905ce620b1241b726bc41dcff44e00204012882540400&bizid=1023&hy=SH&fileparam=302c020101042530230204136ffd93020457e3c4ff02024ef202031e8d7f02030f42400204045a320a0201000400',
    message: '',
    danmuList:
    [{
      text: '第 1s 出现的弹幕',
      color: '#ff0000',
      time: 1
    }, {
      text: '第 3s 出现的弹幕',
      color: '#ff00ff',
      time: 3
    }],
    videoContext: null
  },
  onReady() {
    const videoContext = wx.createVideoContext('myVideo')
    this.setData({ videoContext })
  },
  inputMessage(event) {
    this.setData({
      message: event.detail.value
    })
  },
  onSendDanmu() {
    this.data.videoContext.sendDanmu({
      text: this.data.message,
      color: '#ff00ff'
    })
  }
})
// index.wxss
.message-body {
    padding: 30rpx;
    display: flex;
}
.message-body input {
    background-color: #eee;
    margin: 0rpx 20rpx;
    height: 80rpx;
    width: 80%;
}
.page-body-button {
    background-color: #37f;
    color: #fff;
    width: 150rpx;
    height: 80rpx;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 10rpx;
}

上面代码执行后的页面显示效果如图28所示。

在这里插入图片描述
图28 视频播放器页面显示效果

在例20中的video组件上声明了danmu-list属性,用于显示弹幕信息,用户还可以在输入框中编辑弹幕内容,然后点击“发送”按钮即可在屏幕中发送弹幕,弹幕显示的效果如图29所示。

在这里插入图片描述
图29 发送弹幕效果

5.2 图片显示

image组件是小程序提供的用于在页面中显示图片的一个媒体组件,支持JPG、PNG、SVG、WEBP、GIF等图片格式的显示。image图片组件的属性如表25所示。

在这里插入图片描述

image组件默认宽度为320px,高度为240px,组件上的mode属性用于图片显示时采用的裁剪或缩放模式。

图片组件上还提供了一个用于控制长按图片的属性show-menu-by-longpress,当该属性的值为true时,开启图片长按功能,如果图片为二维码,可以直接识别二维码内容。小程序中长按二维码图片时,支持识别的二维码包括:小程序码、微信个人码、企业微信个人码、普通群码、互通群码、公众号二维码等,不过仅在wx.previewImage中支持图片的长按识别。

小程序的image图片组件上还可以定义两个事件binderror和bindload,binderror事件在图片加载异常时触发,bindload事件在图片加载完成时触发。

在小程序页面中加载图片的示例代码如例21所示。

【例21】image图片组件示例代码

// index.wxml
<view>
    <image
        src="/images/001.jpg"
        mode="aspectFill"
    ></image>
</view>
// index.wxss
view{
    padding: 30rpx;
}
image {
    width: 400rpx;
    height: 400rpx;
}

上面代码执行后的页面效果如图30所示。

在这里插入图片描述
图30 图片显示的页面效果

5.3 系统相机

在小程序内调用手机的相机能力也是小程序提供的基础能力之一,在小程序中可以通过camera组件实现调用系统相机的功能,用户可以通过相机实现拍照和扫描二维码。camera组件的属性如表26所示。

在这里插入图片描述

小程序的camera相机组件上的mode属性可以设置相机的使用模式,当mode属性值为normal时,表示开启相机模式,用户可以使用相机拍照和录像;当mode属性值为scanCode时,表示开启扫码模式,用户可以使用相机扫描二维码。
camera相机组件还提供了四个事件,具体事件如表27所示。

在这里插入图片描述

在使用camera相机组件时,需要注意,在小程序的同一个页面中只能插入一个camera组件。小程序中开启相机能力的示例代码如例22所示。

【例22】camera相机组件示例代码

// index.wxml
<camera 
    device-position="back"
    flash="off"
    binderror="error"
    style="width: 100%; height: 300px;"></camera>
<button type="primary" bindtap="takePhoto">拍照</button>
<view>预览</view>
<image mode="widthFix" src="{{src}}"></image>
// index.js
Page({
  takePhoto() {
    const ctx = wx.createCameraContext()
    ctx.takePhoto({
      quality: 'high',
      success: (res) => {
        this.setData({
          src: res.tempImagePath
        })
      }
    })
  },
  error(e) {
    console.log(e.detail)
  }
})

在微信开发者工具中无法查看相机开启的效果,只能通过预览或真机调试在手机上查看相机的开启效果。

6 地图组件

地图和导航功能已经成为大部分出行类移动应用的必备功能之一,小程序提供了map地图组件方便开发者在小程序应用中快速实现地图功能。小程序的map地图组件是基于腾讯地图的开放能力,在小程序中实现快速渲染地图的一种高级能力,开发者可以根据自身产品的使用场景以及UI风格,选取或者创建风格匹配的地图样式。

小程序map组件提供的属性和API,可以快速创建任何需要的地图展示能力,降低开发成本。map组件提供了大量的属性和事件,其中部分核心属性如表28所示。

在这里插入图片描述

map地图组件提供的事件如表29所示。

在这里插入图片描述

小程序中使用地图组件的示例代码如例23所示。

【例23】map地图组件示例代码

// index.wxml
<view class="map-container">
    <map
        latitude="{{latitude}}"
        longitude="{{longitude}}"
        markers="{{markers}}"
        scale="{{scale}}"
        bindcontroltap="tapControl"
        bindregionchange="regionChange"
    ></map>
</view>
// index.js
Page({
  data: {
    latitude: 22.540822,
    longitude: 113.934457,
    scale: 16,
    markers: [
      {
        latitude: 22.540822,
        longitude: 113.934457,
        label: {
          content: '这里是腾讯大厦',
          color: '#333',
          borderWidth: 1,
          borderColor: '#000',
          bgColor: '#fff',
          padding: 5,
          textAlign: 'right',
          borderRadius: 5
        }
      }
    ]
  }
})

上面代码执行后页面效果如图31所示。

在这里插入图片描述
图31 地图组件页面显示效果

7 本章小结

本章介绍了小程序自定义组件的创建于使用,以及小程序官方组件的属性与事件,并结合案例方便初学者快速上手。组件开发是小程序应用的必备技能之一,大家要熟练掌握小程序官方组件的使用,利用各种组件提供的能力,完成项目需求。

  • 13
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

柯晓楠

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值