环境准备

注册账号

访问注册页面注册⻚⾯,完成注册(建议使用新邮箱)。

获取APPID

登录微信小程序,找到开发开发设置获取APPID。

开发工具

下载地址

第一个微信小程序

打开开发者工具

登录需要扫码登录

新建项目

填写项目信息,复制获取的AppID,后端服务暂时选择不使用云服务。

开发工具

开发工具介绍

结构目录

⼩程序框架的⽬标是通过尽可能简单、⾼效的⽅式让开发者可以在微信中开发具有原⽣APP体验的服务。

文件结构与传统web对比

  • 传统web:
    • 结构 HTML
    • 样式 CSS
    • 逻辑 Javascript
    • 配置 ⽆
  • 微信⼩程序
    • 结构 HTML
    • 样式 WXSS
    • 逻辑 Javascript
    • 配置 JSON

      基本目录结构

  • pages :页面文件夹
    • index :首页文件夹
      • index.js :逻辑文件
      • index.json :配置文件
      • index.wxml :配置文件
      • index.wxss :样式文件
  • logs :日志页面
    • logs.js
    • logs.json
    • logs.wxml
    • logs.wxss
  • utils :第三方工具js文件夹
    • util.js
  • app.js :项目的全局入口文件
  • app.json :全局配置文件
  • app.wxss :全局样式文件
  • project.config.json :项目配置文件 AppID
  • sitemap.json :微信索引配置文件

    配置文件

    配置文件不能出现注释

    全局配置文件 app.json

    小程序根目录下的 app.json 文件用来对微信小程序进行全局配置,决定页面文件的路径、窗口表现、设置网络超时时间、设置多 tab 等。
    完整配置项说明请参考小程序全局配置
    以下是一个包含了部分常用配置选项的 app.json :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    {
    "pages": [
    "pages/index/index",
    "pages/logs/index"
    ],
    "window": {
    "navigationBarTitleText": "Demo",
    "backgroundTextStyle":"light",
       "navigationBarBackgroundColor": "#fff",
       "navigationBarTitleText": "WeChat",
       "navigationBarTextStyle":"black"
    },
    "tabBar": {
    "list": [{
    "pagePath": "pages/index/index",
    "text": "首页"
    }, {
    "pagePath": "pages/logs/index",
    "text": "日志"
    }]
    },
    "networkTimeout": {
    "request": 10000,
    "downloadFile": 10000
    },
    "debug": true,
    "navigateToMiniProgramAppIdList": [
    "wxe5f52902cf4de896"
    ]
    }

    页面配置 page.json

    这⾥的page.json其实⽤来表⽰⻚⾯⽬录下的page.json这类和⼩程序⻚⾯相关的配置。开发者可以独⽴定义每个⻚⾯的⼀些属性,如顶部颜⾊、是否允许下拉刷新等等。每一个小程序页面也可以使用同名 .json 文件来对本页面的窗口表现进行配置,页面中配置项会覆盖app.jsonwindow 中相同的配置项。
    完整配置项说明请参考小程序页面配置

    sitemap 配置

    通过 sitemap.json 配置,或者管理后台页面收录开关来配置其小程序页面是否允许微信索引。当开发者允许微信索引时,微信会通过爬虫的形式,为小程序的页面内容建立索引。当用户的搜索词条触发该索引时,小程序的页面将可能展示在搜索结果中。 爬虫访问小程序内页面时,会携带特定的 user-agent:mpcrawler 及场景值:1129。需要注意的是,若小程序爬虫发现的页面数据和真实用户的呈现不一致,那么该页面将不会进入索引中。sitemap

    模板语法

    WXML(WeiXin Markup Language)是框架设计的⼀套标签语⾔,结合基础组件、事件系统,可以构建出⻚⾯的结构。

    数据绑定

    普通写法

    1
    <view>{{name}}</view>
    1
    2
    3
    4
    5
    Page({
    data:{
    name:'丽丝'
    }
    })

    组件属性

    1
    <view id="item-{{id}}"></view>
    1
    2
    3
    4
    5
    Page({
    data:{
    id:0
    }
    })

    bool类型

    不要直接写checked="false",其计算结果是⼀个字符串
    1
    <checkbox checked="{{false}}"></checkbox>

    运算

    三元运算

    1
    2
    3
    4
    <view hidden="{{ flag ? true : false }}"></view>
    <view>
    {{10%2===0 ? '偶数' : '奇数'}}
    </view>

    算术运算

    1
    2
    3
    <view>
    {{a+b}}+{{c}}+d
    </view>
    1
    2
    3
    4
    5
    6
    7
    Page({
    data:{
    a:1,
    b:3,
    c:5
    }
    })

    逻辑判断

    1
    <view wx:if="{{length > 5}}"></view>

    字符串运算

    1
    <view>{{"hello" + name}}</view>

    列表渲染(遍历)

    wx:for

    项的变量名默认为 item wx:for-item 可以指定数组当前元素的变量名
    下标变量名默认为 index wx:for-index 可以指定数组当前下标的变量名
    wx:key ⽤来提⾼数组渲染的性能
    wx:key绑定的值有如下选择:
  • string 类型,表⽰循环项中的唯⼀属性
  • 保留字*this,它的意思是item本⾝,*this代表的必须是唯⼀的字符串和数组。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    <view>
    <view wx:for="{{ list }}" wx:for-item="item" wx:for-index="index" wx:key="id">
    索引:{{ index }}
    --
    值:{{ item.name }}
    </view>
    </view>
    <view>
    <view>对象循环</view>
    <view wx:for="{{person}}" wx:for-item="value" wx:for-index="key" wx:key="age">
    属性:{{key}}
    --
    值:{{value}}
    </view>
    </view>

    block

    渲染⼀个包含多节点的结构块?block最终不会变成真正的dom元素
    1
    2
    3
    4
    5
    6
    7
    8
    <view>
    <view>对象循环</view>
    <block wx:for="{{person}}" wx:for-item="value" wx:for-index="key" wx:key="age" class="my_list">
    属性:{{key}}
    --
    值:{{value}}
    </block>
    </view>

    条件渲染

    wx:if

    使用wx:if="{{condtion}}"判断是否需要渲染代码块。
    1
    2
    3
    4
    5
    6
    7
       <view>条件渲染</view>
    <view wx:if="{{true}}">显示</view>
    <view wx:if="{{false}}">隐藏</view>

    <view wx:if="{{true}}">1</view>
    <view wx:elif="{{false}}">2</view>
    <view wx:else>3</view>

    hidden

    1
    <view hidden="{{condition}}"> True </view>
    频繁切换使用 hidden,不频繁则 wx:if

    事件的绑定

    • wxml页面
      1
      2
      3
      4
      5
      6
      <view>输入:
      <input type="text" bindinput="handleInput"/>
      </view>
      <view>
      {{num}}
      </view>
    • js page
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      Page({
      /**
      * 页面的初始数据
      */
      data: {
      num:0
      },
      // 输入框测试
      handleInput(e){
      this.setData({
      num:e.detail.value
      });
      console.log(e.detail.value);
      },
      })
      事件传值通过标签⾃定义属性的⽅式和 value
      1
      2
      3
      4
      5
      <button bindtap="handletap" data-operation="{{1}}">+</button>
      <button bindtap="handletap" data-operation="{{-1}}">-</button>
      <view>
      {{num}}
      </view>
      1
      2
      3
      4
      5
      6
      7
      // 加减
      handletap(e){
      const nums = e.currentTarget.dataset.operation;
      this.setData({
      num:this.data.num += nums
      })
      },

      样式 WXSS

      WXSS(WeiXin Style Sheets)是⼀套样式语⾔,⽤于描述 WXML的组件样式。
      与CSS相⽐,WXSS扩展的特性有:
  • 响应式⻓度单位 rpx
  • 样式导⼊

    尺寸单位

尺寸单位

  • rpx(responsive pixel): 可以根据屏幕宽度进行自适应。规定屏幕宽为750rpx。如在 iPhone6 上,屏幕宽度为375px,共有750个物理像素,则750rpx = 375px = 750物理像素,1rpx = 0.5px = 1物理像素。
设备 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

建议: 开发微信小程序时设计师可以用 iPhone6 作为视觉稿的标准。

注意: 在较小的屏幕上不可避免的会有一些毛刺,请在开发时尽量避免这种情况。

样式导⼊

wxss中直接就⽀持,样式导⼊功能。也可以和less中的导⼊混⽤。使⽤ @import 语句可以导⼊外联样式表,只⽀持相对路径。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/** common.wxss **/
view{
background-color: rgb(235, 235, 235);
}
.userinfo {
display: flex;
flex-direction: column;
align-items: center;
}
.userinfo-avatar {
width: 128rpx;
height: 128rpx;
margin: 20rpx;
border-radius: 50%;
}
1
2
/**index.wxss**/
@import "../../styles/common.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 组件前边插入内容

常见组件

微信开发文档

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52

<!-- text -->
<text user-select decode>text &nbsp; 123</text>
<!-- images -->
<view class="img">
<image mode="widthFix" lazy-load src="https://konachan.net/sample/417260b75396b82c6206e044a50e4cc9/Konachan.com%20-%20318761%20sample.jpg"></image>
</view>
<!-- swiper 轮播图 -->
<swiper autoplay="true" interval="1500" circular="true" indicator-dots="true" indicator-color="#0094ff" indicator-active-color="#ff0094">
<swiper-item>
<image mode="widthFix" lazy-load src="https://konachan.net/sample/417260b75396b82c6206e044a50e4cc9/Konachan.com%20-%20318761%20sample.jpg"></image>
</swiper-item>
<swiper-item>
<image mode="widthFix" lazy-load src="https://konachan.net/sample/417260b75396b82c6206e044a50e4cc9/Konachan.com%20-%20318761%20sample.jpg"></image>
</swiper-item>
<swiper-item>
<image mode="widthFix" lazy-load src="https://konachan.net/sample/417260b75396b82c6206e044a50e4cc9/Konachan.com%20-%20318761%20sample.jpg"></image>
</swiper-item>
</swiper>
<!-- navigator -->
<navigator hover-class="navigator-hover" url="/pages/logs/logs">log</navigator>
<!-- rich-text 标签字符串 -->
<rich-text nodes="{{html}}"></rich-text>
<!-- button -->
<button>默认按钮</button>
<button size="mini">迷你按钮</button>
<button type="primary">primary 按钮</button>
<button type="warn">warn按钮</button>
<button type="warn" plain>plain按钮</button>
<button open-type="contact">contact</button>
<button open-type="share">share</button>
<button open-type="getPhoneNumber" bindgetphonenumber="getPhoneNumber">getPhoneNumber</button>
<button open-type="getUserInfo" bindgetuserinfo="getUserInfo">getUserInfo</button>
<button open-type="launchApp">launchApp</button>
<button open-type="openSetting">openSetting</button>
<button open-type="feedback">feedback</button>
<!-- 字体图标 -->
<view class="" hover-class="none" hover-stop-propagation="false">
<icon type="success" size="23" color="red"></icon>
</view>
<!-- radio 单选框 -->
<radio-group bindchange="handleChange">
<radio class="" color="red" value="male"></radio>
<radio class="" color="red" value="female"></radio>
</radio-group>
<view class="" hover-class="none" hover-stop-propagation="false">您选中的是:{{gender}}</view>
<!-- checkbox 多选框 -->
<checkbox-group bindchange="handleItemChange">
<checkbox class="" value="{{item.value}}" wx:for="{{list}}" wx:key="id">{{item.name}}</checkbox>
</checkbox-group>
<view>选中的水果:{{checkdeList}}</view>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
// pages/search/search.js
Page({

/**
* 页面的初始数据
*/
data: {
html: '<div><p>demo</p></div>',
gender: '',
list: [{
id: 0,
name: '🍎',
value: 'apple'
}, {
id: 1,
name: '🍌',
value: 'banana'
}, {
id: 2,
name: '🍊',
value: 'orange'
}],
checkdeList: []
},
// 单选框事件
handleChange(e) {
let gender = e.detail.value;
this.setData({
gender: gender == "male" ? "男" : "女"
});
},
// 多选框事件
handleItemChange(e) {
const checkdeList = e.detail.value;
this.setData({
checkdeList
})
},
getPhoneNumber(e) {
console.log(e);
},
getUserInfo(e) {
console.log(e);
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function(options) {

},

/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady: function() {

},

/**
* 生命周期函数--监听页面显示
*/
onShow: function() {

},

/**
* 生命周期函数--监听页面隐藏
*/
onHide: function() {

},

/**
* 生命周期函数--监听页面卸载
*/
onUnload: function() {

},

/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh: function() {

},

/**
* 页面上拉触底事件的处理函数
*/
onReachBottom: function() {

},

/**
* 用户点击右上角分享
*/
onShareAppMessage: function() {

}
})

自定义组件

创建自定义组件

⼩程序允许我们使⽤⾃定义组件的⽅式来构建⻚⾯。在微信开发者⼯具中快速创建组件的⽂件结构,项目根目录下新建components/Tabs文件夹,然后右键Tabs文件夹,新建Component,生成 json wxml wxss js 4个文件。

声明组件

需要在组件的json⽂件中进⾏⾃定义组件声明

1
2
3
4
{
"component": true,
"usingComponents": {}
}

编辑组件

在组件的wxml⽂件中编写组件模板,在wxss⽂件中加⼊组件样式slot 表⽰插槽,类似vue中的slot,注意:在组件wxss中不应使用ID选择器、属性选择器和标签名选择器。

1
2
3
4
5
6
7
8
9
10
<view class="tabs">
<view class="tabs_title">
<view wx:for="{{tabs}}" wx:key="id" class="title_item {{item.isActive?'active':''}}" bindtap="hanldeItemTap" data-index="{{index}}">
{{item.name}}
</view>
</view>
<view class="tabs_content">
<slot></slot>
</view>
</view>

注册组件

在组件的 js ⽂件中,需要使⽤Component()来注册组件,并提供组件的属性定义、内部数据和⾃定义⽅法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// components/Tabs/Tabs.js
Component({
/**
* 组件的属性列表
*/
properties: {
tabs: {
type: Array,
value: []
}
},
/**
* 组件的初始数据
*/
data: {},

/**
* 组件的方法列表
*/
methods: {
hanldeItemTap(e) {
const { index } = e.currentTarget.dataset;
this.triggerEvent("itemChange", { index });
}
}
})

声明引入自定义组件

在⻚⾯的json⽂件中进⾏引⽤声明。还要提供对应的组件名和组件路径。

1
2
3
4
5
{
"usingComponents": {
"Tabs": "../../components/Tabs/Tabs"
}
}

页面中使用自定义组件

1
2
3
4
5
6
<Tabs tabs="{{tabs}}" binditemChange="handleItemChange">
<block wx:if="{{tabs[0].isActive}}">0</block>
<block wx:elif="{{tabs[1].isActive}}">1</block>
<block wx:elif="{{tabs[2].isActive}}">2</block>
<block wx:else>3</block>
</Tabs>

父子组件之间的传值

父组件向子组件传值

  • 首先在父组件的 json 文件中定义子组件
1
2
3
4
5
{
"usingComponents": {
"StepDevice": "/components/StepDevice/StepDevice"
}
}
  • 之后在父组件wxml中使用定义的组件
1
<StepDevice stepNum="{{item.shopNum}}"/>
  • 子组件规定的写法

    获取定义的数据使用: this.properties.stepNum
    改变数据的写法:this.setData({stepNum: 2 })

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Component({
properties:{
stepNum: {
type: Number,
value: 1
}
},
// 子组件的生命周期函数
lifetimes: {
// 在组件实例进入页面节点树时执行
attached: function () {
console.log(this.properties.stepNum)
},
},
})

子组件向父组件传值

  • 子组件的写法

如果向父组件传值使用到的固定写法this.triggerEvent('父组件定义的事件名称',{传递的数据})
也是在事件触发的时候向父组件传递数据

1
2
3
4
5
<!-- 子组件的写法 -->
<text class="add-btn" bindtap="addBtn">+</text>
<!-- 父组件 -->
<StepDevice bind:changeStepNum="stepChange"/>
<!-- stepChange 为父组件用来获取子组件的数据的方法 -->
  • 子组件方法

this.triggerEvent('父组件定义的事件名称',{传递的数据}) 父组件定义的事件名称就是bind绑定的事件名称这里的就是changeStepNum

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Component({
properties: {
stepNum: {
type: Number,
value: 1
}
},
methods:{
// 给父组件传值
stepChange() {
this.triggerEvent("changeStepNum", {
stepNum: this.properties.stepNum
})
},
// 每次点击的时候就把 数据传递给父组件
addBtn() {
this.stepChange()
}
}
})
  • 父组件的写法

stepChange 为父组件用来获取子组件的数据的方法

1
2
3
<!-- 父组件 -->
<StepDevice bind:changeStepNum="stepChange"/>
<!-- stepChange 为父组件用来获取子组件的数据的方法 -->
  • 获取数据

数据保存在 e.detail

1
2
3
4
stepChange(e) {
const getStepNum = e.detail.stepNum
console.log(getStepNum)
},

参考

生命周期

分为应⽤⽣命周期和⻚⾯⽣命周期

应用生命周期

注册小程序。接受一个 Object 参数,其指定小程序的生命周期回调等。

App() 必须在 app.js 中调用,必须调用且只能调用一次。不然会出现无法预期的后果。

Object object
属性 类型 默认值 必填 说明 最低版本
onLaunch function 生命周期回调——监听小程序初始化。
onShow function 生命周期回调——监听小程序启动或切前台。
onHide function 生命周期回调——监听小程序切后台。
onError function 错误监听函数。
onPageNotFound function 页面不存在监听函数。 1.9.90
onUnhandledRejection function 未处理的 Promise 拒绝事件监听函数。 2.10.0
onThemeChange function 监听系统主题变化 2.11.0
其他 any 开发者可以添加任意的函数或数据变量到 Object 参数中,用 this 可以访问

页面生命周期

注册小程序中的一个页面。接受一个 Object 类型参数,其指定页面的初始数据、生命周期回调、事件处理函数等。

属性 类型 默认值 必填 说明
data Object 页面的初始数据
options Object 页面的组件选项,同 Component 构造器 中的 options ,需要基础库版本 2.10.1
onLoad function 生命周期回调—监听页面加载
onShow function 生命周期回调—监听页面显示
onReady function 生命周期回调—监听页面初次渲染完成
onHide function 生命周期回调—监听页面隐藏
onUnload function 生命周期回调—监听页面卸载
onPullDownRefresh function 监听用户下拉动作
onReachBottom function 页面上拉触底事件的处理函数
onShareAppMessage function 用户点击右上角转发
onShareTimeline function 用户点击右上角转发到朋友圈
onAddToFavorites function 用户点击右上角收藏
onPageScroll function 页面滚动触发事件的处理函数
onResize function 页面尺寸改变时触发,详见 响应显示区域变化
onTabItemTap function 当前是 tab 页时,点击 tab 时触发
其他 any 开发者可以添加任意的函数或数据到 Object 参数中,在页面的函数中用 this 可以访问