第一章至第六章总结

第一章

认识微信小程序

简介:

微信小程序,小程序的一种,英文名Wechat Mini Program,是一种不需要下载安装即可使用的应用,它实现了应用“触手可及”的梦想,用户扫一扫或搜一下即可打开应用。也是一项创新,经过将近两年的发展,已经构造了新的微信小程序开发环境和开发者生态。微信小程序也是这么多年来中国IT行业里一个真正能够影响到普通程序员的创新成果,已经有超过150万的开发者加入到了微信小程序的开发,与腾讯一起共同发力推动微信小程序的发展,微信小程序应用数量超过了一百万,覆盖200多个细分的行业,日活用户达到两个亿,微信小程序还在许多城市实现了支持地铁、公交服务。微信小程序发展带来更多的就业机会,2017年小程序带动就业104万人,社会效应不断提升。

优势:

1、用户体验好:便捷地获取服务,无需安装卸载,即用即走;

2、流量获取易:背靠10亿+微信用户;

3、开发成本低:节省大量资金、时间、人力,从而做好自己的产品;

4、微信生态强:微信生态体系、多渠道实现营销推广,节省推广成本;

5、具有更丰富的功能和出色的使用体验,也会降低用户的使用难度;

场景:一种轻量级的应用服务形式,在线下的使用场景中能发挥大的作用。

代码

index.json

{
  "usingComponents": {
  }
}

index.tx

// index.ts
// 获取应用实例
const app = getApp<IAppOption>()
const defaultAvatarUrl = 'https://mmbiz.qpic.cn/mmbiz/icTdbqWNOwNRna42FI242Lcia07jQodd2FJGIYQfG0LAJGFxM4FbnQP6yfMxBgJ0F3YRqJCJ1aPAK2dQagdusBZg/0'

Component({
  data: {
    motto: 'Hello World',
    userInfo: {
      avatarUrl: defaultAvatarUrl,
      nickName: '',
    },
    hasUserInfo: false,
    canIUseGetUserProfile: wx.canIUse('getUserProfile'),
    canIUseNicknameComp: wx.canIUse('input.type.nickname'),
  },
  methods: {
    // 事件处理函数
    bindViewTap() {
      wx.navigateTo({
        url: '../logs/logs',
      })
    },
    onChooseAvatar(e: any) {
      const { avatarUrl } = e.detail
      const { nickName } = this.data.userInfo
      this.setData({
        "userInfo.avatarUrl": avatarUrl,
        hasUserInfo: nickName && avatarUrl && avatarUrl !== defaultAvatarUrl,
      })
    },
    onInputChange(e: any) {
      const nickName = e.detail.value
      const { avatarUrl } = this.data.userInfo
      this.setData({
        "userInfo.nickName": nickName,
        hasUserInfo: nickName && avatarUrl && avatarUrl !== defaultAvatarUrl,
      })
    },
    getUserProfile() {
      // 推荐使用wx.getUserProfile获取用户信息,开发者每次通过该接口获取用户个人信息均需用户确认,开发者妥善保管用户快速填写的头像昵称,避免重复弹窗
      wx.getUserProfile({
        desc: '展示用户信息', // 声明获取用户个人信息后的用途,后续会展示在弹窗中,请谨慎填写
        success: (res) => {
          console.log(res)
          this.setData({
            userInfo: res.userInfo,
            hasUserInfo: true
          })
        }
      })
    },
  },
})

index.wxml

<!--index.wxml-->
<scroll-view class="scrollarea" scroll-y type="list">
  <view class="container">
    <view class="userinfo">
      <block wx:if="{{canIUseNicknameComp && !hasUserInfo}}">
        <button class="avatar-wrapper" open-type="chooseAvatar" bind:chooseavatar="onChooseAvatar">
          <image class="avatar" src="{{userInfo.avatarUrl}}"></image>
        </button>
        <view class="nickname-wrapper">
          <text class="nickname-label">昵称</text>
          <input type="nickname" class="nickname-input" placeholder="请输入昵称" bind:change="onInputChange" />
        </view>
      </block>
      <block wx:elif="{{!hasUserInfo}}">
        <button wx:if="{{canIUseGetUserProfile}}" bindtap="getUserProfile"> 获取头像昵称 </button>
        <view wx:else> 请使用2.10.4及以上版本基础库 </view>
      </block>
      <block wx:else>
        <image bindtap="bindViewTap" class="userinfo-avatar" src="{{userInfo.avatarUrl}}" mode="cover"></image>
        <text class="userinfo-nickname">{{userInfo.nickName}}</text>
      </block>
    </view>
    <view class="usermotto">
      <text class="user-motto">{{motto}}</text>
    </view>
  </view>
</scroll-view>

index.wxss

/**index.wxss**/
page {
  height: 100vh;
  display: flex;
  flex-direction: column;
}
.scrollarea {
  flex: 1;
  overflow-y: hidden;
}

.userinfo {
  display: flex;
  flex-direction: column;
  align-items: center;
  color: #aaa;
  width: 80%;
}

.userinfo-avatar {
  overflow: hidden;
  width: 128rpx;
  height: 128rpx;
  margin: 20rpx;
  border-radius: 50%;
}

.usermotto {
  margin-top: 200px;
}

.avatar-wrapper {
  padding: 0;
  width: 56px !important;
  border-radius: 8px;
  margin-top: 40px;
  margin-bottom: 40px;
}

.avatar {
  display: block;
  width: 56px;
  height: 56px;
}

.nickname-wrapper {
  display: flex;
  width: 100%;
  padding: 16px;
  box-sizing: border-box;
  border-top: .5px solid rgba(0, 0, 0, 0.1);
  border-bottom: .5px solid rgba(0, 0, 0, 0.1);
  color: black;
}

.nickname-label {
  width: 105px;
}

.nickname-input {
  flex: 1;
}

运行结果

​微信小程序功能

组件

框架为开发者提供了一系列基础组件,开发者可以通过组合这些基础组件进行快速开发。基础组件分为以下八大类:

  1. 视图容器
  2. 基础内容
  3. 表单
  4. 操作反馈
  5. 导航
  6. 多媒体
  7. 地图
  8. 画布

第二章

 小程序的基本目录结构

 pages 用来存放所有小程序的页面
 utils 用来存放工具性质的模块
 app.js 小程序的项目入口地址
 app.json 小程序项目的全局配置文件,“包括小程序中的所有页面路径,窗口外观,界面表现,底部tab等”。
 app.wxss 小程序项目的全局样式文件
 project.config.json 项目的配置文件,用来记录对小程序开发工具的个性化配置
 sitemap.json 用来配置小程序及其页面是否允许被微信索引

2.小程序的页面组成部分

然后每个页面又包括四个组成部分,.js,.json,.wxml,.wxss

1..js 文件,(页面的脚本文件,存放页面的数据,事件处理函数等)
2..json文件(当前页面的配置文件,配置窗口的外观,表现等)
3..wxml文件(页面的模板结构文件)其实就是web开发中的HTML文件
4..wxss文件 (当前页面的样式表文件)也就是传统的css,基本差不多

2.1什么是视图层

小程序的开发框架

框架的视图层由WXMKL(WeiXin Markup language)与WXSS(WeiXin Style Sheet)编写,由组件进行展示。

  对于微信小程序而言,视图层就是所有.wxml文件与.wxss文件的集合

  微信小程序在逻辑层将数据进行处理后发送给视图层展现出来,同时接受视图层的事件反馈。

  .wxml文件用于描述页面的结构。

  .wxss文件用于描述页面的样式。

  视图层以给定的样式展现数据并将时间反馈给逻辑层,而数据展现是以组件来进行的。组件(Component)是视图的基本单元,是构建.wxml文件必不可少的。

  对于小程序的WXML编码开发,我们基本上可以认为就是使用组件、结合时间系统,构建页面结构的过程。.wxml文件中所绑定的数据,均来自于对应页的.js文件中Page方法的data对象。

WXML

  WXML是框架设计的一套类似HTML的标签语言,结合基础组件、事件系统,可以构建出页面的结构,即.wxml文件。

 (WeiXin Style Sheets)是一套样式语言,用于描述 WXML 的组件样式。

WXSS

WXSS 用来决定 WXML 的组件应该怎么显示。

与 CSS 相比,WXSS 扩展的特性有:单位尺寸和样式导入

2.2 什么是逻辑层

小程序开发框架的逻辑层使用 JavaScript 引擎为小程序提供开发者 JavaScript 代码的运行环境以及微信小程序的特有功能。

逻辑层将数据进行处理后发送给视图层,同时接受视图层的事件反馈。

开发者写的所有代码最终将会打包成一份 JavaScript 文件,并在小程序启动的时候运行,直到小程序销毁。这一行为类似 ServiceWorker,所以逻辑层也称之为 App Service。

在 JavaScript 的基础上,我们增加了一些功能,以方便小程序的开发:

1.增加 App 和 Page 方法,进行程序注册和页面注册。
2.增加 getApp 和 getCurrentPages 方法,分别用来获取 App 实例和当前页面栈。
3.提供丰富的 API,如微信用户数据,扫一扫,支付等微信特有能力。
4.提供模块化能力,每个页面有独立的作用域。

2.2.1什么是数据层

微信小程序的数据层是指用于管理和处理小程序中的数据的一层。它主要包括数据的获取、存储、更新和同步等功能。微信小程序提供了一些内置的API和框架,帮助开发者更方便地进行数据层的操作。

在微信小程序中,可以通过以下几种方式来实现数据层的功能:

  1. 数据缓存:小程序提供了本地数据缓存的功能,可以将数据存储在本地,以便下次使用。开发者可以使用wx.setStorageSync和wx.getStorageSync等API来进行数据的存储和获取。

  2. 数据请求:小程序可以通过网络请求获取远程服务器上的数据。开发者可以使用wx.request等API发送HTTP请求,并在回调函数中处理返回的数据。

  3. 数据更新:小程序中的数据可以通过事件驱动的方式进行更新。开发者可以通过监听用户的交互事件或者其他触发条件,来更新数据并更新UI。

  4. 数据同步:小程序中的数据可以进行实时同步。开发者可以使用WebSocket等技术实现数据的实时传输和同步。

  5. 数据管理框架:微信小程序还提供了一些数据管理框架,如WXML和WXSS,用于管理和展示数据。开发者可以使用这些框架来实现数据的绑定、渲染和样式控制等功能。

 2.3如何创建微信小程序页面        

在新建微信小程序后会自动生成一个DEMO实例,我们可以在实例中修改自己所需的内容,当内容过多时,实例中的页面不足以满足我们的需求,因此需要新建微信小程序页面。

本文内容简单,分成两个部分进行介绍:

一、创建小程序
二、页面介绍
三、新建页面

一、创建小程序

二、页面介绍


在新建一个微信小程序项目时,得到如下界面,此开发界面为微信官方提供的Demo实例。

new.js

page({

})

new.josn

{

}

new.wxml

欢迎学习小程序开发

如新增一个new页面作为初始页面,则只需要在pages数组中添加"pages/new/new",开发者工具会自动将.json .js .wxml .wxss 四个文件整合在路径下。
Pages数组的最后一项不需要逗号。
从事过网页编程的人知道,html是用来描述当前这个页面的结构,css用来描述页面的样子,JS 通常是用来处理这个页面和用户的交互。wxml、wxss、js具有其大部分特性。
开发人员可以对new页面进行自定义操作。

三、新建页面

 如新增一个new页面作为初始页面,则只需要在pages数组中添加"pages/new/new",开发者工具会自动将.json .js .wxml .wxss 四个文件整合在路径下。
Pages数组的最后一项不需要逗号。
从事过网页编程的人知道,html是用来描述当前这个页面的结构,css用来描述页面的样子,JS 通常是用来处理这个页面和用户的交互。wxml、wxss、js具有其大部分特性。
开发人员可以对new页面进行自定义操作。

2.4配置文件

  1. pages 配置项


pages 配置项接受一个数组,用来指定小程序由哪些页面组成,数组的每一项都是字符串,代表对应页面的“路径”+“文件名”。pages配置项是必填项。
文件
设置pages 配置项时,应注意以下3点:
页面
(1)数组的第一项用于设定小程序的初始页面。
有相
(2)在小程序中新增或减少页面时,都需要对数组进行修改。
(3)文件名不需要写文件扩展名。小程序框架会自动寻找路径及对.js、.json、.wxml 和 wxss文件进行整合数据绑定。

例如,app.json 文件的配置如下:

{

"pages":[
"pages/news/news",

"pages/index"]

}

2.window配置项

在app.json中设置如下window配置项

window":{
"navigationBarBackgroundColor":"#fff","
navigationBarTextStyle": "black"
"navigationBarTitleText":"小程序window 功能演示",
"backgroundColor": "#ccc",
"backgroundTextStyle": "light"

3. tabBar 配置项

其中,list(列表)接受数组值,数组中的每一项也都是一个对象。对象的数据值说明如图。

在app.json 文件中设置如下tabBar配置:

{
"tabBar":{
"color": "#666666",
"selectedColor": "#ff0000","borderStyle": "black".
"backgroundColor":"#ffffff",
"list":[
{
"pagePath": "pages/index/index","iconPath":"images /index1.png",
"selectedIconPath": "images/index2.png",
"text":"首页"
},
{
"pagePath": "pages /news /news","iconPath": "images/news1.png",
"selectedIconPath": "images/news2.png",
"text":"新闻"
      }
   ]
 }
}

4. networkTimeout 配置项


 

例如,为提高网络效应效率,开发者可以啊app.json中使用下列超时设置:


{	
"networkTimeout ":{
"request ":20000,
"connectSocket":20000,
"uploadFile":20000,
"downloadFile":20000
  }
}

5. debug 配置项

页面中的window 配置只需书写配置项,不必书写window,代码示例如下:

{
"navigationBarBackgroundColor": "#ffffff",
"navigationBarTextStyle": "black"
"navigationBarTitleText":"页面window配置演示",
"backgroundColor": "#eeeeee",
"backgroundTextStyle": "light"
}

2.5逻辑层文件

我们在Demo2的app.js加入代码

app.js

App({
//当小程序初始化完成时,会触发onLaunch(全局只触发一次)
onLaunch: function(){
console.log("小程序初始化完成..)),
//当小程序启动(或从后台进入前台显示),时会触发onshow onShow: 
function (options){ console.log("小程序显示");
 console.log( this.data);
 console.log(this.fun())
},
//当小程序从前台进入后台,会触发onHide
 onHide: function (){
console.log("小程序进入后台”)
},
//当小程序发生脚本错误,或者API调用失败时,会触发onError并带上错误信息
 onError: function(msg){},
//自定义方法
fun:function(){
console.log("在app,js中定义的方法");},
//自定义属性
data:'在app.js中定义的属性'
})

在逻辑层,Page()方法用来注册一个页面,并且每个页面有且仅有一个。

1.设置初始数据


设置初始数据是对页面的第一次数据绑定。对象data将会以JSON(Javascript Object No- tation,JS对象简谱)的形式由逻辑层传至视图层。因此,数据必须是可以转成JSON的格式(字符串、数字、布尔值、对象、数组)。
视图层可以通过WXML对数据进行绑定。


2.定义当前页面的生命周期函数


在Page( ) 函数的参数中,可以定义当前页面的生命周期函数。页面的生命周期函数主要有onLoad、onShow、onReady、onHide、onUnload。
onLoad 页面加载函数。当页面加载完成后调用该函数。一个页面只会调用一次。该函数的参数可以获取wx.navigateTo和 wx. redirectTo及<navigator/>中的query。
onShow页面显示函数。当页面显示时调用该函数。每次打开页面都会调用一次。

onReady页面数据绑定函数。当页面初次数据绑定完成时调用该函数。一个页面只会调用一次,代表页面已经准备就绪,可以和视图层进行交互。
onHide 页面隐藏函数。当页面隐藏时及当navigateTo或小程序底部进行tab切换时,调用该函数。
onUnload页面卸载函数。当页面卸载、进行navigateBack 或redirectTo操作时,调用该函数。

index.js

Page({
  data:{
  name:'yz',
  age:21,
  birthday: [{ year: 1920 },{ month: 11 },{date: 19 }],
  object:{hobby:'rap'}
  },
onLoad:function(options){
  console.log("index onLoad......")
},
onReady:function(){
console.log("index onReady.......")
},
onShow: function(){
console.log("index onShow ......")
},
onHide:function(){
console.log("index onHide......")
},
onUnload:function(){
console.log("index onUnload ......")
},
})

index.wxml

<view>姓名:{{name}}</view>
<view>年龄:{{age}}</view>
<view>出生日期:
{{birthday[0].year}}年
{{birthday[1].month}}月
{{birthday[2].date}}日
</view>
<view>爱好:{{object.hobby}}</view>

在index.js和new.js添加下图代码

Page({
  data:{
  name:'wk',
  age:30,
  birthday: [{ year: 1988 },{ month: 11 },{date: 18 }],
  object:{hobby:'computer'}
  },
onLoad:function(options){
  console.log("index onLoad......")
},
onReady:function(){
console.log("index onReady.......")
},
onShow: function(){
console.log("index onShow ......")
},
onHide:function(){
console.log("index onHide......")
},
onUnload:function(){
console.log("index onUnload ......")
},
})

效果图

3.定义事件处理函数


开发者在Page()中自定义的函数称为事件处理函数。视图层可以在组件中加入事件绑定,当达到触发事件时,小程序就会执行Page()中定义的事件处理函数。

//index.wxm1
<view bindtap ="myclick">单击执行逻辑层事件<~iew>
//index.js 
Page({
myclick:function(){
console.log("点击了 view" >
}
});

4.使用setData 更新数据


小程序在Page对象中封装了一个名为setData()的函数,用来更新data中的数据。函数参数为Object,以“key:value”对的形式表示将this.data中的key对应的值修改为value。

index.js

Page({
  //页面的初始数据
  data:{
    name:'yz', //字符串
    age:19,      //数字
    birthday:[{year:1920},{month:11},{date:19}], //数组
    object:{hobby:'rap'} //对象
  },
  chtext:function() {
    this.setData({
      name:'wb'
    });
  },
  chage:function() {
    this.setData({
      age:20
    });
  },
  charray:function() {
    this.setData({
      birthday:[{year:2015},{month:12},{date:14}]
    });
  },
  chobject:function() {
    this.setData({
      'object.hobby':'街舞,乒乓球,足球'
    });
  },
  adddata:function() {
    this.setData({
      'address':'完成'
    });
  },
  myclick:function(){
    console.log("你点击了view")
  },
});

index.wxml

<view>姓名:{{name}}</view>
<button bind:tap="chtext">修改姓名</button>
<view>年龄:{{age}}</view>
<button bind:tap="chage">修改年龄</button>
<view>出生日期:
  {{birthday[0].year}}年
  {{birthday[1].month}}月
  {{birthday[2].date}}日             
</view>
<button bind:tap="charray">修改出生日期</button>
<view>爱好:{{object.hobby}}</view>
<button bind:tap="chobject">修改爱好</button>
<view>{{address}}</view>
<button bind:tap="adddata">添加数据</button>
<view bind:tap="myclick">单击执行逻辑层事件</view>

效果图

2.6页面结构文件

1.数据绑定

小程序在进行页面数据绑定时,框架会将WXML文件与逻辑文件中的data进行动态绑定,在页面中显示data中的数据。小程序的数据绑定使用Mustache语法()将变量或运算规则包起来。

示例代码

index.mxml

<view>姓名:{{name}}</view>
<view>年龄:{{age}}</view>
<view>出生日期:
{{birthday[0].year}}年
{{birthday[1].month}}月
{{birthday[2].date}}日
</view>
<view>算数运算; {{app+aum}}</view>
<view>逻辑运算; {{app==40}}</view>
<view>三元运算:{{age==1 ?3:4}}</view> 
 
 
 
 

index.js

Page({
  //页面的初始数据
  data:{
  name:'yz',//字符串
  age:21,//数字
  birthday:[{year:1920},{month:11},{ date:19 }],//数组object:{hobby:'computer'}//对象
  }
})

效果图

2.7页面样式文件

wxss常用属性

第三章 

3.1盒子模型

微信小程序的视图层由WXML和WXSS组成。其中,WXSS (WeiXinStyle Sheets)基于CSS拓展的样式语言,用于描述WXML的组成 ,决定WXML的组件如何显示。
在页面设计中,只有掌握了盒子模型以及盒子模型的各个属性和应用方法,才能轻松控制页面中的各个元素。
盒子模型就是我们在页面设计中经常用到的一种思维模型。在CSS 中,一个独立的盒子模型由内容(content)、内边距(padding)、边框(border)和外边距(margin )4个部分组成,
此外,对padding、border和margin可以进一步细化为上、下、左、右4个部分,在CSS中可以分别进行设置.

此外, 对padding、border 和margin 可以进一步细化为上、下、左、右4 个部分, 在CSS可以分别进行设置。

3.2块级元素与行内元素

3.21块级元素

块级元素默认占一行高度,一行内通常只有一个块级元素(浮动后除外),添加新的块级元素时,会自动换行,块级元素一般作为盒子出现。

块级元素的特点如下:(一个为一行,可以设置长宽高)

(1)一个块级元素占一行
(2)块级元素的默认高度由内容决定,除非自定义高度。
(3)块级元素的默认宽度是父级元素的内容区宽度,除非自定义宽度。

(4)块级元素的宽度、高度、外边距及内边距都可以自定义设置。

(5)块级元素可以容纳块级元素和行内元素。

index.js

Page({
  
})

index.josn

{
  
}

index.wxml

<!--每个块级元素占一行-->
<view style = "border:1px solid #f00">块级元素1</view>
<!--块级元素的宽度等于父级元素的宽度减去内外边距的宽度-->
<view style = "border:1px solid #0f0;margin:15px;padding:20px">块级元素2</view >
<!--块级元素的宽度、高度自定义设置-->
<view style = "border:1px solid #00f;width:200px;height:80px">块级元素3</view >
<!--块级元素的高度随内容决定,内容为块级元素 -->
<view style= "border:1px solid #ccc;">
<view style = "height:60px">块级元素4</view >
</view>
<!--块级元素的高度随内容决定,内容为文本元素,块级元素的宽度为100px-->
<view style = "border: 1px solid #f00;width:100px;background-color:#ccc">父级元素高度随内容决定,内容为文本</view>

运行效果图

3.2.2行内元素

行内元素,不必从新一行开始,通常会与前后的其他行内元素显示在同一行中,它们不占有独立的区域,仅靠自身内容支撑结构,一般不可以设置大小,常用于控制页面中文本的样式。将一个元素的display属性设置为inline后,该元素即被设置为行内元素。

行内元素的特点如下:(由内容决定,text最常见的行内元素,不能设置长宽高,文字在后面点缀叠加)
(1)行内元素不能被设置高度和宽度,其高度和宽度由内容决定。
(2)行内元素内不能放置块级元素,只级容纳文本或其他行内元素。 

(3)同一块内,行内元素和其他行内元素显示在同一行。

index.js

Page({
  
})

index.josn

{
  
}

index.wxml

<view style= "padding:20px">
<text style ="border:1px solid #f00">文本1</text >
<text style = " border:1px solid #0f0; margin:10px; padding:5px">文本2</text >
<view style ="border:1px solid #00f; display:inline">块级元
设置为行内元素</view>一行显示不全,自动换行显示
</view>

运行效果图

3.2.3 行内块元素

当元素的 display 属性被设置为imnline-block时,元素被设置为行内块元素。行内块元可以被设置高度、宽度、内边距和外边距。

index.js

// pages/index/index.js
Page({
 
})

index.josn

{
}

index.wxml

<view>
<view style= "display: inline-block;border: 1px solid #f00;margin: 10px;width: 200px;">块级元素、行内元素和行内块元素
</view>三种类型
</view>

运行效果图

3.3浮动和定位

3.3.1 元素浮动与清除

概念:元素浮动就是指设置了浮动属性的元素会脱离标准文档流的控制, 移到其父元素中指定位置的过程。 在CSS中, 通过float 属性来定义浮动。

{float:none|left|right;}

其中none——默认值,表示元素不浮动;

left——元素向左浮动

right——元素向右浮动

index.js

Page({
  
})

index.josn

{
}

index.wxml

<view>box1,box2,box3没</view>
<view style="border: 1px solid #ccc;padding: 5px;">
  <view style="border: 1px solid #0f0;">box1</view>
  <view style="border: 1px solid #0f0;">box2</view>
  <view style="border: 1px solid #0f0;">box3</view>
</view>
 
<view>box1左</view>
<view style="border: 1px solid #ccc;padding: 5px;">
  <view style="float: left; border: 1px solid #0f0;">box1</view>
  <view style="border: 1px solid #0f0;">box2</view>
  <view style="border: 1px solid #0f0;">box3</view>
</view>
 
<view>box2左</view>
<view style="border: 1px solid #f00;padding: 5px;">
  <view style="float: left; border: 1px solid #0f0;">box1</view>
  <view style="border: 1px solid #0f0;">box2</view>
  <view style="border: 1px solid #0f0;">box3</view>
</view>
 
<view>box1,box2左</view>
<view style="border: 1px solid #f00;padding: 5px;">
  <view style="float: left; border: 1px solid #0f0;">box1</view>
  <view style="float: left;border: 1px solid #0f0;">box2</view>
  <view style="border: 1px solid #0f0;">box3</view>
</view>
 
<view>box1,box2,box3左</view>
<view style="border: 1px solid #f00;padding: 5px;">
  <view style="float: left; border: 1px solid #0f0;">box1</view>
  <view style="float: left;border: 1px solid #0f0;">box2</view>
  <view style="float: left;border: 1px solid #0f0;">box3</view>
</view>

运行效果图

3.3.2 元素定位

浮动很灵活,无法精准定位控制,所以通过position属性对页面元素的精准定位。

{position:static|reative|absolute|fixed}

index.js

Page({
  
})

index.josn

{
}

index.wxml

<!--未定位static-->
<view style="border: 3px solid #f00;width: 100px;height: 100px">box1</view>
<view style="border: 3px solid #f00;width: 100px;height: 100px">box2</view>
<view style="border: 3px solid #f00;width: 100px;height: 100px">box3</view>
 
<!--box2相对定位relative top:30px left:30px-->
<view style="border: 3px solid #f0f;width: 100px;height: 100px">box1</view>
<view style="border: 3px solid #f0f;width: 100px;height: 100px;position:relative;left: 30px;top: 30px;">box2</view>
<view style="border: 3px solid #f0f;width: 100px;height: 100px">box3</view>
 
<!--box2绝对定位absolute top:30px left:30px-->
<view style="border: 3px solid #f00;width: 100px;height: 100px">box1</view>
<view style="border: 3px solid #0f0;width: 100px;height: 100px;position:absolute;left: 30px;top: 30px;">box2</view>
<view style="border: 3px solid #f00;width: 100px;height: 100px">box3</view>
 
<!--box2固定定位fixed top:30px left:30px-->
<view style="border: 3px solid #f0f;width: 100px;height: 100px">box1</view>
<view style="border: 3px solid #f0f;width: 100px;height: 100px;position:fixed;left: 30px;top: 30px;">box2</view>
<view style="border: 3px solid #f0f;width: 100px;height: 100px">box3</view>

运行效果图

3.4 flex布局

3.4.1容器属性

1.display

.box{display:flex|inline-flex;}

2.flex-direction

.box{flex-direction:row|row-reverse|column|column-reverse;}

row———主轴为水平方向, 起点在左端, 当元素设置为 flex布局时, 主轴默认为row;

row-reverse———主轴为水平方向, 起点在右端; 

column———主轴为垂直方向, 起点在顶端;

column-reverse———主轴为垂直方向, 起点在底端。

3.flex-wrap

其中, nowrap———不换行, 默认值;

wrap———换行, 第一行在上方;

wrap - reverse———换行, 第一行在下方。

     当设置换行时, 还需要设置align - item 属性来配合自动换行, 但align - item 的值不能为“stretch”。

4.flex-flow

.box{flex-flow:<flex-direction>||<flex-wrap>;}

5.ustify-content

.box{justify-content:flex-start|flex-end|center|space-between|space-around;}

align-items———与交叉轴方向有关, 默认交叉由上到下;

flex-start———交叉轴起点对齐;

flex-end———交叉轴终点对齐;

center———交叉轴中线对齐;

baseline———项目根据它们第一行文字的基线对齐;

stretch———如果项目未设置高度或设置为auto, 项目将在交叉轴方向拉伸填充容器, 此为默认值。


6.align-items

.box{align-items:flex-start|flex-end|center|baseline|stretch;}

align-items———与交叉轴方向有关, 默认交叉由上到下;

flex-start———交叉轴起点对齐;

flex-end———交叉轴终点对齐;

center———交叉轴中线对齐;

baseline———项目根据它们第一行文字的基线对齐;

stretch———如果项目未设置高度或设置为auto, 项目将在交叉轴方向拉伸填充容器, 此为默认值。

index.json

{
  "navigationBarBackgroundColor": "#000000",
  "navigationBarTextStyle": "white",
  "backgroundTextStyle": "dark"
}

index.wxml

<view class="cont1">
<view class="item">1</view>
<view class="item item2">2</view>
<view class="item item3">3</view>
<view class="item item4">4</view>
</view>

index.wxss

.cont1{
  display: flex;
  flex-direction: row;
  align-items: baseline;
}
.item{
  background-color: #ccc;
  border: 1px solid#f00;
  height: 100px;
  width: 50px;
  margin: 2px;
}
.item2{
  height: 80px;
}
.item3{
  display: flex;
  height: 50px;
  align-items:flex-end ;
}
.item4{
  height: 120px;
}

运行效果图

7.align-content

.box{align-content;flex-start|flex-end|center|space-between|space-around|stretch}

3.4.2 项目属性

1.order

.item{order:<number>;}

index.json

{
  "navigationBarBackgroundColor": "#000000",
  "navigationBarTextStyle": "white",
  "backgroundTextStyle": "dark"
}

Index.wxml

<view class="cont1">
<view class="item">1</view>
<view class="item item2">2</view>
<view class="item item3">3</view>
<view class="item item4">4</view>
</view>
<view class="cont1">
<view class="item" style="order: 1;">1</view>
<view class="item "style="order: 3;">2</view>
<view class="item "style="order: 2;">3</view>
<view class="item item4">4</view>
</view>

index.wxss

.cont1{
  display: flex;
  flex-direction: row;
  align-items: baseline;
}
.item{
  background-color: #ccc;
  border: 1px solid#f00;
  height: 50px;
  width: 50px;
  margin: 2px;
}
.item2{
  height: 50px;
}
.item3{
  display: flex;
  height: 50px;
  align-items:flex-start ;
}
.item4{
  height: 50px;
}

运行效果图

2.flex-grow

.item{flex-grow:<number>;}

index.josn

{
  "navigationBarBackgroundColor": "#000000",
  "navigationBarTextStyle": "white",
  "backgroundTextStyle": "dark"
}

index.wxml

<view class="cont1">
<view class="item">1</view>
<view class="item item2">2</view>
<view class="item item3">3</view>
<view class="item item4">4</view>
</view>
<view class="cont1">
<view class="item">1</view>
<view class="item "style="flex-grow:1">2</view>
<view class="item "style="flex-grow:2">3</view>
<view class="item">4</view>
</view>

index.wxss

.cont1{
  display: flex;
  flex-direction: row;
  align-items: baseline;
}
.item{
  background-color: #ccc;
  border: 1px solid#f00;
  height: 50px;
  width: 50px;
  margin: 2px;
}
.item2{
  height: 50px;
}
.item3{
  display: flex;
  height: 50px;
  align-items:flex-start ;
}
.item4{
  height: 50px;
}

运行效果图

3.flex-shrink

.item{flex-shink:<number>;}

index.josn

{
  "navigationBarBackgroundColor": "#000000",
  "navigationBarTextStyle": "white",
  "backgroundTextStyle": "dark"
}

index.wxml

<view class="cont1">
<view class="item">1</view>
<view class="item item2">2</view>
<view class="item item3">3</view>
<view class="item item4">4</view>
</view>
<view class="cont1">
<view class="item">1</view>
<view class="item "style="flex-shrink:1">2</view>
<view class="item "style="flex-shrink:2">3</view>
<view class="item"style="flex-shrink:3">4</view>
</view>

index.wxss

.cont1{
  display: flex;
  flex-direction: row;
  align-items: baseline;
}
.item{
  background-color: #ccc;
  border: 1px solid#f00;
  height: 60px;
  width: 120px;
  margin: 2px;
}
.item2{
  height: 60px;
}
.item3{
  display: flex;
  height: 60px;
  align-items:flex-start ;
}
.item4{
  height: 60px;
}

运行效果图

4.flex-basis

.item{flex-basis:<numner>|auto;}

index.josn

{
  "navigationBarBackgroundColor": "#000000",
  "navigationBarTextStyle": "white",
  "backgroundTextStyle": "dark"
}

index.wxml

<view class="cont1">
  <view class="item">1</view>
  <view class="item">2</view>
  <view class="item">3</view>
  <view class="item">4</view>
</view>
<view class="cont1">
  <view class="item">1</view>
  <view class="item" style="flex-basis:100px;">2</view>
  <view class="item" style="flex-basis: 200px;">3</view>
  <view class="item">4</view>
</view>

index.wxss

.cont1{
  display: flex;
  flex-direction: row;
  align-items: baseline;
}
.item{
  background-color: #ccc;
  border: 1px solid#f00;
  height: 100px;
  width: 50px;
  margin: 2px;
}
.item2{
  height: 80px;
}
.item3{
  display: flex;
  height: 80px;
  align-items:flex-start ;
}
.item4{
  height: 120px;
}

运行效果图

5.flex

.item{<flex-grow>|<flex-shrink>|<flex-basis>;}

6.align-self

.item{aligin-self:auto|flex-start|flex-end|center|baseline|stretch;}

第四章

 4.1 组件的定义及属性

  概念:组件是页面视图层(WXML)的基本组成单元,组件组合可以构建功能强大的页面结构。小程序框架为开发者提供了容器视图、基础内容、表单、导航、多媒体、地图、画布、开放能力等8类(30多个)基础组件。
  每一个组件都由一对标签组成,有开始标签和结束标签,内容放置在开始标签和结束标签之间,内容也可以是组件。组件的语法格式如下:

<标签名  属性名=“属性值”>内容...</标签名>

组件通过属性来进一步细化。不同的组件可以有不同的属性,但它们也有一些共用属性,如id、class、style、hidden、data-∗、bind∗/catch∗等。
1. id组件的唯一表示,保持整个页面唯一,不常用。
2. class组件的样式类,对应WXSS中定义的样式。
3. style组件的内联样式,可以动态设置内联样式。
4. hidden组件是否显示,所有组件默认显示。
5. data-∗ 自定义属性,组件触发事件时,会发送给事件处理函数。事件处理函数可以通过传入参数对象的currentTarget. dataset方式来获取自定义属性的值。
6. bind∗/catch∗ 组件的事件,绑定逻辑层相关事件处理函数。

4.2 容器视图组件

概念:容器视图组件是能容纳其他组件的组件,是构建小程序页面布局的基础组件,主要包括view、scroll-view和swiper组件。

4.2.1 view

概念:view组件是块级组件,没有特殊功能,主要用于布局展示,相当于HTML中的div,是布局中最基本的用户界面(User Interface, UI)组件,通过设置view的CSS属性可以实现各种复杂的布局。

index.wxml

<view style="text-align:center">默认flex布局</view>
<view style="display:flex">
<view style ="border:2px solid #f00;flex-grow:1">1 </view>
<view style ="border:2px solid #f00;flex-grow:1">2 </view>
<view style ="border:2px solid #f00;flex-grow:1">3 </view>
</view>
<view style="text-align:center">上下混合布局</view>
<view style="display:flex;flex-direction:column">
<view style="border:2px solid #f00;">1 </view>
<view style="display:flex">
<view style="border:2px solid #f00;flex-grow:1">
2 </view>
<view style="border:2px solid #f00;flex-grow:2">3</view>
</view>
</view>
<view style="text-align:center">左右混合布局</view>
<view style="display:flex">
<view style ="border:2px solid #f00;flex-grow:1">1 </view>
<view style ="display:flex;flex-direction:column;flex-grow:1">
<view style ="border:2px solid #f00;flex-grow:1">2</view>
<view style ="border:2px solid #f00;flex-grow:2">3</view>
</view>
</view>

运行效果

4.2.2  scroll-view

【注意】
1.在使用竖向滚动时,如果需要给scroll -view组件设置一个固定高度,可以通过WXSS设置height来完成。
2.请勿在scroll-view组件中使用textarea、map、canvas、video组件。
3.scroll-into-view属性的优先级高于scroll-top。
4.由于在使用scroll-view组件时会阻止页面回弹,所以在scroll-view组件滚动时无法触发onPullDownRefresh。
5.如果要实现页面下拉刷新,请使用页面的滚动,而不是设置scroll-view组件。这样做,能通过单击顶部状态栏回到页面顶部。

4.2.3 swiper

概念:swiper组件可以实现轮播图、图片预览、滑动页面等效果。一个完整的swiper组件由<swiper/ >和<swiper-item/ >两个标签组成,它们不能单独使用。<swiper/ >中只能放置一个或多个<swiper-item/ >,若放置其他组件则会被删除;<swiper-item/ >内部可以放置任何组件,默认宽高自动设置为100%。

<swiper indicator-dots='true' autoplay='true' interval ='5000' du-swiperration='1000'>
<swiper-item >
<image src="../images/a.jpg" style="width:100%"></image>
</swiper-item>
<swiper-item>
<image src="../images/d.jpg" style="width:100%"></image>
</swiper-item>
<swiper-item>
<image src ="../images/s.jpg" style ="width:100%"></image>
</swiper-item>
</swiper>

运行效果

4.3 基础内容组件


概念:基础内容组件包括icon、text和progress,主要用于在视图页面中展示图标、文本和进度条等信息。

4.3.1 icon

概念:icon组件即图标组件,通常用于表示一种状态,如success、info、warn、waiting、cancel等。

index.js

//icon.js
//pages/icon/icon.js
 Page({ 
  data:{
  iconType:[ "success"," success_no_circle","info"," warn"," wait- ing","cancel","download","search","clear"],
  iconSize:[10,20,30,40],
  iconColor:['#f00','#0 f0','#00f']
}
  })

index.wxml

<view> icon类型:
<block wx:for="{{iconType}}">
<icon type ="{{item}}"/>{{item}}
</block>
</view >
<view >icon大小:
<block wx:for="{{iconSize}}">
<icon type = "success" size="{{item}}"/>{{item}}
</block>
</view>
<view >icon颜色:
<block wx:for="{{iconColor}}">
<icon type = "success" size = "30" color="{{item}}"/>{{item}}
</block >
</view >

运行效果

4.3.2  text

概念:text组件用于展示内容,类似HTML中的<span >, text组件中的内容支持长按选中,支持转义字符“\”,属于行内元素。

index.js

Page({ 
  data: {
  x:[1,2,3,4,5],
  y:[1,2,3,4,5,6,7,8,9]}
})

index.wxml

  <block wx:for="{{x}}" wx:for-item="x">
    <view class="aa">
    <block wx:for="{{25-x}}" wx:for-item="x">
    <text decode="{{true}}" space="{{true}}">&nbsp;</text>
  </block>
  <block wx:for="{{y}}" wx:for-item="y">
  <block wx:if="{{y<=2*x-1}}">
  <text>*</text>
  </block>
  </block>
  </view>
  </block>
  <block wx:for="{{x}}"wx:for-item="x">
  <view class="aa">
  <block wx:for="{{19+x}}" wx:for-item="x">
  <text decode="{{true}}" space="{{true}}">&nbsp;</text>
  </block>
<block wx:for="{{y}}" wx:for-item="y">
<block wx:if="{{y<=11-2*x}}">
<text>*</text>
</block>
</block>
</view>
</block>

运行效果

4.3.3 progress

概念:progress组件用于显示进度状态,如资源加载、用户资料完成度、媒体资源播放进度等。

index.wxml

<view>显示百分比</view>
<progress percent ='80'show-info ='80'></progress>
<view>改变宽度</view>
<progress percent ='50'stroke -width ='2'></progress>
<view>自动显示进度条</view>
<progress percent='80' active></progress>

运行效果

4.4 表单组件

概念:表单组件的主要功能是收集用户信息,并将这些信息传递给后台服务器,实现小程序与用户之间的沟通。表单组件不仅可以放置在<form/ >标签中使用,还可以作为单独组件和其他组件混合使用。

4.4.1 button

概念:button组件用来实现用户和应用之间的交互,同时按钮的颜色起引导作用。一般来说,在一个程序中一个按钮至少有3种状态:默认点击(default)、建议点击(primary)、谨慎点击(warn)。在构建项目时,应在合适的场景使用合适的按钮,当<button>被<form/ >包裹时,可以通过设置form-type属性来触发表单对应的事件。

index.js 

Page({
  data:{
  size:'default',
  plain:false,
  loading:'false'
  },
  //改变按钮的大小
  buttonSize:function(){
  if(this.data.size =="default")
  this.setData({size:'mini'})
  else 
  this.setData({size:'default'})
},
  //是否显示镂空
  buttonPlain:function(){
  this.setData({plain:!this.data.plain})
  },
  //是否显示 loading 图案
  buttonLoading:function(){
    this.setData({loading:!this.data.loading})
  }
})

index.wxml

<button type="default">type:default </button>
<button type="primary">type:primary </button>
<button type="warn">type:warn</button>
<button type="default" bindtap ='buttonSize'size="{{size}}">改变size
</button>
<button type="default" bindtap= 'buttonPlain'plain="{{plain}}">改变plain
</button>
<button type="default" bindtap='buttonLoading'loading ="{{loading}}">改变1oading显示</button>

 运行效果

4.4.2 radio

概念:单选框用来从一组选项中选取一个选项。在小程序中,单选框由<radio-group/ >(单项选择器)和<radio/ >(单选项目)两个组件组合而成,一个包含多个 <radio/ >的<radio-group/ >表示一组单选项,在同一组单选项中<radio/ >是互斥的,当一个按钮被选中后,之前选中的按钮就变为非选。

index.js

//radio.js
Page({
  data:{
  radios:[
  {name:'java',value:'JAVA'},
  {name:'python',value:'python',checked:'true'},
  {name:'php',value:'PHp'},
  {name:'swif',value:'Swif'},
  ],
  city:"",
  lang:""
  },
  citychange:function(e){
  this.setData({city:e.detail.value});
  },
  radiochange:function(event){
  this.setData({lang:event.detail.value});
  console.log(event.detail.value)
  }
})

 index.wxm

<view>选择您喜爱的城市:</view>
<radio-group bindchange="citychange">
<radio value="西安">西安</radio>
<radio value="北京">北京</radio>
<radio value="上海">上海</radio>
<radio value="广州">广州</radio>
<radio value="深圳">深圳</radio>
</radio-group>
<view>你的选择:{{city}}</view>
<view>选择您喜爱的计算机语言:</view>
<radio-group class="radio-group" bindchange="radiochange">
<label class="radio" wx:for="{{radios}}">
<radio value="{{item.value}}"checked="{{item.checked}}"/>
{{item.name}}
</label>
</radio-group>
<view>你的选择:{{lang}}</view>

运行效果

4.4.3 checkbox

 概念:复选框用于从一组选项中选取多个选项,小程序中复选框由 <checkbox -group/ >(多项选择器)和<checkbox/ >(多选项目)两个组件组合而成。一个<checkbox-group/ >表示一组选项,可以在一组选项中选中多个选项。

index.js

//checkbox.js 
Page({
  city:"",
   data:{ 
     citys:[
    {name:'km',value:'昆明'},
    {name:'sy',value:'三亚'},
   {name:'zh',value:'珠海',checked:'true'}, 
   {name:'dl',value:'大连'}]
     },
    cityChange:function(e){
    console.log(e.detail.value);
     var city = e.detail.value; 
     this.setData({city:city})
    }
    })

index.wmxl

<view>选择您想去的城市:</view >
<checkbox-group bindchange ="cityChange">
<label wx:for="{{citys}}">
<checkbox value="{{item.value}}" 
checked ='{{item.checked}}'>
{{item.value}}
</checkbox>
</label>
</checkbox-group>
<view>您的选择是:{{city}}</view>
 

运行效果

4.4.4 switch

index.js

//switch.js
Page({
  data:{
  var1:'关',
  var2:'开',
  var3:'未选'
  },
  swl:function(e){
  this.setData({var1:e.detail.value?'开':'关'})
},
  sw2:function(e){
  this.setData({var2:e.detail.value?'开':'关'})
},
  sw3:function(e){
  this.setData({var3:e.detail.value?'已选':'未选'})
  }
})

index.wxml

<view>
<switch bindchange="sw1">{{var1}}</switch></view>
<view>
<switch checked bindchange="sw2">var2 }</switch></view>
<view>
<switch type="checkbox" bindchange ="sw3">{{var3}}|</switch></view>

运行效果

4.4.5 slider 

概念:slider组件为滑动选择器,可以通过滑动来设置相应的值。

index.js

Page({
  data:{
  size:'20'
  },
  sliderchange:function(e){
  this.setData({size:e.detail.value})
  }
})

index.wxml

<view>默认min=0 max=100 step =1 </view><slider></slider>
<view>显示当前值</view>
<slider show-value></slider><view>设置min=20 max=200 step=10</view ><slider min ='0'max='200'step ='10'show-value ></slider>
<view>背景条红色,已选定颜色绿色</view><slider color ="#f00" selected-color ='#f0'></slider >
<view>滑动改变icon 的大小</view>
<slider show-value bindchange='sliderchange'>
</slider><icon type="success" size='{{size}}'></icon >

运行效果

4.4.6 picker

1.普通选择器

index.js

//picker.js
Page({
data:{
array: ['Java','Python' ,'c' ,'c#'],
objArray:[
{id:0,name:'Java'},
{id:1,name:'Python'},
{id:2 ,name:'c'},
{id:3 ,name:'c#'}
],
index1:0,
index2:0
},
arrayChange:function(e){
  console.log('picker值变为',e.detail.value)
  var index=0;this.setData({indexl:e.detail.value
  })
},
objArrayChange:function(e){
console.log('picker值变为',e.detail.value)
this.setData({
  index2:e.detail.value
})
}
})

index.wxml

<view>----range为数组---</view>
<picker range ="{{array}}" value ="{{indexl}}" bindchange='arrayChange'>
当前选择:{{array[index1]}}
</picker >
<view>---range为数组对象--</view>
<picker
bindchange ="objArrayChange" value ="{{index2}}" range-key="name" range="iobjArray">
当前选择:{{objArray[index2].name}}</picker>

运行结果

2.多列选择器

index.js

Page({
  data:{
  multiArray:[['陕西省','广东省'],['西安市','汉中市','延安市'],['雁塔区','长安区']],
  multiIndex:[0,0,0]
  },
  //绑定 Multipicker
  bindMultiPickerChange:function(e){
  console.log('picker发送选择改变,携带值为',e.detail.value)
  this.setData({multiIndex:e.detail.value
  })
  },
  //绑定MultiPickerColumn
  bindMultiPickerColumnChange:function(e){
  console.log('修改的列为',e.detail.column,'','值为',e.detail.value);
  var data ={multiArray:this.data.multiArray,
  multiIndex:this.data.multiIndex
  };
  data.multiIndex[e.detail.column]= e.detail.value;
  switch(e.detail.column){}
  case0 :
  switch(data.multiIndex[0]){
  case 0:
  data.multiArray[1]=['西安市','汉中市','延安市'];
  data.multiArray[2]=['雁塔区','长安区'];
  break;
  casel :
  data.multiArray[1]=['深圳市','珠海市'];
  data.multiArray[2]=['南山区','罗湖区'];
  break;
  data.multiIndex[1]=0;
  data.multiIndex[2]=0;
  break ;
  case1 :
  switch(data.multiIndex0){
  case 0:
  switch(data.multiIndex1){
  case 0:
  data.multiArray[2]=['雁塔区','长安区'];
  break;
  case 1:
  data.multiArray[2]=['汉台区','南郑区'];
  break;
  case 2:
  data.multiArray[2]=['宝塔区','子长县','延川县'];
  break;
  }
  break;
  case 1:
  switch(data.multiIndex[1]){
    case 0:
    data.multiArray[2]=['南山区','罗湖区'];
    case 1:
    data.multiArray[2]=['香洲区','斗门区'];
    break;
  }
  break;
  }
  data.multiIndex[2]=0;
  console.log(data.multiIndex);
  break;
  }
  this.setData(data);
  },
})

index.wxml

<view>多列选择器</view>
<picker mode="multiSelector" bindchange="bindMultiPickerChange" 
bindcolumnchange="bindMultiPickerColumnChange"
value="{{multiIndex}}"
range="{{multiArray}}">
  <view>
    当前选择:{{multiArray[0][multiIndex[0]]}},{{multiArray[1][multiIndex[1]]}},{{multiArray[2][multiIndex[2]]}}
  </view>
  </picker>

运行结果

3.时间选择器、日期选择器

 

index.js

//picker-datetime.js
Page({
data:{
startdate:2000,
enddate:2050,
date:'2018',
starttime:'00:00',
endtime:'12 :59',
time:'8 :00'
},
changedate:function(e){
this.setData({date:e.detail.value});
console.log(e.detail.value)
},
changetime:function(e){
this.setData({time:e.detail.value})
console.log(e.detail.value)
}
})

index.wmxl

<view>
<picker mode ="date" start = "{{startdate}}" end = "{{enddate}}" value="{{date}}" bindchange="changedate">
选择的日期:{{date}}
</picker>
</view>
<view>
<picker mode ="time" start ="{{starttime}}" 
end ="{{endtime}}" bindchange="changetime">
选择的时间:{{time}}
</picker>
</view>

运行结果

4.省市选择器

index.js

//picker-region.js
Page({
data:{
region:['陕西省','西安市','长安区'],
customitem:'全部'
},
changeregion:function(e){
console.log(e.detail.value)
this.setData({
region:e.detail.value})
}
})

 index.wxml

<picker mode ="region" value ="{{region}}" custom -item ="{{customitem}}"  bindchange="changeregion">
选择省市区:{{region[0]}},{{region[1]}},{{region[2]}}
</picker>

运行结果

4.4.7 picker-view  

index.js

//picker-view.js
const date =new Date()
const years=[]
const months=[]
const days=[]
//定义年份
for(let i=1900;i<=2050;i++){
years.push(i)
}
//定义月份
for(let i=1;i<=12;i++){
months.push(i)
}
//定义日期
for(let i=1;i<=31;i++){
days.push(i)
}
Page({
data:{
years:years,
months:months,
days:days,
year:date.getFullYear(),
month:date.getMonth()+1,day:date.getDate(),value:[118,0,0],
},
//定位到2018年1月1日
bindChange:function(e){
const val =e.detail.value 
console.log(val);
this.setData({
year:this.data.years[val[0]],
month:this.data.months[val[1]],
day:this.data.days[val[2]]
})
}
})

index.wxml

<view>当前日期:{{year}}年{{month}}月{{day}}日</view >
<picker-view indicator-style="height:50px;" style ="width:100%; height:300px;"
 value ="{{value}}" bindchange ="bindchange">
 <picker-view-column>
<view wx:for="{{years}}"style="line-height:50px">{{item}}年</view>
</picker-view-column>
<picker-view-column>
<view wx:for="{{months}}" style ="line-height:50px">{{item}}月</view>
</picker-view-column>
<picker-view-column>
<view wx:for="{{days}}" style="line-height:50px">{{item}}日</view>
</picker-view-column>
</picker-view>

运行结果

4.4.8 input

index.js

//input.js
Page({
  data:{
  focus:false,
  inputValue:""
  },
  bindButtonTap:function(){
  this.setData({
  focus:true
    })
  },
  bindKeyInput:function(e){
  this.setData({
  inputValue:e.detail.value
  })
},
  bindReplaceInput:function(e){
  var value =e.detail.value
  var pos =e.detail.cursor
  if(pos!=-1){
  //光标在中间
  var left =e.detail.value.slice(0,pos)
  //计算光标的位置
  pos =left.replace(/11/g,'2').length
  }
  //直接返回对象,可以对输入进行过滤处理,同时可以控制光标的位置
  return{
value:value.replace(/11/g,'2'),
Cursor:pos
  }
//或者直接返回字符串,光标在最后边
//return value.replace( /11 /g,'2'),
  }
})

index.wxml

<input placeholder="这是一个可以自动聚焦的 input" auto-focus/>
<input placeholder="这个只有在按钮点击的时候才聚焦" focus ="{{focus}}"/>
<button bindtap="bindButtonTap">使得输入框获取焦点</button>
<input maxlength="10" placeholder="最大输入长度为10"/>
<view class="section_title">你输入的是:{{inputValue}}</view>
<input bindinput="bindKeyInput" placeholder="输入同步到view中"/>
<input bindinput="bindReplaceInput" placeholder="连续的两个1会变成2"/>
<input password type="number"/>
<input password type="text"/>
<input type="digit" placeholder="带小数点的数字键盘"/>
<input type="idcard" placeholder="身份证输入键盘"/>
<input placeholder-style="color:red" placeholder="占位符字体是红色的"/>

运行结果

4.4.9 textarea

index.wxml

<textarea bindblur ="bindTextAreaBlur" auto-height placeholder="自动变高"/>
<textarea placeholder="placeholder 颜色是红色"placeholderstyle="color:red;"/>
<textarea placeholder="这是一个可以自动聚焦的textarea" auto-focus/>
<textarea placeholder="这个只有在按钮点击的时候才聚焦"focus="{{focus}}"/>
<button bindtap="bindButtonTap">使得输入框获取焦点</button >
<form bindsubmit="bindFormSubmit">
<textarea placeholder ="form 中的textarea" name ="textarea" />
<button form-type="submit">提交</button></form>

index.js

//textarea.js
Page({
data:{
height:10,
focus:false
},
bindButtonTap:function(){
this.setData({
focus:true
})
},
bindTextAreaBlur:function(e){
  console.log(e.detail.value)
},
bindFormSubmit:function(e){
console.log(e.detail.value.textarea)
}
})

运行结果

4.4.10  laber

index.wxml

<!--单击中国不能选择/取消复选框-->
<view><checkbox></checkbox>中国</view>
<!--单击“中国”可以选择/取消复选框-->
<view><label><checkbox> </checkbox >中国</label></view>
<!--使用for找到对应的 id -->
<checkbox-group bindchange="cityChange">
<label wx:for="{{citys}}">
<checkbox value ="{{item.value}}" checked = '{{item.checked}}'>
{{item.value}}</checkbox>
</label>
</checkbox-group>
<view>您的选择是:{{city}}</view>

index.js

//1abel.js
Page({
city:"",
data:{
citys:[
{name:'km',value:'昆明'},
{name:'sy',value:'三亚'},
{name:'zh',value:'珠海',checked:'true'},
{name:'dl',value:'大连'}]
},
cityChange:function(e){
console.log(e.detail.value);
var city =e.detail.value;
this.setData({city: city})
}
})

运行结果

4.4.11 form

index.wxml

<form bindsubmit ="formSubmit " bindreset ="formReset ">
  <view>姓名:
    <input type="text"name="xm"/>
  </view>
  <view>性别:
    <radio-group name="xb">
      <label><radio value="男" checked/>男</label>
      <label><radio value="女"/>女</label>
    </radio-group>
  </view>
  <view>爱好:
    <checkbox-group name="hobby">
      <label wx:for="{{hobbies}}">
        <checkbox value="{{item.value}}" checked='{{item.checked}}'>{{item.value}}</checkbox>
      </label>
    </checkbox-group>
  </view>
  <button formType='submit'>提交</button>
  <button formrype='reset'>重置</button>
</form>

index.js

//form. js
Page({
  hobby :"",
  data:{
  hobbies :[
  {name:'jsj',value:'吃',checked:'true'},
  {name:'music',value:'喝'},
  {name:'game',value:'玩'},
  {name:'swim',value:'乐',checked:'true'}]
  },
  formSubmit:function(e){
  console.log('form发生了submit事件,携带数据为:'.e.detail.value)
  },
  formReset:function(){
  console.log('form发生了reset事件')
  }
  })

运行结果

4.5 多媒体组件

4.5.1 image

 

1.缩放模式
1. scaleToFill不保持纵横比缩放图片,使图片的宽高完全拉伸至填满image元素。
2. aspectFit保持纵横比缩放图片,使图片的长边能完全显示出来。也就是说,可以将图片完整地显示出来。
3. aspectFill保持纵横比缩放图片,只保证图片的短边能完全显示出来。也就是说,图片通常只在水平或垂直方向是完整的,在另一个方向将会发生截取。

4. widthFix宽度不变,高度自动变化,保持原图宽高比不变。

index.js

//image.js
Page({
  data:{
  modes:['scaleToFill','aspectFit','aspectFill','widthFrix']
  }
})

index.wxml

<block wx:for="{{modes}}">
<view>当前图片的模式是:{{item}}</view>
<image mode ="{{item}}" src="/image/b.jpg"
 style ="width;100%;"
 style="height;100%;"/>
</block>

运行结果

2.裁剪模式

1. top不缩放图片,只显示图片的顶部区域。
2. bottom不缩放图片,只显示图片的底部区域。
3. center不缩放图片,只显示图片的中间区域。
4. left不缩放图片,只显示图片的左边区域。
5. right不缩放图片,只显示图片的右边区域。
6. top left不缩放图片,只显示图片的左上边区域。
7. top right不缩放图片,只显示图片的右上边区域。

8. bottom left不缩放图片,只显示图片的左下边区域。
9. bottom right不缩放图片,只显示图片的右下边区域。

index.jx

Page({
  data:{
  modes:['top','center','left','right','top_left','top_right','bottom_left','bottom_right']
  }
})

index.wxml 

  <block wx:for ="{{modes}}">
<view>当前图片的模式是:{{item}}</view>
<image mode ="{{item}}" src ="/image/pic02.jpg"  style ="width:100;"style="height:100%"/>
</block>
运行结果

4.5.2 audio

index.js

//audio.js
Page( {
data:{
poster:'http://.gtimg.cn/usic/hoto new/002R300x300M000003rsKF44Gyask.jpg?max age=2592000',
name:'此时此刻',
author:'许巍',
src:'http://ws.stream.qqmusic.gg.comM500001VfvsJ21xFab.mp3? guidffffffff82def4af4b12b3cd9337d5e7&uin=346897220&vkey=6292F51E1E384E06DCBDC9AB7C49FD713D632D313AC4858BACB8DDD29067D3C601481D36E62053BF8DFEAF74C0A5CCFADD6471160CAF3E6A&fromtag=46',
},
play:function(){
this.setData({
action:{
method: 'play'
}
})
},
pause:function(){
this.setData({
action:{
method: 'pause'
}
})
},
playRate:function(){
this.setData({
action:{
method:'setPlaybackRate',
data:10 //速率
}
})
console.log('当前速率:'+this.data.action.data)
},
currentTime:function(e){
this.setData({
action:{
method:'setCurrentTime',
data:120
}
})
}
})

index.wxml

<audio src ="{{src}}" action="{{action}}" poster = "{{poster}}" name = "{{name}}" author ="{{author}} " loop controls></audio >
<button type="primary" bindtap='play'>播放</button >
<button type="primary" bindtap="pause">暂停</button >
<button type ="primary" bindtap="playRate">设置速率</button>
<button type="primary" bindtap="currentTime">设置当前时间(秒)</button>

运行结果

4.5.3 video

index.js

//video.js
Page({
  data:{
  srC:"../images/4e6a9a27f33b2a2fce82dbbba927ef0e.mp4",
  },
  bindButtonTap:function(){
  var that =this
  wx.chooseVideo({
  sourceType: [ 'album' ,'camera'],
  maxDuration:60,
  camera:['front','back'],
  success:function(res){
  that.setData({
  src:res.tempFilePath
  })
}
})
}
})

index.wxml

<video src ="{{src}}" controls ></video >
<view class="btn-area">
<button bindtap="bindButtonTap">获取视频</button>
</view>

运行结果

4.5.4 camera

index.js

Page({
  takePhoto(){
    const ctx=wx.createCameraContext()//创建并返回 camera上下文对象/拍照,成功则返回图片
    ctx.takePhoto({
      quality:' high',
      success:(res)=>{
        this.setData({
          src:res.tempImagePath
        })
      }
    })
  },
  error(e){
  console.log(e.detail)
  }
})

index.wxml

<camera device-position="back" flash="off" bindeerror="error" style="width: 100%;height: 350px;"></camera>
<button type="primary" bindtap="takePhoto">拍摄</button>
<view>预览</view>
<image mode="widthFix" src="{{src}}"></image>

运行结果

4.6 其他组件

 

index.js

//.js
Page({
data :{
markers :[{
//标记点
iconPath:"/ages /dw.png",
id:0,
longitude:"108.9290",
latitude:"34.1480",
width:50,
height:50
}],
polyline:[{
  points:[{
  longitude:"108.9200",
  latitude:"34.1400",
  },
{
  longitude:"108.9200",//线路点2
  latitude:"34.1500"
  },
{
longitude:"108.9200",//线路点3
latitude:"34.1700",
}
  ],
color:"#00ff00",
width:2,
dottedLine:true
}],
controls:[{
//控件的相关信息
id:1,
iconPath:'ages/w.png',
position:{
left:0,
top:300,
width:30,
height:30
},
clickable:true
}]
},
regionchange(e){
console.log(e.type)
},
markertap(e){
console.log(e.markerId)
},
controltap(e){
console.log(e.controlId)
}
})

index.wxml

 <map id ="map"
longitude="108.9200"
latitude="34.1550"
scale="14"
controls="{{controls}}"
bindcontroltap="controltap"
markers="{{markers}}"bindmarkertap="markertap"polyline="{{polyline}}"
bindregionchange="regionchange"
show-location
style="width:100%;height:300px;"></map>

运行结果

4.6.2 canvas 

index.js

//.js
Page({
onLoad:function(options){
var ctx=wx.createCanvasContext('myCanvas')
ctx.setFillStyle('green')
ctx.fillRect(10,10,200,100)
ctx.draw()
}
})

index.wxml

<canvas canvas-id ="myCanvas" style ="border: 1px solid red;"/>

 运行结果

第五章 

 5.1  即速应用概述

5.1.1 即速应用的优势

即速应用是深圳市咫尺网络科技开发有限公司开发的一款同时兼具微信小程序和支付宝小程序快速开发能力的工具,用户只需简单拖拽可视化组件,就可以实现在线小程序开发。据不完全统计,在微信小程序正式发布的1年内,在即速应用上打包代码并成功上线的微信小程序已经超过5万个。
即速应用的功能特点主要体现在以下几个方面:
1.开发流程简单,零门槛制作
使用即速应用来开发微信小程序的过程非常简单,无须储备相关代码知识,没有开发经验的人也可以轻松上手。
(1)登录即速应用的官方网站(www.jisuapp.cn),进入制作界面,从众多行业模板中选择一个合适的模板。
(2)在模板的基础上进行简单编辑和个性化制作。
(3)制作完成后,将代码一键打包并下载。
(4)将代码上传至微信开发者工具。
(5)上传成功后,等待审核通过即可。
2.行业模板多样,种类齐全

即速应用为广大开发者提供了非常齐全的行业解决方案。目前,即速应用已经上线60多个小程序行业模板,涉及餐饮(单店版、多店版)、婚庆、旅游、运动、美容、房地产、家居、医药、母婴、摄影、社区、酒店、KTV、汽车、资讯等多个行业。
这些小程序行业模板可以有效地帮助企业拓宽资源整合渠道,降低运营成本,提高管理效率。
3.丰富的功能组件和强大的管理后台
即速应用的功能组件和管理后台非常实用,可以根据实际情况解决商家的不同需求。例如,到店体系可以实现电子点餐、排队预约和线上快速结算;社区体系可以实现评论留言和话题管理;多商家系统可以实现分店统一管理、多门店统一运营;营销工具可以实现会员卡、优惠券的设置等营销方式……
目前,即速应用有4个版本,分别为基础版、高级版、尊享版和旗舰版。基础版为免费使用的版本,适合制作个人小程序,其他版本根据功能不同可以满足不同企业的需求。
即速应用的应用范围主要包括以下类型:
(1)资讯类:新闻、媒体。
(2)电商类:网购(服装、电器、读书、母婴……)。
(3)外卖类:餐饮及零售。
(4)到店类:餐饮及酒吧。

(5)预约类:酒店、KTV、家教、家政,其他服务行业。

5.1.2 即速应用界面介绍

1.菜单栏
菜单栏中的“风格”选项用于设置小程序页面的风格颜色,“管理”选项用于进入后台管理页面,“帮助”选项用于提示帮助功能,“客服”选项用于进入客服界面,“历史”选项用来恢复前项操作,“预览”选项用在PC端预览制作效果,“保存”选项用于保存已制作的内容,“生成”选项用于实现小程序打包上线设置。

2.工具栏
工具栏包括“页面管理”“组件库”2个选项卡,“页面管理”实现添加页面和添加分组以及对某一页面进行改名、收藏、复制、删除操作。“组件库”有9个基础组件、7个布局组件、18个高级组件和2个其他组件。

3.编辑区
编辑区是用来制作小程序页面的主要区域,通过拖拽组件实现页面制作,右边的“前进”“后退”选项可以进行恢复操作,“模板”选项可以用来选择模板,“元素”选项可以用来显示页面中的组件及其层次关系,“数据”选项可以用来进行页面数据管理,“模块”选项可以用来选择模块。

4.属性面板
属性面板用来设置选定组件的属性及样式,包括“组件”和“组件样式”两个选项卡。“组件”选项卡用来设置组件内容及点击事件;“组件样式”选项卡用来设置组件的样式,不同组件有不同的样式需要设置。

5.2 即速应用组件

5.2.1 基础组件

1.文本组件

文本组件是用来编辑文字信息,可以设置字体的大小,字体的样式和位置等。

 2.图片组件

图片组件主要是用来插入图片,或者进行图片模板,设置图片的样式等。

3.按钮组件 

按钮组件是用来拉一个按钮框,可以编辑按钮的文字,也可以设置按钮的类型和样式等。

4.标题组件

标题组件是用来编辑标题的组件,可以编辑标题的文字,样式等。

5.商品列表组件 

商品列表组件是用来设置以下商品的组件,可以设置组件样式,选择模板等。

6.视频组件

视频组件是用来插入视频或者更改其样式,可以选择视频组件的样式 等。

7.轮播组件

轮播组件用于实现图片的轮播展示,可以更改组件样式添加轮播图,以及数据的绑定等。

8.公告组件

公告组件是用来添加公告,可以输入公告信息,添加组件的样式等等。

9.添加其他组合

添加其他组件是用来选择组合模板,如图所示,可以在组合模板库中选择自己喜欢的模板。

5.2.2 应用组件 

2.分割线组件
分割线组件被放置于任意组件之间,用于实现分割。分割线组件的属性面板如图所示。

3.弹窗组件

弹窗组件是用来新建弹窗,可以找模板或者新建弹窗等。

 4.面板组件
面板组件相当于一个大画板,用户可以将很多基本(甚至高级)的组件(如文本组件、图片组件、按钮组件、标题组件、分类组件、音频组件、双栏组件、计数组件等)放进面板组件里一起管理。面板组件的属性面板如图5-5所示。

5.自由面板组件
自由面板组件是指放置在该面板内的组件可以自由拖动,调节组件大小。用户既可以向自由面板内拖入部分组件(包括文本组件、图片组件和按钮组件),也可以拖入任意相关容器组件,用于不规则布局。自由面板组件的属性面板如图5-6所示。

6.滑动面板组件

滑动面板组件是用来设置单面横滑和多面横滑,也可以使用模板等。

7.动态分类组件
动态分类组件仅适用于电商、到店类小程序。用户通过选择动态分类组件的样式,可以实现顶部分类、侧边栏分类来展示应用数据、商品数据等。动态分类的二级有图模式只适用于电商类小程序。

8.分类导航组件

分类导航是用来是用来分类的,分类导航需要和动态分类配合使用,将分类导航和动态分类做数据绑定,小程序端点击导航将跳转至对应的动态分类里面。

9. 侧边栏组件

侧边栏是是设置最左边的背景,可以新建侧边栏也可以使用它原有的侧边栏模板。

10.悬浮窗组件

悬浮窗组件的固定搭配有:客服、我的订单、购物车、回到顶部。悬浮窗组件通常出现在个人中心或商品列表页面。

11.分类横滑组件

分类横滑组件是用来设置一些小零件,可以选择它的样式,添加面板,设置修改标题名称,选择类型等。

5.3 即速应用后台管理

1.数据管理
数据管理包括数据总览、访客分析和传播数据功能。数据总览提供小程序总浏览量、昨日/今日访问量、总用户量、总订单数及浏览量。

2.用户管理
用户管理主要用于实现对用户进行添加、分组、群发消息、储值金充值、赠送会员卡等功能,如图所示。

3. 商品管理
商品管理是后台管理的主要内容,前端商品列表组件的数据来源于后台商品管理。商品管理可以管理商品列表、积分商品、位置管理、支付方式、订单管理、拼团订单管理、订单统计、账单明细、运费管理和评价管理功能。

4.订单管理

订单管理是用来预览订单的,可以查阅订单总览和订单的管理。

5.售后订单

售后订单是用来查阅订单的,可以接收各个平台的订单。

6.营销推广

营销推广可以用来查阅营销的预览跟数据信息展示,有会员卡推销,微信会员卡推销等等。

7.账单总览

 账单总览是用来查看你最近的收入与支出,可以查阅最近七天或者是一天或是年的收录实际情况。

8.店铺管理

店铺管理是用来管理店铺的,可以点击我的店铺进行管理我的店铺,有堂食点餐和行业预约等功能。

 9.功能模块

功能模块是用来了解该功能,可以进入推荐功能进行查阅管理开通,如图所示。

10.系统设置

系统设置有以下功能,支付设置、短信管理、微信小程序设置、子账号设置、云资源 配置、商家助手功能自定义、授权管理、抖音小程序设置、自定义版本交易组件、视频号设置、跨境店铺配置、多商家入驻、导航设置等等。

5.4 打包上传 

第六章

6.1 网络API

微信小程序处理的数据通常从后台服务器获取,再将处理过的结果保存到后台服务器,这就要求微信小程序要有与后台进行交互的能力。微信原生API接口或第三方API提供了各类接口实现前后端交互。
网络API可以帮助开发者实现网络URL访问调用、文件的上传和下载、网络套接字的使用等功能处理。微信开发团队提供了10个网络API接口。
 wx.request(Object)接口 用于发起HTTPS请求。
 wx.uploadFile(Object)接口用于将本地资源上传到后台服务器。

 wx.downloadFile(Object)接口用于下载文件资源到本地。
 wx.connectSocket(Object)接口 用于创建一个WebSocket连接。
 wx.sendSocketMessage(Object)接口 用于实现通过WebSocket连接发送数据。
 wx.closeSocket(Object)接口用于关闭WebSocket连接。
 wx.onSocketOpen(CallBack)接口 用于监听WebSocket连接打开事件。
 wx.onSocketError(CallBack)接口 用于监听WebSocket错误。
 wx.onSocketMessage(CallBack)接口 用于实现监听WebSocket接收到服务器的消息事件。
 wx.onSocketClose(CallBack)接口 用于实现监听WebSocket关闭。
在本节,我们将介绍常用的3个网络API

6.1.1 发起网络请求

js


Page({
  data:{
html:""
  },
getbaidutap:function(){
var that = this;
wx.request({
url:'https://www.baidu.com',//百度网址
data:{},//发送数据为空
header:{'Content-Type':'application/json'},
success:function(res){
console.log(res);
that.setData({
html:res.data
})
}
  })
}
})

wxml 

<button type="primary"bindtap ="getbaidutap">获取 HTML 数据</button>
<textarea value ='{{html}}'auto-heightmaxlength ='0'> </textarea>

js

//postcode.js
Page({
  data:{
  postcode:"",
  address:[],//邮政编码对应的地址
  errMsg:"",
  error_code:-1//错误码
  },
  input:function(e){//输入事件
    this.setData({
  postcode:e.detail.value,
    })
  console.log(e.detail.value)
    },
  find:function(){//查询事件
  var postcode =this.data.postcode;
  if(postcode!=null&& postcode!=""){
  var self =this;
  //显示 toast 提示消息
  wx.showToast({
    title:'正在查询,请稍候....',
  icon: 'loading',
  duration:10000
  });
  wx.request({
  url:'https://v.juhe.cn/postcode/query',
  //第三方后台服务器
  data :{
   ' postcode' :postcode,
  'key':'0ff9bfccdf147476e067de994eb5496e'
  },
  header :{
  'Content-Type ':'application/json',
  },
  method:'GET',//方法为GET
  success:function(res){
    wx.hideToast();//隐藏toast
    if(res.data.error_code==0){
  console.log(res);
  self.setData({
  errMsg:"",
  error_code:res.data.error_code,//错误代码
  address:res.data.result.list//获取到的数据
  })
}
  else{
  self.setData({
  errMsg:res.data.reasonllres.data.reason,//错误原因分析
  error_code:res.data.error_code
  })
  }
  }
  })
  }
  }
  })

wxml

<view>邮政编码:</view >
<input type="text" bindinput="input" placeholder='6位邮政编码'/>
<button type="primary" bindtap="find">查询</button>
<block wx:for="{{address}}">
<block wx:for="{{item}}"><text>{{item}}</text></block>
</block >

6.1.2 上传文件

js

//upload.js
Page({
data:{
img :null,
uploadimage:function(){
var that =this;
//选择图片
wx.chooseImage({
success:function(res){
  var tempFilePaths =res.tempFilePaths
  upload(that,tempFilePaths);
}
})
function upload(page,path){
//显示toast提示消息
wx.showToast({
icon:"loading",
title:"正在上传"
}),
wx.uploadFile({
url:"http://localhost/",
filePath:path[0],
name:'file',
success:function(res){
console.log(res);
if(res.statusCodel=200){
wx.showModal({
title:'提示',
content:'上传失败',
showCancel:false
})
return;
}
var data =res.data
page.setData({ //上传成功修改显示头像
  img:path[0]
})
},
fail:function(e){
console.log(e);
wx.showModal({
title:'提示',
content:'上传失败',
showCancel:false
})
},
complete:function(){//隐藏 Toast
wx.hideToast();
}
})
}
}
}
})

wxml

 
<button type="primary"bindtap="uploadimage">上传图片</button ><image src="../images/ a.jpg"mode="widthFix"/>

6.1.3 下载文件

js

Page({
  data:{
    img:null,
  },
  downloadimage:function(){
    var that = this;
    wx.downloadFile({
      url: "http://localhost/1.jpg", //通过WAMP软件实现
      success:function(res){
        console.log(res)
        that.setData({
          img:res.tempFilePath
        })
      }
    })
  }
 })

wxml

<button type="primary" bind:tap="downloadimge">下载图像</button>
<image src="{{img}}"mode='widthFix'style = "width:90%;height:500px"></image>

6.2 多媒体API

多媒体API主要包括图片API、录音API、音频播放控制API、音乐播放控制API等,其目的是丰富小程序的页面功能。

6.2.1 图片API

图片API实现对相机拍照图片或本地相册图片进行处理,主要包括以下4个API接口:
 wx.chooseImage(Object)接口用于从本地相册选择图片或使用相机拍照。
 wx.previewImage(Object)接口 用于预览图片。

 wx.getImageInfo(Object)接口用于获取图片信息。
 wx.saveImageToPhotosAlbum(Object)接口 用于保存图片到系统相册。
1.选择图片或拍照
wx. chooseImage(Object)接口用于从本地相册选择图片或使用相机拍照。拍照时产生的临时路径在小程序本次启动期间可以正常使用,若要持久保存,则需要调用wx. saveFile保存图片到本地。

若调用成功,则返回tempFilePaths和tempFiles,tempFilePaths表示图片在本地临时文件路径列表。tempFiles表示图片的本地文件列表,包括path和size。

wx.chooseImage({
count:2,//默认值为9
sizeType:['original','compressed'],//可以指定是原图还是压缩图,默认
者都有
sourceType:['album','camera'],//可以指定来源是相册还是相机,默认二者都有
success:function(res){
//返回选定照片的本地文件路径列表,tempFilePath可以作为img标签的src属性来显示图片
var tempFilePaths =res.tempFilePaths
var tempFiles =res.tempFiles;
console.log(tempFilePaths)
console.log(tempFiles)
}
})

2.预览图片
wx. previewImage(Object)接口主要用于预览图片。

3.获取图片信息
wx. getImageInfo(Object)接口用于获取图片信息。

wx.chooseImage({
success:function(res){
wx.getImageInfo({
src:res.tempFilePaths[0], 
success:function(e){ 
console.log(e.width) 
console.log(e.height)
}
})
},
})
wx.chooseImage({
success:function(res){
wx.getImageInfo({
src:res.tempFilePaths[0], 
success:function(e){ 
console.log(e.width) 
console.log(e.height)
}
})
},
})

4.保存图片到系统相册
wx. saveImageToPhotosAlbum(Object)接口用于保存图片到系统相册,需要得到用户授权scope.writePhotosAlbum。

6.2.2 录音API

录音API提供了语音录制的功能,主要包括以下两个API接口:
■ wx.startRecord(Object)接口用于实现开始录音。
■ wx.stopRecord(Object)接口

用于实现主动调用停止录音。
1.开始录音
wx. startRecord(Object)接口用于实现开始录音。当主动调用wx.stopRecord(Object)接口或者录音超过1分钟时,系统自动结束录音,并返回录音文件的临时文件路径。若要持久保存,则需要调用wx. saveFile()接口。

2.停止录音
wx. stopRecord(Object)接口用于实现主动调用停止录音。

wx.startRecord)
({
success: function(res){
var tempFilePath= res.tempFilePath},
fail: function(res){
//录音失败
}
})
setTimeout(function(){//结束录音
wx.stopRecord()
},10000)

6.2.3 音频播放控制API

音频播放控制API主要用于对语音媒体文件的控制,包括播放、暂停、停止及audio组件的控制,主要包括以下3个API:
 wx.playVoice(Object)接口 用于实现开始播放语音。
 wx.pauseVoice(Object)接口用于实现暂停正在播放的语音。

 wx.stopVoice(Object)接口 用于结束播放语音。
1.播放语音
wx. playVoice(Object)接口用于开始播放语音,同时只允许一个语音文件播放,如果前一个语音,如果前一个语音文件还未播放完,则中断前一个语音文件的播放。

wx.startRecord({
success: function(res){
var tempFilePath= res.tempFilePath wx.playVoice({//录音完后立即播放
filePath:tempFilePath, complete:function(){
}
})
}
})

  2.暂停播放
wx. pauseVoice(Object)用于暂停正在播放的语音。再次调用wx.playVoice(Object)播放同一个文件时,会从暂停处开始播放。如果想从头开始播放,则需要先调用wx.stopVoice(Object)。

wx.startRecord({
success: function(res){
var tempFilePath = res.tempFilePath
wx.playVoice({ filePath:tempFilePath
})
 
setTimeout(function(){
//暂停播放
wx.pauseVoice()},5000)
}
})

3.结束播放

wx. stopVoice(Object)用于结束播放语音。

6.2.4 音乐播放控制API

音乐播放控制API主要用于实现对背景音乐的控制,音乐文件只能是网络流媒体,不能是本地音乐文件。音乐播放控制API主要包括以下8个API:
 wx.playBackgroundAudio(Object)接口 用于播放音乐。

 wx.getBackgroundAudioPlayerState(Object)接口 用于获取音乐播放状态。
 wx.seekBackgroundAudio(Object)接口 用于定位音乐播放进度。
 wx.pauseBackgroundAudio()接口 用于实现暂停播放音乐。
wx.stopBackgroundAudio()接口 用于实现停止播放音乐。
 wx.onBackgroundAudioPlay(CallBack)接口 用于实现监听音乐播放。
 wx.onBackgroundAudioPause(CallBack)接口 用于实现监听音乐暂停。
 wx.onBackgroundAudioStop(CallBack)接口 用于实现监听音乐停止。
1.播放音乐
wx. playBackgroundAudio(Object)用于播放音乐,同一时间只能有一首音乐处于播放状态。

wx.playBackgroundAudio({
dataUrl:'http://bmob-cdn-16488.b0.upaiyun.com/2018/02/01/ti.mp3',
title:'有一天',
coverImgUrl:'http://bmob-cdn-16488.b0.upaiyun.com/2018/02/01/si.jpg',
success:function(res){
console.log(res)
}
})

2.获取音乐播放状态
wx.getBackgroundAudioPlayerState(Object)接口用于获取音乐播放状态。

 

 

wx.getBackgroundAudioPlayerState({
 success:function(res){
var status=res.status
var dataUrl=res.dataUrl
var currentPosition=res.currentPosition
var duration=res.duration
var downloadPercent=res.downloadPercent
console.log("播放状态:"+status)
console.log("音乐文件地址:"+dataUrl)
console.log("音乐文件当前播放位置:"+currentPosition)
console.log("音乐文件的长度:"+duration)
console.log("音乐文件的下载进度:"+status)
}
})

3.控制音乐播放进度
wx. seekBackgroundAudio(Object)接口用于控制音乐播放进度。

 

wx.seekBackgroundAudio({
posiyion:30
})

 4.暂停播放音乐
wx. pauseBackgroundAudio()接口用于暂停播放音乐。

wx.playBackgrondAudio{
dataUrl:'/music/a.mp3',
title:'我的音乐',
coverImgUrl:'/images/poster.jpg',
success:function(){
console.log('开始播放音乐了');
}
});
setTimeout(function(){
console.log('暂停播放');
wx.pauseBackgroundAudio();
},5000);

 5.停止播放音乐
wx. stopBackgroundAudio()接口用于停止播放音乐。

wx.playBackgrondAudio{
dataUrl:'/music/a.mp3',
title:'我的音乐',
coverImgUrl:'/images/poster.jpg',
success:function(){
console.log('开始播放音乐了');
}
});
setTimeout(function(){
console.log('暂停播放');
wx.stopBackgroundAudio();
},5000);

6.监听音乐播放
wx. onBackgroundAudioPlay(CallBack)接口用于实现监听音乐播放,通常被wx. playBack-groundAudio(Object)方法触发,在CallBack中可改变播放图标。

wx.playBackgroundAudio({
 dataUrl:this.data.musicData.dataUrl,
title:this.data.musicData.title,
coverImgUrl:this.data.musicData.coverImgUrl,
success:function(){
wx.onBackgroundAudioStop(function(){
that.setData({
isPlayingMusic:false
})
})

7.监听音乐暂停
wx. onBackgroundAudioPause(CallBack)接口用于实现监听音乐暂停,通常被wx. pause-BackgroundAudio()方法触发。在CallBack中可以改变播放图标。
8.监听音乐停止
wx. onBackgroundAudioStop(CallBack)接口用于实现监听音乐停止,通常被音乐自然播放停止或wx.seekBackgroundAudio(Object)方法导致播放位置等于音乐总时长时触发。在CallBack中可以改变播放图标。
9.案例展示
在此,以小程序music为案例来展示音乐API的使用。该小程序的4个页面文件分别为music. wxml、music.wxss、music. json和music. cojs。

js

Page({
  data:{
   //记录播放状态
  isPlaying:false,
  //记录coverImg,仅当音乐初始时和播放停止时,使用默认的图片。播放中和暂停时,都使用当前音乐的图片
  coverImgchangedImg:false,	
  //音乐内容 
  music:{
  "url":"../images/e e.mp4",
  "title":"盛晓玫-有一天",
  "coverImg":
  "../images/e e.mp4"
  	},
  },	
  onLoad:function(){	
  	//页面加载时,注册监听事件	
  	this.onAudioState();	
  	},	
//点击播放或者暂停按钮时触发
	onAudioTap:function(event){	
  if(this.data.isPlaying){
  //如果在正常播放状态,就暂停,并修改播放的状态
  	wx.pauseBackgroundAudio();	
  	}else{	
 //如果在暂停状态,就开始播放,并修改播放的状态28 
 let music = this.data.music;
  	wx.playBackgroundAudio({	
  	dataUrl: music.url,	
  	title: music.title,	
  	coverImgUrl:music.coverImg	
    })	
  }
},
//点击即可停止播放音乐	
	onStopTap:function(){	
   let that = this;
	wx.stopBackgroundAudio({	
	success:function(){	
	//改变coverImg和播放状态	
  that.setData({ isPlaying:false,changedImg:false});
  }
})	
},
 //点击“快进10秒”或者“快退10秒”时,触发
	onPositionTap:function(event){	
 let how = event.target.dataset.how;//获取音乐的播放状态
	wx.getBackgroundAudioPlayerState({	
	success:function(res){	
//仅在音乐播放中,快进和快退才生效	
//音乐的播放状态,1表示播放中54 
let status = res.status;
 if(status === 1){//音乐的总时长
let duration = res.duration;//音乐播放的当前位置
let currentPosition = res.currentPosition;
if(how ==="0"){
//注意:快退时,当前播放位置快退10秒小于0时,直接设置position为1;否则,直接减去10秒//快退到达的位置
let position = currentPosition - 10;
if(position <0){
position =1;//执行快退	
}
wx.seekBackgroundAudio({	
position: position	
});	
//给出一个友情提示,在实际应用中,请删除!!!
wx. showToast({title:"快退10s",duration:500});
}	
if(how === "1"){//注意:快进时,当前播放位置快进10秒后大于总时长时,直接设置position 为总时长减1
//快进到达的位置
let position =currentPosition +10;
if(position >duration){
position =duration-1;//执行快进	
}
wx.seekBackgroundAudio({	
position: position});//给出一个友情提示,在实际应用中,请删除!!!
wx.showToast({ title:"快进10s",duration:500});
}	
}else {	//给出一个友情提示,在实际应用中,请删除!!!
wx.showToast({title:"音乐未播放",duration:800});	
  }	
}
})
},//音乐播放状态	
onAudioState:function(){	
let that =this;
wx.onBackgroundAudioPlay(function(){//当wx.playBackgroundAudio()执行时触发101 //改变coverImg和播放状态
that.setData({ isPlaying:true,changedImg:true});	
console.log("on play");	
});	
wx.onBackgroundAudioPause(function(){	//当wx.pauseBackgroundAudio()执行时触发//仅改变播放状态
that.setData({isPlaying:false});
console.log("on pause");	
});	
wx.onBackgroundAudioStop(function(){	//当音乐自行播放结束时触发//改变coverImg和播放状态
that.setData({isPlaying:false,changedImg:false});	
console.log("on stop");	
});	
}
})

wxml

<view class="container">
<image class="bgaudio"src = "{{changedImg? music.coverImg:'../images/a.jpg'}}"/>
<view class ="control-view">
<!--使用data-how定义一个0表示快退10秒-->
<image src ="../images/a.jpg"bindtap="onPositionTap"data-how= "0 "/>
<image src = "../images/a.jpg" bindtap = "onAudioTap"/>
<image src ="../images/a.jpg"bindtap = "onStopTap"/><!--使用data-how定义一个1表示快进10秒-->
<image src ="../images/a.jpg"bindtap ="onPositionTap"data-how = "1"/>
</view >
</view >

wxss

.bgaudio{
  height:350rpx; width:350rpx;
  margin-bottom:100rpx;
}
  .control-view image{ 
  height:64rpx;
     width:64rpx; 
     margin:30rpx;
}

 

6.3 文件API

网络上下载或录音的文件都是临时保存的,若要持久保存,需要用到文件API。文件API提供了打开、保存、删除等操作本地文件的能力,主要包括以下5个API接口:
■ wx.saveFile(Object)接口 用于保存文件到本地。
■ wx.getSavedFileList(Object)接口 用于获取本地已保存的文件列表。
■ wx.getSaveFileInfo(Object)接口 用于获取本地文件的文件信息。
■ wx.removeSaveFile(Object)接口 用于删除本地存储的文件。
■ wx.openDocument(Object)接口 用于新开页面打开文档,支持格式:doc、xls、ppt、pdf、docx、xlsx、ppts。
1.保存文件
wx. saveFile(Object)用于保存文件到本地。

saveImg:function()
wx.chooseImage(
count:1,/默认值为9
sizeType:['original',compressed],/可以指定是原图还是压缩图,默认
者都有
sourceType:[album,camera’],/可以指定来源是相册还是相机,默认二
都有
success:function(res)var tempFilePaths =res.tempFilePaths0wx.saveFile(tempFilePath:tempFilePathssuccess:function(res)var saveFilePath =res.savedFilePath;
console.1og(saveFilePath)

 2.获取本地文件列表
wx. getSavedFileList(Object)接口用于获取本地已保存的文件列表,如果调用成功,则返回文件的本地路径、文件大小和文件保存时的时间戳(从1970/01/01 08: 00: 00到当前时间的秒数)文件列表。

wx.getSavedFileList(
success:function(res)
that.setData(
fileList:res.fileList

 3.获取本地文件的文件信息
wx. getSaveFileInfo(Object)接口用于获取本地文件的文件信息,此接口只能用于获取已保存到本地的文件,若需要获取临时文件信息,则使用wx. getFileInfo(Object)接口。

wx.chooseImage(
count:1,/默认值为9sizeType:['original',compressed],/可以指定是原图还是压缩图,默认
二者都有
sourceType:['album',camera’],/可以指定来源是相册还是相机,默认二者
都有
success:function(res)var tempFilePaths =res.tempFilePaths0wx.saveFile(tempFilePath:tempFilePaths,success:function(res)var saveFilePath =res.savedFilePath;wx.getSavedFileInfo(
filePath:saveFilePath,success:function(res)
console.1og(res.size)

 

 4.删除本地文件
wx. removeSaveFile(Object)接口用于删除本地存储的文件。

wx.getSavedFileList({
      success:function(res){
        if(res.fileList.length>0){
          wx.removeSavedFile({
            filePath:res.fileList[0].filePath,
            complete:function(res){
              console.log(res)
            }
          })
        }
      }
    })

 

5.打开文档
wx. openDocument(Object)接口用于新开页面打开文档,支持格式有doc、xls、ppt、pdf、docx、xlsx、pptx。

 
wx.downloadFile({
  url:"../images/tu2.png",
  success:function(res){
    var tempFilePath=res.tempFilePath;
    wx.openDocument({
      filePath: tempFilePath,
      success:function(res){
        console.log("打开成功")
      }
    })
  }
  })

6.4 本地数据缓存API

小程序提供了以键值对的形式进行本地数据缓存功能,并且是永久存储的,但最大不超过10 MB,其目的是提高加载速度。数据缓存的接口主要有4个:
 wx.setStorage(Object)或wx.setStorageSync(key, data)接口 用于设置缓存数据。
 wx.getStorage(Object)或wx.getStorageSync(key)接口 用于获取缓存数据。
 wx.removeStorage(Object)或wx.removeStorageSync(key)接口 用于删除指定缓存数据。

 wx.clearStorage()或wx.clearStorageSync()接口 用于清除缓存数据。
其中,带Sync后缀的为同步接口,不带Sync后缀的为异步接口。

6.4.1 保存数据

1. wx. setStorage(Object)
wx. setStorage(Object)接口将数据存储到本地缓存接口指定的key中,接口执行后会覆盖原来key对应的内容。

wx.setStorage({
Key:'name',
data:'sdy',
success:function(res){
console.log(res)
}
})

 

2. wx. setStorageSync(key, data)
wx. setStorageSync(key, data)是同步接口,其参数只有key和data。

wx.getStorageSync('age','25')

6.4.2 获取数据


1. wx. getStorage(Object)
wx. getStorage(Object)接口是从本地缓存中异步获取指定key对应的内容。

wx.getstorage({ key:'name',
success:function(res){ 
console.log(res.data)
},
})

2. wx. getStorageSync(key)
wx. getStorageSync(key)从本地缓存中同步获取指定key对应的内容。其参数只有key。

try{
var value = wx.getstorageSync('age')
 if(value){
console.log("获取成功"+value)
} 
catch(e){
console.log("获取失败")
}

6.4.3 删除数据


1. wx. removeStorage(Object)
wx. removeStorage(Object)接口用于从本地缓存中异步移除指定key。

wx.removeStorage({
 key:'name',
success:function(res){ console.log("删除成功")
},
fail:function(){
console.log("删除失败")
}
 
})

2. wx. removeStorageSync(key)
wx. removeStorageSync(key)接口用于从本地缓存中同步删除指定key对应的内容。 

try {
wx.removeStorageSync('name')
} catch(e){
//Do something when catch error
}

6.4.4 清空数据


1. wx. clearStorage()
wx. clearStorage()接口用于异步清理本地数据缓存,没有参数。

wx.getStorage({
key:'name',
success:function(res){
wx.clearStorage()
},
})

2.wx.clearStroageSync()

wx.clearStroageSync()接口用于同步清理本地数据缓存。

try{
wx.clearStorageSync()
}catch(e){
}

 6.5 位置信息API

小程序可以通过位置信息API来获取或显示本地位置信息,小程序支持WGS84和GCj02标准,WGS84标准为地球坐标系,是国际上通用的坐标系;GCj02标准是中国国家测绘局制定的地理信息系统的坐标系统,是由WGS84坐标系经加密后的坐标系,又称为火星坐标系。默认为WGS84标准,若要查看位置需要使用GCj02标准。主要包括以下3个API接口:
 wx.getLocation(Object)接口用于获取位置信息。
 wx.chooseLocation(Object)接口 用于选择位置信息。
 wx.openLocation(Object)接口用于通过地图显示位置。

6.5.1 获取位置信息


wx. getLocation(Object)接口用于获取当前用户的地理位置、速度,需要用户开启定位功能,当用户离开小程序后,无法获取当前的地理位置及速度,当用户点击“显示在聊天顶部”时,可以获取到定位信息。

 

wx.getLocation({ 
  type:'wgs84',
success:function(res){
console.log("经度:"+res.longitude); console.log("纬度:"+res.latitude); console.log("速度:"+res.longitude);
console.log("位置的精确度:"+res.accuracy);
console.log("水平精确度:"+res.horizontalAccuracy); console.log("垂直精确度:"+res.verticalAccuracy);},
})

6.5.2 选择位置信息


wx. chooseLocation(Object)接口用于在打开的地图中选择位置,用户选择位置后可返回当前位置的名称、地址、经纬度信息。

 

 

wx.getLocation({
  type:'gcj02',//返回可以用于wx.openLocation的经纬度
  success:function(res){
  var latitude = res.latitude 
  var longitude= res.longitude
  wx.openLocation({
  latitude: latitude, 
  longitude:longitude, 
  scale:10,
  name:'智慧国际酒店',
  address:'西安市长安区西长安区300号'})
}
})

6.6设备相关API
设备相关的接口用于获取设备相关信息,主要包括系统信息、网络状态、拨打电话及扫码等。主要包括以下5个接口API:
 wx.getSystemInfo(Object)接口、wx.getSystemInfoSync()接口 用于获取系统信息。
 wx.getNetworkType(Object)接口 用于获取网络类型。
 wx.onNetworkStatusChange(CallBack)接口 用于监测网络状态改变。
 wx.makePhoneCall(Object)接口 用于拨打电话。

 wx.scanCode(Object)接口 用于扫描二维码

6.6.1 获取系统信息

wx. getSystemInfo(Object)接口、wx. getSystemInfoSync()接口分别用于异步和同步获取系统信息。

wx.getSystemInfo({
  success:function(res){
  console.log("手机型号:"+res.model)
  console.log("设备像素比:"+res.pixelRatio)
   console.log("窗口的宽度:"+ res.windowWidth) 
  console.log("窗口的高度:"+res.windowHeight) 
  console.log("微信的版本号:"+res.version) 
  console.log("操作系统版本:"+ res.system) 
  console.log("客户端平台:"+res.platform)},})

 

6.6.2 网络状态

1.获取网络状态
wx. getNetworkType(Object)用于获取网络类型。

 

wx.getNetworkType({
  success:function(res){
  console.log(res.networkType)},})

2.监听网络状态变化

wx. onNetworkStatusChange(CallBack)接口用于监听网络状态变化,当网络状态变化时,返回当前网络状态类型及是否有网络连接。

wx.onNetworkStatusChange(function(res){
  console.log("网络是否连接:"+res.isConnected) 
  console.log("变化后的网络类型"+res.networkType)})

6.6.3 拨打电话

wx. makePhoneCall(Object)接口用于实现调用手机拨打电话。

 

wx.makePhoneCall({
phoneNumber:'18092585093'//需要拨打的电话号码
})

6.6.4 扫描二维码
 

wx. scanCode(Object)接口用于调起客户端扫码界面,扫码成功后返回相应的内容。

//允许从相机和相册扫码
 wx.scanCode({
  success:(res) =>{
  console.log(res.result) 
  console.log(res.scanType) 
  console.log(res.charSet) 
  console.log(res.path)
  }
  })
  
  //只允许从相机扫码
   wx.scanCode({
  onlyFromCamera:true,
   success:(res) =>{ 
     console.log(res)
   }
  })

<view style="margin-top: 20px;">
<button type="primary" bindtap="getSystemInfo">
获取系统信息</button> </view>
<view style="margin-top: 20px;">
<button type="primary" bindtap="getNetworkType">
获取网络信息</button> </view>
<view style="margin-top: 20px;">
<button type="primary" bindtap="makePhoneCall">
拨打电话</button> </view>
<view style="margin-top: 20px;">
<button type="primary" bindtap="scanCode">
相机和相机扫码</button> </view>
<view style="margin-top: 20px;">
<button type="primary" bindtap="scanCodebd">
相机扫码</button> </view>
 

const app = getApp()
Page({
  data:{
 
  },
  getSystemInfo:function(){
   wx.getSystemInfo({
     success:function(res){
       console.log("手机型号"+res.model)
       console.log("设置像素比"+res.pixelRatio)
       console.log("窗口的宽度"+res.windowWidth)
       console.log("窗口的高度"+res.windowHeight)
       console.log("微信的版本号"+res.version)
       console.log("操作系统版本"+res.system)
       console.log("客户端平台"+res.platform)
     }
   })
  },
  getNetworkType:function(){
wx.getNetworkType({
  success:function(res){
    console.log(res.networkType)
  }
})
  },
  onNetworkStatusChange:function(){
    wx.onNetworkStatusChange(function(res){
console.log("网络是否连接:"+res.isConnected)
console.log("变化后网络类型"+res.networkType)
    })
    
 
},
makePhoneCall:function(){
wx.makePhoneCall({
  phoneNumber: '18279850186',
})
},
scanCode:function(){
  wx.scanCode({
    success:(res)=>{
      console.log(res.result)
      console.log(res.scanType)
      console.log(res.charSet)
      console.log(res.path)
    }
  })
},
scanCodebd:function(){
  wx.scanCode({
    onlyFromCamera:true,
    success:(res)=>{
      console.log(res)
    }
  })
}
 
})

  • 23
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值