项目构成

  • pages存放小程序的页面
  • utils存放工具性质的模块
  • app.js小程序项目的入口文件
  • app.json小程序的项目的全局配置文件
  • app.wxss全局样式文件
  • project.config.json项目配置文件
  • sitemap.json用来配置小程序及其页面是否允许被微信索引

微信推荐页面都放到pages中

json配置文件

project.config.json

记录对小程序开发工具所做的个性化配置

{
"description": "项目配置文件,详见文档:https://developers.weixin.qq.com/miniprogram/dev/devtools/projectconfig.html",
"packOptions": {
"ignore": [],
"include": []
},
"setting": { //其他的一些配置
"bundle": false,
"userConfirmedBundleSwitch": false,
"urlCheck": true,
"scopeDataCheck": false,
"coverView": true,
"es6": true,
"postcss": true,
"compileHotReLoad": false,
"lazyloadPlaceholderEnable": false,
"preloadBackgroundData": false,
"minified": true,
"autoAudits": false,
"newFeature": false,
"uglifyFileName": false,
"uploadWithSourceMap": true,
"useIsolateContext": true,
"nodeModules": false,
"enhance": true,
"useMultiFrameRuntime": true,
"useApiHook": true,
"useApiHostProcess": true,
"showShadowRootInWxmlPanel": true,
"packNpmManually": false,
"enableEngineNative": false,
"packNpmRelationList": [],
"minifyWXSS": true,
"showES6CompileOption": false,
"minifyWXML": true,
"useStaticServer": true,
"checkInvalidKey": true,
"babelSetting": {
"ignore": [],
"disablePlugins": [],
"outputPath": ""
},
"disableUseStrict": false,
"useCompilerPlugins": false
},
"compileType": "miniprogram",
"libVersion": "2.19.4",
"appid": "wx4de46425c2db08cb", //运行别人的项目需要改成自己的ID
"projectname": "miniprogram-92", //与小程序名称名称不同
"condition": {},
"editorSetting": {
"tabIndent": "insertSpaces",
"tabSize": 4
}
}

sitemap.json

支持小程序内的搜索、类似于PC网页的SEO

{
"desc": "关于本文件的更多信息,请参考文档 https://developers.weixin.qq.com/miniprogram/dev/framework/sitemap.html",
"rules": [{
"action": "allow", //改为disallow表示不被微信索引
"page": "*"
}]
}

页面.json

页面样式配置全局样式

新建页面

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

将新建的页面放在第一位,就是当前编译器渲染的首页

WXML和HTML

WXSS和CSS

小程序.JS

app.js

// app.js
App({
onLaunch() {
// 展示本地存储能力
const logs = wx.getStorageSync('logs') || []
logs.unshift(Date.now())
wx.setStorageSync('logs', logs)

// 登录
wx.login({
success: res => {
// 发送 res.code 到后台换取 openId, sessionKey, unionId
}
})
},
globalData: {
userInfo: null
}
})

什么是宿主环境

  • 程序运行必须的依赖环境
  • 脱离了宿主环境的软件没有任何意义
  • 小程序的宿主环境是微信

微信宿主环境

  • 通信模型
  • 运行机制
  • 组件
  • API

通信的主体

  • 渲染层和逻辑层
  • WXML和WXSS工作在渲染层
  • JS脚本工作在逻辑层

通信模型

  • 渲染层和逻辑层之间的通信
  • 逻辑层和第三方服务器之间的通信
  • 均由微信客户端转发

运行机制

  • 启动过程

    1. 下载小程序的代码包到本地
    2. 解析app.json全局配置文件
    3. 执行app.js小程序入口文件,调用App()创建小程序实例
    4. 渲染小程序的首页
    5. 启动完成
  • 渲染过程

    1. 加载解析页面的.json配置文件
    2. 加载页面的.wxml模板和.wxss样式
    3. 执行页面的.js文件,调用Page()创建页面实例
    4. 页面渲染完成

组件

容器组件

名称 用途
view 普通视图区域、类似于HTML中的div,是块级元素,用来布局
scroll-view 可滚动的视图区域、用来实现滚动列表的效果
swiper和swiper-item 轮播图容器组件和轮播图item组件,item是内部的轮播小组件

view

<!--类似HTML的div-->
<view class = "container">
<view>A</view>
<view>B</view>
<view>C</view>
</view>
/* pages/list/list.wxss */
.container1 view{
width: 100px;
height: 100px;
text-align: center;
line-height: 100px;
}

.container1 view:nth-child(1){
background-color: green;
}
.container1 view:nth-child(2){
background-color: blue;
}
.container1 view:nth-child(3){
background-color: pink;
}

.container1 {
display: flex;
justify-content: space-around;
}


scroll-view

<!--滚动窗口-->
<scroll-view class = "container1" scroll-y>
<view>A</view>
<view>B</view>
<view>C</view>
</scroll-view>
/* pages/list/list.wxss */
.container1 view{
width: 100px;
height: 100px;
text-align: center;
line-height: 100px;
}

.container1 view:nth-child(1){
background-color: green;
}
.container1 view:nth-child(2){
background-color: blue;
}
.container1 view:nth-child(3){
background-color: pink;
}

.container1 {
border: 1px solid red;
width: 100px;
height: 120px;
}


swiper

<!--轮播图-->
<swiper class="swiper-container" indicator-dots indicator-color="white" autoplay interval="3000" circular>
<!--第一个轮播图-->
<swiper-item>
<view class="item">A</view>
</swiper-item>
<!--第二个轮播图-->
<swiper-item>
<view class="item">B</view>
</swiper-item>
<!--第三个轮播图-->
<swiper-item>
<view class="item">C</view>
</swiper-item>
</swiper>
/*轮播图样式*/
.swiper-container {
height:150px
}

.item {
height: 100%;
line-height: 150px;
text-align: center;
}
swiper-item:nth-child(1) .item{
background-color: lightblue;
}
swiper-item:nth-child(2) .item{
background-color: lightgreen;
}
swiper-item:nth-child(3) .item{
background-color: lightyellow;
}

内容组件

text

只有text组件支持长按选中按钮

<view>
手机号支持长按选中效果
<text selectable>13800005056</text>
</view>

rich-text

<rich-text nodes="<h1 style='color: red;'>标题</h1>"></rich-text>

功能组件

button

  • 默认按钮独占一行
<!--不同类型的按钮样式-->
<button>push</button>
<button type="primary">push-主色调</button>
<button type="warn">push-警告</button>
<!--添加mini属性-->
<button size="mini">push</button>
<button type="primary" size="mini">push-主色调</button>
<button type="warn" size="mini">push-警告</button>
<!--添加mini属性-->
<button size="mini" plain>push</button>
<button type="primary" size="mini" plain>push-主色调</button>
<button type="warn" size="mini" plain>push-警告</button>

image

<image>同样占据一定空间</image>
<image src="/image/1.png" mode="aspectFill"></image>
image {
border: 1px solid red;
}

默认情况下,图片会被缩放或剪裁

API分类

协同工作和发布

发布上线,通过后台设置

数据绑定

基本原则,在data中定义数据,在wxml中使用数据

Mustache语法或者叫插值表达式Mustache应用场景

  • 绑定内容
  • 绑定属性
  • 运算

动态绑定内容

// pages/list/list.js
Page({

/**
* 页面的初始数据
*/
data: {
info: 'hello world'
},
})
<view> {{info}}</view>

动态绑定属性

// pages/list/list.js
Page({

/**
* 页面的初始数据
*/
data: {
imgsrc: 'https://ts1.cn.mm.bing.net/th/id/R-C.2530400ae4fb46c851fb84505fad2319?rik=V%2bxQIfrRsCTlDw&riu=http%3a%2f%2fimg.crcz.com%2fallimg%2f202003%2f05%2f1583415058483289.jpg&ehk=UO4T%2b11wo2Pqv7DUHPfk5pd9gbne4a7uyQ9eUKbNmUY%3d&risl=&pid=ImgRaw&r=0&sres=1&sresct=1'
},
})
<image src="{{imgsrc}}" mode="widthFix"></image>

三元运算

Page({

/**
* 页面的初始数据
*/
data: {
randomNum: Math.random() * 10
randomNum1: Math.random().toFixed(2)
},
})
<view>{{randomNum >= 5 ? '数字大于或等于5':'数字小于5'}}</view>
<view>{{randomNum1*100}}</view>

事件绑定

事件是渲染层到逻辑层的通讯方式,通过事件可以将用户在渲染层产生的行为,反馈到逻辑层进行业务的处理。

常见事件

当事件回调触发的时候,会收到一个事件对象event,他的详细属性如下表所示

target和currentTarget的区别

target是出发该事件的源头组件,而currentTarget则是当前事件所绑定的组件。点击内部的按钮时,点击事件以冒泡的方式向外扩散,也会出发外层的tap事件处理函数,此时,对于外层的view来说

e.target指向的是触发事件的源头组件,也就是view当中的button

e.currentTarget指向的是当前正在触发事件的那个组件,也就是当前的view组件

bindtap的语法格式

page({
//定义按钮的事件处理函数
btnTapHandler(event){
console.log(event)
},
})

<button type="primary" bindtap="btnTapHandler">按钮</button>

数据赋值

page({
/**
* 页面的初始数据
*/
data: {
randomNum: Math.random() * 10,
randomNum1: Math.random().toFixed(2),
Num:0
},
//修改数据的值
CountChange(){
this.setData({
Num:this.data.Num + 1
})
},
})

<button type="primary" bindtap="CountChange"> +1</button> 

事件传参

在小程序中不能在绑定时间的同时为事件处理函数传递参数

<button type="primary" bindtap="btnTapHandler(123)">事件传参</button>

小程序会认为btnTapHandler(123)是名称

使用data-*自定义属性传参,*表示参数的名字,2这样传的是数字2,单纯写2是字符2

<button type="primary" bindtap="btnTapHandler" data-info="{{2}}">事件传参</button>

page({
/**
* 页面的初始数据
*/
data: {
randomNum: Math.random() * 10,
randomNum1: Math.random().toFixed(2),
Num:0
},
//定义+2按钮的事件处理函数
btnTap2(event){
this.setData({Num:this.data.Num + event.target.dataset.info })
},

})
<button type="primary" bindtap="btnTap2" data-info="{{2}}">+2</button>

bindinput的语法格式

通过input事件来响应文本框的输入事件

inputHandler(e){
console.log(e.detail.value)
},
<input bindinput="inputHandler"></input>

数据同步(文本框和data)

  1. 定义数据

    page({
    /**
    * 页面的初始数据
    */
    data: {
    Num:0
    },
    })
  2. 渲染结构

    <input value="{{Num}}" bindinput="inputHandler"></input>
  3. 美化样式

    input {
    border: 1px solid #221133;
    padding:5px;
    margin: 5px;
    border-radius: 3px;
    }
  4. 绑定input事件处理函数

    page({
    /**
    * 页面的初始数据
    */
    data: {
    Num:0
    },
    inputHandler(e){
    this.setData({
    Num:e.detail.value
    })
    },
    })

条件渲染

wx:if

<view wx:if="{{type == 1}}"></view>
<view wx:elif="{{type == 2}}"></view>
<view wx:else>保密</view>
data: {
type:2
},

结合block使用wx:if

如果要一次性控制多个组件的展示或隐藏,可以使用block标签

<block wx:if="{{true}}">
<view>1</view>
<view>2</view>
</block>

hidden

控制组件的显示或隐藏,可以和wx:if有相同的效果但是原理不同

<view hidden="{{!flag}}">这是hidden控制的</view>
data: {
flag:true
},

使用建议,当频繁切换的时候使用hidden

列表渲染

wx:for

data: {
arr1:['苹果','华为','小米']
},
<view wx:for="{{arr1}}">
索引是:{{index}},item项是:{{item}}
</view>

手动指定索引和当前项的变量名*

<view wx:for="{{arr1}}" wx:for-index="idx" wx:for-item="itemName">
索引是:{{idx}},item项是:{{itemName}}
</view>

wx:key

类似于Vue列表渲染中的:key,小程序也建议在列表渲染时为渲染出来的列表项指定唯一的key值,从而提高渲染效率,没有id可用index作为key值

data: {
arr1:['苹果','华为','小米'],
arr2:[
{id:1,name:'小红'},
{id:2,name:'小黄'},
{id:3,name:'小白'}
]
},
<view wx:for="{{arr2}}" wx:key="id">
{{item.name}}
</view>

WXSS

WXSS具有大部分CSS特性

rpx

根据不同的设备,将设备的屏幕宽度等分为750份

  • 在较小的设备上1rpx代表的宽度较小
  • 在较大的设备上1rpx代表的宽度较大

rpx与px的单位换算

样式导入

路径/common/common.wxss

.username {
color: blue;
}

在index.wxcss中

@import "/common/common.wxss";
input {
border: 1px solid #221133;
padding:5px;
margin: 5px;
border-radius: 3px;
}

在index.wxml中

<view wx:for="{{arr2}}" wx:key="id" class="username">
{{item.name}}
</view>

全局样式

在app.wxss中配置全局的样式

局部样式

在页面文件中.wxss中配置页面局部样式

  • 当局部样式和全局样式冲突时,根据就近原则,使用当前页面样式
  • 当局部的样式权重大于等于全局样式的权重,局部的才会覆盖

全局配置

window

期中导航栏和背景区域可以通过window节点配置

{
"pages":[
"pages/list/list",
"pages/index/index",
"pages/logs/logs"

],
"window":{
"backgroundTextStyle":"light",
"navigationBarBackgroundColor": "#fff",
"navigationBarTitleText": "qxd", //
"navigationBarTextStyle":"black"
},
"style": "v2",
"sitemapLocation": "sitemap.json"
}

tabBar

"tabBar": {
"list": [
{
"pagePath": "pages/index/index",
"text": "首页"
},
{
"pagePath": "pages/list/list",
"text": "内容"
}
]
},

在每个tab中可以包含如下的配置项

  • 图片放到image文件夹中,从根目录加入路径
  • 在全局app.json中添加代码
"tabBar": {
"list": [
{
"pagePath": "pages/index/index",
"text": "首页",
"iconPath": "/image/1.png",
"selectedIconPath": "/image/1_active.png"
},
{
"pagePath": "pages/list/list",
"text": "内容",
"iconPath": "/image/2.png",
"selectedIconPath": "/image/2_active.png"
},
{
"pagePath": "pages/logs/logs",
"text": "个人信息",
"iconPath": "/image/3.png",
"selectedIconPath": "/image/3_active.png"
}
]
},

页面配置

在页面的json文件中配置

"enablePullDownRefresh": true //下拉刷新不推荐在全局中使用

网路数据请求

get请求

调用wx.request()方法

<button bindtap="getInfo">发送请求</button>
//发起get数据请求
getInfo() {
wx.request({
url: 'https://www.escook.cn/api/get',
method:'GET',
data: {
name: 'zs',
age: 20
},
success:(res) =>{
console.log(res)
}
})
},

url: ‘https://www.escook.cn/api/get’,必须先配置到小程序的后台

Post请求

同样调用wx.request()方法

<button bindtap="postInfo">发送get请求</button>
//发起post数据请求
postInfo() {
wx.request({
url: 'https://www.escook.cn/api/get',
method:'POST',
data: {
name: 'ls',
age: 33
},
success:(res) =>{
console.log(res.data)
}
})
},

在页面刚加载时就请求数据

在页面刚刚加载的时候,自动请求一些初始化数据,希望进入首页就自动执行post和get请求,使用onload

/**
* 生命周期函数--监听页面加载
*/
onLoad(options) {
this.getInfo(),
this.postInfo()
},

跳过合法域名校验

跨域和Ajax

跨域问题只存在于基于浏览器的web开发中,由于小程序的宿主环境不是浏览器,而是微信客户端,所以小程序中不存在跨域的问题。

Ajax技术的和兴时依赖于浏览器中的XMLHttpRequest这个对象,由于小程序宿主环境是尾行客户端,所以小程序中不能叫做“发起Ajax请求”,而是叫做“发起网络数据请求”

案例-本地生活

链接:https://pan.baidu.com/s/1WJ_Bh6b8HBaF7tpCpg0APg?pwd=18if
提取码:18if

页面导航

导航到tabBar-声明式导航

<navigator url="/pages/index/index" open-type="switchTab">导航到消息页面</navigator>
<navigator url="/pages/index/index" open-type="navigate">导航到消息页面</navigator>

导航到tabBar页面-编程式导航

<button bindtap="gotoMessage">跳转到消息页面</button>
//通过编程式导航跳转到消息页面
gotoMessage() {
wx.switchTab({
url: '/pages/message/message',
})
},

导航到非tabBar页面-编程式

<button bindtap="gotoRead">跳转到非tabBar页面</button>
//通过编程式导航跳转到消息页面
gotoRead() {
wx.navigateTo({
url: '/pages/read/read',
})
},

后退导肮-编程式

<button bindtap="gotoRead">通过编程式导航后退</button>
//通过编程式导航后退
gotoBack() {
wx.navigateBack(){
delta: 1 //后退层级数
}
},

导航传参-声明式

<navigator url="/pages/info/info?name=wx&age=20" open-type="navigate">跳转到info并传参</navigator>

导航传参-编程式

<button bindtap="gotoInfo">跳转到info并传参</button>
//通过编程式导航到info页面并传递参数
gotoInfo() {
wx.navigateTo({
url: '/pages/info/info?name=wx&age=20',
})
},

onLoad获取参数

/**
* 生命周期函数--监听页面加载
*/
onLoad(options) {
console.log(options)
},

其他页面可以获取到值

	/**
* 页面的初始数据
*/
data: {
//导航传递的参数
query:{}
},
/**
* 生命周期函数--监听页面加载
*/
onLoad(options) {
console.log(options)
this.setDate({
query:options
})
},

页面事件

下拉刷新

  • 全局开启下拉刷新
  • 局部开启下拉刷新
{
"usingComponents": {},
"enablePullDownRefresh": true
}

配置下拉刷新窗口颜色

{
"usingComponents": {},
"enablePullDownRefresh": true,
"backgroundColor": "#efefef",
"backgroundTextStyle": "dark"
}

监听下拉刷新窗口函数

/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh() {
console.log('触发了message页面的下拉刷新')
},

下拉刷新关闭

/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh() {
this.setData({
Num: 0
})
wx.stopPullDownRefresh({
success: (res) => {},
})
},

上拉触底

  • 上拉触底距离是可以自定义的,在页面或全局的json文件中,配置onReachBottomDistance来改变,默认50
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom() {
//触底事件在触发是,应考虑用户多次触发的可能做节流处理
console.log("触发了触底事件")
},

案例-上拉触底

  1. 定义获取随机颜色的方法

    /**
    * 页面的初始数据
    */
    data: {
    colorList:[]
    },
    //得到随机颜色
    getColors(){
    wx.showLoading({title:'数据加载中...'})
    wx.request({
    url: 'https://www.escook.cn/api/color',
    method:'GET',
    success:({data:res}) =>{
    this.setData({
    colorList:[...this.data.colorList,...res.data]
    })
    }
    })
    },
  2. 页面加载时获取初始数据

    /* *
    *生命周期函数--监听页面加载
    */
    onLoad(options) {
    this.getColors()
    },

  3. 渲染UI,美化页面效果

    <view wx:for="{{colorList}}" wx:key="index" class="num-item" style="background-color: rgb({{item}}) ;">{{item}}</view>
    .num-item{
    border: 1rpx solid #efefef;
    border-radius: 8rpx;
    line-height: 200rpx;
    margin: 15rpx;
    text-align: center;
    text-shadow: 0rpx 0rpx 5rpx #fff;
    box-shadow: 1rpx 1rpx 6rpx #aaa;
    }
  4. 上拉触底获取颜色

    /**
    * 页面上拉触底事件的处理函数
    */
    onReachBottom() {
    this.getColors()
    },
  5. 添加loading提示效果

    //得到随机颜色
    getColors(){
    //查官方API文档
    wx.showLoading({title:'数据加载中...'})
    wx.request({
    url: 'https://www.escook.cn/api/color',
    method:'GET',
    success:({data:res}) =>{
    this.setData({
    colorList:[...this.data.colorList,...res.data]
    })
    }
    })
    },
  6. 对上拉触底进行节流处理

    /**
    * 页面的初始数据
    */
    data: {
    colorList:[],
    //节流值
    isloading: false
    },
    //得到随机颜色
    getColors(){
    //节流操作
    this.setData({
    isloading:true
    })
    wx.showLoading({
    title:'数据加载中...'
    }),
    wx.request({
    url: 'https://www.escook.cn/api/color',
    method:'GET',
    success:({data:res}) =>{
    this.setData({
    colorList:[...this.data.colorList,...res.data]
    })
    },
    complete:()=>{
    wx.hideLoading()
    this.setData({
    isloading:false
    })
    }

    })

    },
    /**
    * 页面上拉触底事件的处理函数
    */
    onReachBottom() {
    if(this.data.isloading){
    return
    }
    this.getColors()
    },

生命周期

  • 应用生命周期

  • 页面生命周期

  • 生命周期函数,自动按次序执行

    • 页面生命周期函数
    • 应用生命周期函数

应用生命周期函数

App({

/**
* 当小程序初始化完成时,会触发 onLaunch(全局只触发一次)
*/
onLaunch: function () {
//完成初始化的功能
},

/**
* 当小程序启动,或从后台进入前台显示,会触发 onShow
*/
onShow: function (options) {

},

/**
* 当小程序从前台进入后台,会触发 onHide
*/
onHide: function () {

},

/**
* 当小程序发生脚本错误,或者 api 调用失败时,会触发 onError 并带上错误信息
*/
onError: function (msg) {

}
})

页面生命周期函数

// pages/info/info.js
Page({
/**
* 页面的初始数据
*/
data: {},
/**
* 生命周期函数--监听页面加载
*/
onLoad(options) {},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady() {},
/**
* 生命周期函数--监听页面显示
*/
onShow() {},
/**
* 生命周期函数--监听页面隐藏
*/
onHide() {},
/**
* 生命周期函数--监听页面卸载
*/
onUnload() {},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh() {},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom() {},
/**
* 用户点击右上角分享
*/
onShareAppMessage() {}
})

WXS

在html中无法使用.js的函数,但是可以使用wxs,从而完成过滤器等的功能

  • 数据类型

    number、string、boolean、object、function、array、date、regexp

  • wxs不支持类似于ES6以上的语法

  • wxs遵循CommonJS

内嵌wxs脚本

<view>{{m1.toUpper(username)}}</view>
<wxs module="m1">
module.exports.toUpper = function(str){
return str.toUpperCase()
}
</wxs>

外联wxs脚本

案例-本地生活

自定义组件

  • 根目录下component文件夹,键入组件的名称之后回车

局部引用

  • 放在页面的.json文件中
"usingComponents": {
"my- test1":"/compoment/test1/test1"
},

全局引用

  • 放在全局app的.json文件中

组件和页面区别

  • 组件.json的声明不同
  • 组件的.js文件为Component()函数
  • 组件的事件处理函数需要定义到methods节点中

组件样式隔离

组件中的样式不会影响外界页面,外界页面样式也不会影响组件

  • app.wxss中的全局样式对组件无效
  • 只有class选自其会有样式隔离效果,id选择器、属性选择器、标签选择器不受样式隔离的影响
  • 在组件和引用组建的页面中建议使用class选择器,不使用id、属性、标签选择器

修改组件的样式隔离

stylelsolation可选值

data数据

// compoment/test1/test1.js
Component({
/**
* 组件的初始数据
*/
data: {

},
})

methods方法

// compoment/test1/test1.js
Component({
methods:{
addCount(){ //事件处理函数

}
_myfunction(){//自定义函数

}
}
})

properties属性

/**
* 组件的属性列表
*/
properties: {
//第一种方式简化
min:Number,
//第二种方式完整定义
max:{
type:Number,
value:10
}
},

data和properties的区别

  • data更倾向与存储组件的私有数据

  • properties更倾向于存储外界传递到组建的中的数据

  • 本质上相同

数据监听器

  • 作用类似于vue中的watch侦听器
  • 可以在一个监听器中监听多个字段
Component({
observers:{
'字段A,字段B'function(字段A的新值,字段B的新值){
//do something
}
}
})
<view style="text-align: center;">监听器的应用:{{num1}} + {{num2}} = {{sum}}</view>
<button bindtap="addNum">num +</button>
<button bindtap="decNum">num -</button>

监听对象属性的变化

  • 数据监听器支持监听对象中单个或多个属性的变化
Component({
observers:{
'对象.属性A,对象.属性B'function(属性A的新值,属性B的新值){
//do something,监听分三种情况,分别可以对属性和对象进行赋值触发
}
}
})

案例-颜色变化块

<text style="text-align: center;">组件2:对象监听器的应用,改变颜色</text>
<view style="height: 200rpx;width: 828rpx;background-color: rgb({{fullcolor}});text-align: center;line-height: 200rpx;font-size: 30rpx;text-shadow: 0rpx 0rpx 2rpx black;color: white;">
颜色值:{{fullcolor}}
</view>

<view style="display:flex;">
<button bindtap="addRed" style="background-color:rgb(214, 141, 119)">R</button>
<button bindtap="addGreen" style="background-color: lightgreen;">G</button>
<button bindtap="addBlue" style="background-color: lightblue;">B</button>
</view>



 data: {
color:{
r:0,
g:0,
b:0
},
fullcolor:'0, 0, 0'
},

/**
* 组件的方法列表
*/
methods: {
addRed(){
if(this.data.color.r + 1 > 255){
this.setData({
'color.r': 0
})
return 0
}
this.setData({
'color.r':this.data.color.r + 2
})
},
addGreen(){
if(this.data.color.g + 1 > 255){
this.setData({
'color.g': 0
})
return 0
}
this.setData({
'color.g':this.data.color.g+ 2
})
},
addBlue(){
if(this.data.color.b + 1 > 255){
this.setData({
'color.b': 0
})
return 0
}
this.setData({
'color.b':this.data.color.b + 2
})
}
},
observers:{
'color.r,color.g,color.b':function(r,g,b){
this.setData({
fullcolor:`${r}, ${g}, ${b}`
})
}
}

})

简化监听项

observers:{
'color.**':function(obj){
this.setData({
fullcolor:`${obj.r}, ${obj.g}, ${obj.b}`
})
}
}

纯数据字段

概念:指不用于界面渲染的data字段,既不会展示在界面上,也不会出纳递给其他组件,仅在组件内部使用

好处:提升页面更新的性能

// compoment/test1/test1.js
Component({
options:{
//指定所有_开头的数据字段为纯数据字段
pureDtaPattern:/^_/ //正则表达式
},
data: {
a:true, //普通数据字段
_b:true // 纯数据字段
}
})

组件的生命周期函数

生命周期函数 参数 描述说明
created 在组件实例刚刚被创建时执行
attached 在组件实例静页面节点树时执行
ready 在钻进在试图层布局完成后执行
moved 在组件实例被移动到节点树另一个位置时执行
detached 在组件实列 被从页面节点数移除时执行
error Object Error 每当组件方法抛出错误时执行

组件所在页面的生命周期

自定义的组件行为依赖于页面状态变化,此时就需要用到组件所在页面的生命周期

生命周期函数 参数 描述
show 组件所在页面被展示时执行
hide 组件所在页面被隐藏时执行
resize Object Size 组件所在页面尺寸变化时执行

插槽

在组件中用于承载组件使用者提供的wxml结构,即替换为wxml标签

<!-- 组件封装者-->
<slot></slot>
<!-- 组件使用者-->
<component-tag-name>
<view> 这是插入到组件的内容</view>
</component-tag-name>

多个插槽的使用

//启用多个节点
options:{
multipleSlots:true
}
<!-- 定义的时候用name指定名称-->
<my-test3>
<view slot="before">这里是插入到组件slot name="before"中的内容</view>
<view slot="after">这里时插入到组件slot name=”after"中的内容</view>
</my-test3>

父子组件之间的通信

  • 属性绑定

    • 用于父组件向子组件的指定属性设置数据
  • 事件绑定

    • 用于子组件向父组件传递数据,可以传递任意数据
  • 获取组件实例

    • 父组件还可以通过this.selectComponent()获取子组件实例对象

    • 这样就可以直接访问子组件的任意数据和方法

属性绑定

<!-- 父组件 -->
<view>父组件中的count = {{count}}</view>
<button bindtap="addCount" size="mini" type="primary" style="margin-left: 140px;">count + 1</button>
<my-test4 count="{{count}}"></my-test4>
//父组件js

/**
* 组件的初始数据
*/
data: {
count: 0
},

<!-- 子组件 -->
<text>子组件4:</text>
<view style="text-align: center;">子组件中的count = {{count}}</view>
/**
* 组件的属性列表
*/
properties: {
count:Number
},

事件绑定

  1. 在父组件的js中,定义一个函数,这个函数即将通过自定义事件的形式,传递给子组件。

    syncCount(e){
    // console.log('syncCount')
    this.setData({
    count:e.detail.value
    })
    }
  2. 在父组件的wxml,通过自定义事件的形式,将步骤1定义的函数引用,传递给子组件

    <my-test4 count="{{count}}" bind:sync="syncCount"></my-test4>
  3. 在组件的js中,通过调用this.triggerEvent(‘自定义事件名称’,{/参数对象/}),将数据发送到父组件

    addCount(){
    this.setData({
    count : this.properties.count + 1
    }),
    this.triggerEvent('sync',{value: this.properties.count})
    }
  4. 在父组件的js中,通过e.detail获取到子组件

获取组件实例

可在父组件里调用this.selectComponent(“id或class选择器”),获取子组件的实例对象,从而直接访问子组件的任意数据的方法。调用时需要传入一个选择器,例如this.selectComponent(".my-component")。

<!-- 为了获取子组件,需要给子组件配置class或者id(id是#ca) -->
<my-test5 id="ca" class="containA"></my-test5>
<button bindtap="getChild" type="primary" >获取子组件的实例对象</button>

getChild(){
const child = this.selectComponent('.containA')
child.setData({
count : this.data.count
})
}

behaviors

类似与vue中的mixins

工作方式,每个beavior可以包含一组属性、数据、生命周期函数和方法。组件引用它时,它的属性、数据和方法会被合并到组件中。每个组件可以引用多个behavior,behavior也可以应用其它behavior。

//组件.js
const myBehavior = require('../../behaviors/my-behavior')
Component({
behaviors:[myBehavior]
)}
//behavior.js
module.exports = Behavior({
data:{
username:'zs'
},
properties:{

},
methods:{

}
})
<view>在behavior中的用户名为:{{username}}</view>

behavior的可用节点

behavior重名规则

  • 同名数据字段重名规则
  • 同名的属性或方法
  • 同名的生命周期函数

npm包

  • 不依赖于Node.js内置库的包
  • 不支持依赖于浏览器内置对象的包
  • 不支持依赖于C++的包

Vant Weapp

  • 有赞前端团队开源

安装

  1. 初始化包管理文件

    npm init -y
  2. 安装npm包

    npm i @vant/weapp@1.3.3 -S --production
  3. 构建npm包

    微信开发者工具 --> 工具 --> 构建npm

    本地设置,使用npm包,新版本不用勾选

  4. 删除style:“v2”

  5. 在页面或全局的json组件usingComponents中添加组件

    "usingComponents": {
    "van-button": "@vant/weapp/button/index"
    }
  6. 根据vant的文档来当作组件一样使用

定制全局主题样式

在app.wxss中,写入CSS变量,即对全局生效

page{
--button-danger-background-color:#C00000;
--button-danger-border-color:#D60000;
}

API Promise化

基于回调函数的异步API的缺点:在默认情况下,小程序官方提供的异步API都是基于回调函数实现的,容易造成回调地狱

API Promsie化通过额外的配置,将官方提供、基于回调函数的异步API,升级改在为基于Promise的异步API,从而提高代码的可对那个、维护性,避免回调地狱的问题。

实现API的Promise化,主要依赖于miniprogram-api-promise这个第三方包。

#在当前项目文件夹终端中安装npm包,记得先要初始化
npm i --save miniprogram-api-promise@1.0.4
#安装完成删除miniprogram_npm后进行npm构建
//在小程序的入口文件中(app.js),只需调用一次promisifyAll()方法
//即可实现异步API的Promise化
import {promisifyAll} from 'miniprogram-api-promise'

const wxp = wx.p = {}
//promisify all wx's api
promisifyAll(wx,wxp)

全局数据共享

状态管理,解决组件之间数据共享的问题,开发中常用的全局数据共享方案有:Vuex、Redux、MobX等。

在小程序中,可以使用mobx-miniprogram配合mobx-miniprogram-bindings实现全局数据共享。其中:

  • mobx-miniprogram用来创建Store实例对象
  • mobx-miniprogram-bindings用来把Store中的共享数据或方法,绑定到组件或页面中使用。