# 小程序

官方文档地址

# 1. 基础部分

本篇文章旨在快速上手小程序,在有 Vue 作为前置知识的情况下,理解。

# 1.1 rpx wxss

# wxss小程序样式特性:

尺寸单位 rpx 核心点。移动设备的分辨率与rpx:

设备 屏幕尺寸 分辨率(px) reader 分辨率(pt) PPI(DPI)
iPhone 3GS 3.5 320*480 @1x 320*480 163
iPhone 4/4s 3.5 640*960 @2x 320*480 326
iPhone 5/5S/5C 4 640*1136 @2x 320*568 326
iPhone 6/6S 4.7 750*1334 @2x 375*667 326
iPhone 6/6S Plus 5.5 1242*2208 @3x 414*736 401

通常以 iphone6s 为基准

rpx.png PPI.png

假设设计稿就按照iphone6S的尺寸来模拟,UI工程师给我们的素材是750宽的,换算到小程序的px那就是375px即750rpx。

以iphone 6s设备的尺寸作为基准值定义在 iPhone 6s的情况下 一个物理分辨率=1rpx=0.5px 然后在不同的分辨率的情况下, 我们把rpx与px的换算比率进行自动调整

750rpx.png
设备 rpx换算px (屏幕宽度/750) px换算rpx (750/屏幕宽度)
iPhone5 1rpx = 0.42px 1px = 2.34rpx
iPhone6 1rpx = 0.5px 1px = 2rpx
iPhone6 Plus 1rpx = 0.552px 1px = 1.81rpx

# wxss 选择器

选择器 样例 样例描述
.class .intro 选择所有拥有 class="intro" 的组件
#id #firstname 选择拥有 id="firstname" 的组件
element view 选择所有 view 组件
element, element view, checkbox 选择所有文档的 view 组件和所有的 checkbox 组件
::after view::after 在 view 组件后边插入内容
::before view::before 在 view 组件前边插入内容

wxss 不支持 > + ~ 等等,推荐使用类名选择器

  • 样式导入
@import './test.wxss';/**会被编译到目标文件,不会产生多与文件请求**/
@import url('/test.wxss');/**这种写法,不会打包合并,会产生文件请求**/
  • 样式优先级

!important:∞ > 内联style:1000 > #id:100 > .class:10 > 标签选择器element:1

# 1.2 小程序结构

wxapp01.png wxapp02.png

# 入口文件 app.js

//app.js
App({
    
})

地位类似于 Vue 里面的 index.js 整个小程序只有一个 App 实例,是全部页面共享的。开发者可以通过 getApp 方法获取到全局唯一的 App 实例,获取App上的数据或调用开发者注册在 App 上的函数。

鉴于小程序没有类似Vuex之类的全局的数据管理工具,因此一般我们需要在多个页面使用到的变量数据,就存在app.js里面的globalData里面。

# 全局配置文件 app.json

app.json 是当前小程序的全局配置,包括了小程序的所有页面路径、界面表现、网络超时时间、底部 tab 等。

{
    "pages":[
        "pages/index/index",
        "pages/logs/logs"
    ],
    "window":{
        "backroundTextStyle":"light",
        "navigationBarBackgroundColor":"#fff",
        "navigationBarTitleText":"WeChat",
        "navigationBarTextStyle":"black"
    },
    "style":"v2",
    "sitemapLocation":"sitemap.json"
}

pages字段:用于描述当前小程序所有页面路径,这是为了让微信客户端知道当前你的小程序页面定义在哪个目录。当我们新建页面时,根据新建方法的不同,需要检查pages。也可以直接在pages新增配置来自动创建页面。

window字段: 定义小程序所有页面的顶部背景颜色,文字颜色定义等。

style字段:指定使用weui样式的版本。

sitemapLocation:指明 sitemap.json 的位置。

# 1.3 小程序生命周期

App({
  onLaunch (options) {
    // 小程序初始化完成时触发,全局只触发一次。参数也可以使用 wx.getLaunchOptionsSync 获取。
  },
  onShow (options) {
    // 小程序启动,或从后台进入前台显示时触发。也可以使用 wx.onAppShow 绑定监听。
  },
  onHide () {
    // 小程序从前台进入后台时触发。也可以使用 wx.onAppHide 绑定监听。
  },
  onError (msg) {
    // 小程序发生脚本错误或 API 调用报错时触发。也可以使用 wx.onError 绑定监听。
  },
  globalData: 'I am global data'
})

# 1.4 小程序页面生命周期

page生命周期是微信客户端根据用户操作主动处罚的

onLoad: function(options) {
	// 页面创建时执行,页面销毁前只会触发一次,在这里可以拿到上一个页面传递的数据
},
onShow: function() {
	// 页面出现在前台时执行,页面第一次显示、从其他页面返回都会触发
},
onReady: function() {
	// 页面首次渲染完毕时执行,页面销毁前只会触发一次
},
onHide: function() {
	// 页面从前台变为后台时执行,使用 wx.navigateTo 跳转,或底部tab切换页面会触发
},
onUnload: function() {
	// 页面销毁时执行,使用 wx.redirectTo 或 wx.navigateBack 返回,当前页面被销毁
}

# 1.5 用户行为

onPullDownRefresh: function() {
	// 触发下拉刷新时执行
},
onReachBottom: function() {
	// 页面触底时执行
},
onShareAppMessage: function () {
	// 页面被用户分享时执行
},
onPageScroll: function() {
	// 页面滚动时执行
},
onResize: function() {
	// 页面尺寸变化时执行
},

# onPullDownRefresh

文档:API>界面>下拉刷新>wx.startPullDownRefresh

监听用户下拉

需要在app.jsonwindow选项中或页面配置中开启enablePullDownRefresh

可以通过wx.startPullDownRefresh触发下拉刷新,调用后触发下拉刷新动画,效果与用户手动下拉刷新一致。

当处理完数据刷新后,wx.stopPullDownRefresh可以停止当前页面的下拉刷新。

"enablePullDownRefresh":true

# onShareAppMessage

定义此方法后,右上角才会显示分享按钮,需要 return 一个配置对象,自定义分享内容。

onShareAppMessage: function () {
    return {
        title:'自定义转发标题',
        path:'转发路径,默认当前页面 path ,必须是以 / 开头的完整路径',
        imageUrl:'自定义图片路径,可以是本地文件路径、代码包文件路径或者网络图片路径。支持PNG及JPG。显示图片长宽比是 5:4,默认为截图'
    }
}

# 1.6 简易双向数据绑定

文档:指南>小程序框架>视图层>简易双向绑定

只能是一个单一字段的数据,不能绑定对象的某个属性

<input model:value="{{inputVal}}"/>

# 1.7 事件

官方文档详解

类型 触发条件
touchstart 手指触摸动作开始
touchmove 手指触摸后移动
touchcancel 手指触摸动作被打断,如来电提醒,弹窗
touchend 手指触摸动作结束
tap 点击,手指触摸后马上离开
longpress 手指触摸后,超过350ms再离开,如果指定了事件回调函数并触发了这个事件,tap事件将不被触发
longtap 长按,手指触摸后,超过350ms再离开(推荐使用longpress事件代替)
transitionend 会在 WXSS transition 或 wx.createAnimation 动画结束后触发
animationstart 会在一个 WXSS animation 动画开始时触发
animationiteration 会在一个 WXSS animation 一次迭代结束时触发
animationend 会在一个 WXSS animation 动画完成时触发
touchforcechange 在支持 3D Touch 的 iPhone 设备,重按时会触发

事件绑定:bind

<view bindtap="handleTap">
    Click here!
</view>

绑定并阻止事件冒泡:catch

<view catchtap="handleTap">
    Click here!
</view>

# 1.8 setData 方法

官方文档地址

setData(data,callBack);//callBack在本次setData对界面渲染完毕后触发

原则上:每次只设置需要改变的最小单位数据,同一个事件里合并多次setData

# setData理解

Page实例原型中中setData方法,小程序的渲染层 WebView 和逻辑层 JavascriptCore 是在两个线程中运行,彼此独立,并不具备数据直接共享的通道。当前,视图层和逻辑层的数据传输,实际上通过两边提供的 evaluateJavascript 所实现。即用户传输的数据,需要将其转换为字符串形式传递,同时把转换后的数据内容拼接成一份 JS 脚本,再通过执行 JS 脚本的形式传递到两边独立环境。

# setData几种操作不可取

  • 1.频繁调用setData

部分小程序非常频繁(毫秒级)的去setData,其导致了两个后果:

Android 下用户在滑动时会感觉到卡顿,操作反馈延迟严重,因为 JS 线程一直在编译执行渲染,未能及时将用户操作事件传递到逻辑层,逻辑层亦无法及时将操作处理结果及时传递到视图层;

渲染有出现延时,由于 WebView 的 JS 线程一直处于忙碌状态,逻辑层到页面层的通信耗时上升,视图层收到的数据消息时距离发出时间已经过去了几百毫秒,渲染的结果并不实时;

  • 2.每次setData传递大量数据

setData的底层实现可知,我们的数据传输实际是一次 evaluateJavascript 脚本过程,当数据量过大时会增加脚本的编译执行时间,占用 WebView JS 线程。

  • 3.后台页面进行setData

当页面进入后台态(用户不可见),不应该继续去进行setData,后台态页面的渲染用户是无法感受的,另外后台态页面去setData也会抢占前台页面的执行。

# 1.9 插值

文档地址:框架>WXML语法参考>数据绑定

数据用双花括号插值,可以进行运算,简单的三目,算术,逻辑运算等。

<view>
	{{message}}
</view>
<input model:value="{{message}}"/>

# 1.10 条件渲染

文档地址:框架>WXML语法参考>条件渲染

wx:if条件渲染符合 vue 语法,判断多个组件或标签时可使用<block></block>占位标签,减少无意义标签。

<view wx:if="{{}}">one</view>
<view wx:elif="{{}}">one</view>
<view wx:else>one</view>

hidden相当于 Vue v-show,组件始终会被渲染,只是简单的控制显示与隐藏。

如果频繁切换状态,wx:if控制组件销毁和渲染,会产生非常大的性能开销,使用hidden优化。

# 1.11 列表渲染

文档地址:框架>WXML语法参考>列表渲染

wx:for,默认数组的当前项的下标变量名默认为 index,数组当前项的变量名默认为 item ,可使用<block></block>占位标签,减少无意义标签。

<view wx:for="{{List}}">
	{{index}}--{{item}}
</view>

需要指定别名:

<view wx:for="{{List}}" wx:for-index='idx' wx:for-item='itemName'>
	{{idx}}--{{itemName}}
</view>

wx:key同样,key唯一标识很重要

# 1.12 template模板

文档地址:框架>WXML语法参考>模板

新建模板/template/list-template/list-template.wxml,模板样式/template/list-template/list-template.wxss,检查app.json pages注册。

模板和组件场景,如果没有交互,用模板。

<!--list-template.wxml-->
<template name='list'>
	<view class='list-wrapper'>
    	<text class='list-text'>{{templateData.msg}}--hello world</text>
    </view>
</template>
/**list-template.wxss**/
.list-wrapper{
    background-color:#ddd;
}
.list-text{
    color:red;
    font-size:16px;
}

使用模板

<!--index.wxml-->
<import src='/template/list-template/list-template.wxml'/>
<view>
    <template is='list' data='{{templateData}}'></template>
</view>

样式需要单独引入

/**index.wxss**/
@import '/template/list-template/list-template.wxss';

# 1.13 全局变量

文档地址:指南>小程序框架>逻辑层>模块化

通过全局函数 getApp 可以获取全局的应用实例,如果需要全局的数据可以在 App() 中设置,如:

//app.js 入口文件中定义,保证后续都能访问
App({
    globalData: 1
})
//在 a.js 访问
console.log(getApp().globalData)
//在 b.js 访问
var app = getApp()
app.globalData++

# 1.14 页面跳转,页面栈概念

路由方式 触发时机 路由前页面 路由后页面
初始化 小程序打开的第一个页面 onLoad, onShow
打开新页面 调用 API wx.navigateTo 使用组件 `` onHide onLoad, onShow
页面重定向 调用 API wx.redirectTo 使用组件 `` onUnload onLoad, onShow
页面返回 调用 API wx.navigateBack 使用组件`` 用户按左上角返回按钮 onUnload onShow
Tab 切换 调用 API wx.switchTab 使用组件 `` 用户切换 Tab 各种情况请参考下表
重启动 调用 API wx.reLaunch 使用组件 `` onUnload onLoad, onShow

wx.navigateTo()和wx.redirectTo()只能打开非tabBar页面。

使用 wx.navigateBack 可以返回到原页面。小程序中页面栈最多十层。

# wx.navigateTo()

文档:API>路由>wx.navigateTo

保留当前页面,跳转到应用内的某个页面,但是不能跳到 tabbar 页面。

参数:

属性 类型 默认值 必填 说明
url string 需要跳转的应用内非 tabBar 的页面的路径 (代码包路径), 路径后可以带参数。参数与路径之间使用 ? 分隔,参数键与参数值用 = 相连,不同参数用 & 分隔;如 'path?key=value&key2=value2'
events Object 页面间通信接口,用于监听被打开页面发送到当前页面的数据。基础库 2.7.3 开始支持。
success function 接口调用成功的回调函数
fail function 接口调用失败的回调函数
complete function 接口调用结束的回调函数(调用成功、失败都会执行

# 页面栈

文档:指南>小程序框架>页面路由

wx.navigateTo()使用两次后,页面层级有3层,这样的页面层级关系就是页面栈,页面栈最多十层。

首页pageAwx.navigateTo()-->页面pageBwx.navigateTo()-->详情页pageC

描述为:[pageA,pageB,pageC],C是当前所处页面,最上层,A为最根层。

当前页pageC wx.navigateTo(url:pageD)-->[pageA,pageB,pageC,pageD]

  • # 结合页面生命周期理解:

当前页pageD wx.navigateBack() -->[pageA,pageB,pageC],此时D被回收调用pageD.onUnload(),pageC.onShow()

当前页pageC wx.redirectTo(url:pageE) -->[pageA,pageB,pageE],此时pageC.onUnload(),pageE.onLoad(),pageE.onshow(),pageE.onReady()

  • # 结合tabBar

tabBar:{
    "list":[
        {"text":"tab1","pagePath":"pageA"},
        {"text":"tab2","pagePath":"pageF"},
        {"text":"tab3","pagePath":"pageG"},
    ]
}

当前页pageE wx.switchTab(url:pageF),此时原来的页面栈会被全部清空(除了pageA)。此时的页面栈 [pageF],此时点击 tab1 切换到 pageA ,pageA 不会触发 onLoad(),pageA没有被销毁。

# 页面通信

文档:API>路由>wx.navigateTo

如果一个页面由另一个页面通过 wx.navigateTo 打开,这两个页面间将建立一条数据通道:

  • 被打开的页面可以通过 this.getOpenerEventChannel() 方法来获得一个 EventChannel 对象;
  • wx.navigateTosuccess 回调中也包含一个 EventChannel 对象。

这两个 EventChannel 对象间可以使用 emiton 方法相互发送、监听事件。

# 1.15 wx.request

文档地址:API>网络>发起请求

属性 类型 默认值 必填 说明 最低版本
url string 开发者服务器接口地址
data string/object/ArrayBuffer 请求的参数
header Object 设置请求的 header,header 中不能设置 Referer。 content-type 默认为 application/json
timeout number 超时时间,单位为毫秒 2.10.0
method string GET HTTP 请求方法
dataType string json 返回的数据格式
responseType string text 响应的数据类型 1.7.0
enableHttp2 boolean false 开启 http2 2.10.4
enableQuic boolean false 开启 quic 2.10.4
enableCache boolean false 开启 cache 2.10.4
success function 接口调用成功的回调函数
fail function 接口调用失败的回调函数
complete function 接口调用结束的回调函数(调用成功、失败都会执行)

示例:

wx.request({
  url: 'test.php', //仅为示例,并非真实的接口地址
  data: {
    x: '',
    y: ''
  },
  header: {
    'content-type': 'application/json' // 默认值
  },
  success (res) {
    console.log(res.data)
  }
})

# 1.16 云函数

云函数文档:云开发>基础>云开发能力>云函数

云开发简单理解就是一个nodejs服务

云开发注意问题:需要安装依赖,云函数本地调试报错是由于热更新,逻辑没写完,不用管。

// 云函数入口文件
const cloud = require('wx-server-sdk')
cloud.init()
// 云函数入口函数
exports.main = async (event, context) => {
    const wxContext = cloud.getWXContext()
    return {//返回一个对象
        event,
        openid: wxContext.OPENID,
        appid: wxContext.APPID,
        unionid: wxContext.UNIONID,
    }
}

调用云函数

wx.cloud.init();
wx.cloud.callFunction({
    name:'云函数名',
    data:{
        //要发送给云函数的数据
    },
    success(res){
        console.log(res)
    }
})

# 云函数定时触发器

云函数文档:云开发>开发指引>云函数>定时触发器

如果云函数需要定时 / 定期执行,也就是定时触发,我们可以使用云函数定时触发器。配置了定时触发器的云函数,会在相应时间点被自动触发,函数的返回结果不会返回给调用方。

在需要添加触发器的云函数目录下新建文件 config.json,格式如下:

{
  // triggers 字段是触发器数组,目前仅支持一个触发器,即数组只能填写一个,不可添加多个
  "triggers": [
    {
      // name: 触发器的名字,规则见下方说明
      "name": "myTrigger",
      // type: 触发器类型,目前仅支持 timer (即 定时触发器)
      "type": "timer",
      // config: 触发器配置,在定时触发器下,config 格式为 cron 表达式,规则见下方说明
      "config": "0 0 2 1 * * *"
    }
  ]
}

config触发器触发周期,标准corn表达式

第一位 第二位 第三位 第四位 第五位 第六位 第七位
分钟 小时 星期

!!!!!!配置完成记得上传触发器

# 1.17 数据库

数据库文档:云开发>开发指引>数据库

需要注意:云函数里使用数据库操作只能用 promise 不能用回调,回调有问题,并且小程序容易抽风,重启解决大部分问题。

小程序数据库是文档型数据库,类似mongodb,比关系型数据库简单。

# 获取数据库引用

const db = wx.cloud.database()

# 连接集合

const todos = db.collection('message')//连接message集合

# 添加数据

// addMessage云函数入口文件
const cloud = require('wx-server-sdk')
cloud.init()
let db = cloud.database()//获取数据库引用
// 云函数入口函数
exports.main = async (event, context) => {
    return new Promise((resolve, reject) => {
        db.collection('message').add({//连接message集合
            data: {
                age:event.age,
                author:event.author,
                content: event.content,
                time: new Date().toLocaleString()
            }
        }).then((res) => {
            console.log(res);
            resolve(res);
        }).catch((err) => {
            resolve(err);
        })
    })
}
//通过云函数调用
addMessage(){
    wx.cloud.callFunction({
        name:'addMessage',//云函数名
        data:{//传递数据给云函数
            age:'18',
            author:'十月',
            content:'第一条数据,今天五月18日'
        },
        success(res){
        	console.log(res)//添加成功返回的是数据的_id
        }
    })
},

# 查询

文档:云开发>开发指引>数据库>增删改查SDK>查询

where 方法接收一个对象参数,该对象中每个字段和它的值构成一个需满足的匹配条件,各个字段间的关系是 "与" 的关系,即需同时满足这些匹配条件

// getMessage云函数入口文件
const cloud = require('wx-server-sdk')
cloud.init()
let db = cloud.database()
// 云函数入口函数
exports.main = async (event, context) => {
    return new Promise((resolve,reject)=>{
        db.collection('message').where({//where查询条件
            author:event.author
        }).get().then(res=>{//get()返回的是promise
            resolve(res)
        })
    })
}
//通过云函数调用
getMessage(){
    wx.cloud.callFunction({
        name:'getMessage',//云函数名
        data:{//传递数据给云函数
        	author:'十月'
        },
        success(res){
        	console.log(res.result.data)//查询得到的数据是array
        }
    })
},

不使用云函数,直接查询也可以。

//promise写法,get()返回的是promise
getMessage(){
    wx.cloud.database().collection('message').where({
    	author:'十月'
    }).get().then((res)=>{
    	console.log(res.data);
    })
},
//get()回调写法
getMessage(){
    wx.cloud.database().collection('message').where({
    	author:'十月'
    }).get({
        success(res){
            console.log(res.data);
        }
    })
},

查询指令的坑:云函数内使用get()方法,只能使用promise形式,不能用get({success(res){console.log(res)}})回调方式

使用数据库 API 提供的 where 方法我们可以构造复杂的查询条件完成复杂的查询任务. 数据库 API 提供了大于、小于等多种查询指令,这些指令都暴露在 db.command 对象上。

let db = wx.cloud.database()
let _ = db.command
db.collection('message').where({
	age:_.gt(18)//查询age>18
}).get().then((res)=>{
	console.log(res.data)
})

查询指令

文档:云开发>开发指引>数据库>增删改查SDK>查询指令

查询指令 说明
eq 等于
neq 不等于
lt 小于
lte 小于或等于
gt 大于
gte 大于或等于
in 字段值在给定数组中
nin 字段值不在给定数组中

查询多个条件

&&

let db = wx.cloud.database()
let _ = db.command
db.collection('message').where({
	age:_.gt(18).and(_.lt(25))//查询 age>18 && age<25
}).get().then((res)=>{
	console.log(res.data)
})

||

let db = wx.cloud.database()
let _ = db.command
db.collection('message').where({
	age:_.eq(18).or(_.eq(25))//查询 age=18 || age=25
}).get().then((res)=>{
	console.log(res.data)
})

let db = wx.cloud.database()
let _ = db.command
db.collection('message').where({
	age:_.not(_.eq(18))//查询 age!==18
}).get().then((res)=>{
	console.log(res.data)
})
let db = wx.cloud.database()
let _ = db.command
db.collection('message').where({
	age:_.not(_.or([_.lt(50),_.eq(100)]))//非(小于50或等于100)-->大于50且不等于100
}).get().then((res)=>{
	console.log(res.data)
})
//简化写法nor
let db = wx.cloud.database()
let _ = db.command
db.collection('message').where({
	age:_.nor([_.lt(50),_.eq(100)])//非(小于50或等于100)-->大于50且不等于100
}).get().then((res)=>{
	console.log(res.data)
})

多个字段非

//筛选出age不小于20 且 tags 不包含'mini'
let db = wx.cloud.database()
let _ = db.command
db.collection('message').where(_.nor([{
    age:_.lt(20)
},{
    tags:'mini'
}])).get().then((res)=>{
	conso

# 更新

文档:云开发>开发指引>数据库>增删改查SDK>更新

改一定是在查之后,先查再改。

// updateMessage云函数入口文件
const cloud = require('wx-server-sdk')
cloud.init()
let db = cloud.database()
// 云函数入口函数
exports.main = async (event, context) => {
    return new Promise((resolve,reject)=>{
        db.collection('message').where(
            event.condition//这样写让前端给查找条件{}
        ).update({
            data:event.updateData
        }).then((res)=>{
            resolve(res)
        })
    })
}
//调用云函数
updateMessage(){
    wx.cloud.callFunction({
        name:'updateMessage',
        data:{
        	condition:{author:'十月'},//查询条件
        	updateData:{content:'第一次之旅,假的假的'}//需要修改的数据
        },
        success(res){
        	console.log('333',res.result)//更新返回的是stats:{updated:1}表示更新了几条数据
        }
    })
}

除了用指定值更新字段外,数据库 API 还提供了一系列的更新指令用于执行更复杂的更新操作,更新指令可以通过 db.command 取得:

更新指令 说明
set 设置字段为指定值
remove 删除字段
inc 原子自增字段值
mul 原子自乘字段值
push 如字段值为数组,往数组尾部增加指定值
pop 如字段值为数组,从数组尾部删除一个元素
shift 如字段值为数组,从数组头部删除一个元素
unshift 如字段值为数组,往数组头部增加指定值

# 删除数据

文档:云开发>开发指引>数据库>增删改查SDK>删除数据

# 聚合

文档:云开发>开发指引>数据库>聚合

关联多个集合,联合查询,根据authList集合的name去关联查询bookShop集合的author,数据命名personalFile

db.collection('authList').aggregate().lookup({
    from:'bookShop',
    localField:'name',
    foreignField:'author',
    as:'personalFile'
}).end().then((res)=>{
    resolve(res);
}).catch((err)=>{
    resolve(err);
})

# 1.18 云存储

wx.chooseImage

1.上传图片示例,wx.cloud.upliadFile()方法,cloudPath 云存储路径会解析/创建对应目录。

uploadFile(){
    wx.chooseImage({
        complete: (res) => {
            console.log(res);
            res.tempFilePaths.forEach((item,index)=>{
                let type = item.replace(/.+\./,'').toLowerCase();//得到文件后缀名
                wx.cloud.uploadFile({
                    cloudPath:'images/'+Date.now() + type,
                    filePath:item,
                    success(res){
                    	console.log('上传成功',res);//返回的数据拿到fileId
                    }
                })
            })
        },
    })
}

# 1.19 behaviors

文档:指南>自定义组件>behaviors

behaviors 是用于组件间代码共享的特性,类似于Vue的“mixins”。

let mainBehavior = Behavior({
    data:{
        //数据
    },
    methods:{
        //方法
    }
})
export default mainBehavior;

使用

import mainBehavior from '..path';
Component({
    behaviors:[mainBehavior],//可使用多个behavior
})

# 字段的覆盖和组合规则

组件和它引用的 behavior 中可以包含同名的字段,对这些字段的处理方法如下:

  • 如果有同名的属性或方法,组件本身的属性或方法会覆盖 behavior 中的属性或方法,如果引用了多个 behavior ,在定义段中靠后 behavior 中的属性或方法会覆盖靠前的属性或方法;
  • 如果有同名的数据字段,如果数据是对象类型,会进行对象合并,如果是非对象类型则会进行相互覆盖;
  • 生命周期函数不会相互覆盖,而是在对应触发时机被逐个调用。如果同一个 behavior 被一个组件多次引用,它定义的生命周期函数只会被执行一次。

# 1.20 Component构造器

文档:指南>自定义组件>Component构造器

Component 构造器可用于定义组件,调用 Component 构造器时可以指定组件的属性、数据、方法等。

# 1.21 组件间通信

文档:指南>自定义组件>组件间通信与事件

组件间的基本通信方式有以下几种。

  • WXML 数据绑定:用于父组件向子组件的指定属性设置数据,仅能设置 JSON 兼容数据(自基础库版本 2.0.9 开始,还可以在数据中包含函数)。具体在 组件模板和样式 章节中介绍。
  • 事件:用于子组件向父组件传递数据,可以传递任意数据。
  • 如果以上两种方式不足以满足需要,父组件还可以通过 this.selectComponent 方法获取子组件实例对象,这样就可以直接访问组件的任意数据和方法。

# 类似事件车通信

1.监听事件

<!-- 当自定义组件触发“myevent”事件时,调用“onMyEvent”方法 -->
<component-tag-name bindmyevent="onMyEvent" />
<!-- 或者可以写成 -->
<component-tag-name bind:myevent="onMyEvent" />
Page({
  onMyEvent: function(e){
    e.detail // 自定义组件触发事件时提供的detail对象
  }
})

2.触发事件

<!-- 在自定义组件中 -->
<button bindtap="onTap">点击这个按钮将触发“myevent”事件</button>
Component({
  properties: {},
  methods: {
    onTap: function(){
      var myEventDetail = {} // detail对象,提供给事件监听函数
      var myEventOption = {} // 触发事件的选项
      this.triggerEvent('myevent', myEventDetail, myEventOption)
    }
  }
})

触发事件的选项包括:

选项名 类型 是否必填 默认值 描述
bubbles Boolean false 事件是否冒泡
composed Boolean false 事件是否可以穿越组件边界,为false时,事件将只能在引用组件的节点树上触发,不进入其他任何组件内部
capturePhase Boolean false 事件是否拥有捕获阶段

# 1.22 小程序动态类名绑定

<view class="{{'type' + item.type}} mc-bg"></view>
/*双括号内可用拼接 , 多个类名在双括号外空格隔开, item是wx:for得到的项, 结果如下*/
<view class="typeA mc-bg"></view>
Last Updated: 2020-6-18 20:12:07