目录
- 1、小程序简介
- 1.1、什么是小程序
- 1.2、小程序可以干什么
- 1.3、小程序和普通网页有什么不同
- 2、小程序开发前序
- 2.1、小程序开发者工具
- 2.2、注册小程序账号(个人)
- 2.3、移动端适配相关了解
- 2.4、小程序适配方案
- 3、微信小程序特点
- 4、小程序结构组成
- 5、文件夹基本结构规范
- 6、WXML语法
- 7、生命周期
- 7.1、为什么要有生命周期函数这个东西存在?
- 7.2、app生命周期
- 7.3、page页面的生命周期
一、小程序简介
1.1、 什么是小程序
- 2017年十大热词之一
- 微信小程序,简称小程序,是一种体积很小,下载速度很快的应用,所以有些地方会说,小程序无需下载,用完即走,其实这是用户感知不到它的下载过程
- 小程序刚发布的时候,要求压缩包的体积不能大于1M,在2017年4月做了改进,改为了2M
- 2017年1月9日,第一批小程序正式上线了
1.2、小程序可以干什么
- 用app进行互补,提供类似app的功能,比app操作更加简洁的轻应用
- 通过扫一扫或者在微信搜索即可下载
- 用户使用频率不高,但又不得不用的功能软件,目前看来小程序是首选
- 连接线上线下,引流
- 开发门槛低,成本低
1.3、 小程序和普通网页有什么不同
- 运行环境不同:普通页面运行在浏览器环境,微信小程序运行在微信环境
- 开发模式不同:网页的开发模式是浏览器+代码编辑器;但小程序有自及的一套标准开发模式:a、申请账号;b、安装小程序开发者工具;c、创建和配置小程序项目
- api不同:由于运行环境的不同,所以小程序中无法调用DOM和BOM中的API,但小程序可以调用微信环境提供的各种自带API,例如:地理定位、扫码、支付等;
二、小程序开发前序
2.1、小程序开发者工具
首先需要先下载一个微信小程序开发工具小程序开发者工具下载地址,选择自己对应的版本
2.2、注册小程序账号(个人)
具体的注册流程这里就不细说了,大家可以参照官方文档一步步去走
2.3、移动端适配相关了解
2.3.1、物理像素:屏幕的分辨率,它是设备能控制显示的最小单元,可以看成是对应的像素点
2.3.2、设备独立像素以及css像素:设备独立像素(也叫密度无关像素),可以认为是计算机坐标系统中的一个点,这个点代表一个可以由程序使用并控制的虚拟像素(比如:css像素只是在android机中css像素就不叫css像素了,而是叫设备独立像素),然后由相关系统转换为物理像素
2.3.3、dpr比 & DPI & PPI
1、dpr:设备像素比,物理像素/设备独立像素=dpr,一般以ipone6的dpr为准dpr=2
2、PPI:一英寸显示屏上像素点的个数
3、DPI:最早指的是打印机在单位面积上打印的墨点个数,墨点越多越清晰
2.4、小程序适配方案
小程序底层已经做了viewport适配的处理,也就是相当于让布局视口等于视觉视口,小程序中一般都用rpx,在ipone6下,1rpx =1个物理像素=0.5px
三、微信小程序特点
- 小程序没有Dom对象,一切基于组件化(组件:具有特定功能效果的集合)
- 小程序的四个重要的文件
a、.js
b、.wxml=>view结构=>html
c、.wxss=>view样式=>css
d、.json=>view数据=>json文件
四、小程序结构组成
当你新建一个小程序时,默认打开的会有这么几个文件,我们一一做下介绍:
4.1、App
包含app.js 、 app.json 、 app.wxss
- app.js:整个小程序只有一个 App 实例,是全部页面共享的。开发者可以通过 getApp 方法获取到全局唯一的 App 实例,获取App上的数据或调用开发者注册在 App 上的函数。
// app.js
App({
onLaunch (options) {
// Do something initial when launch.
},
onShow (options) {
// Do something when show.
},
onHide () {
// Do something when hide.
},
onError (msg) {
console.log(msg)
},
globalData: 'I am global data'
})
// xxx.js
const appInstance = getApp()
console.log(appInstance.globalData) // I am global data
- app.json: 小程序的全局配置文件,包括了小程序的所有页面路径、界面表现、网络超时时间、底部 tab 等
{
"pages": [ //所有页面的路径
"pages/index/index",
"pages/logs/index"
],
"window": {
"navigationBarTitleText": "Demo" //导航栏标题文字内容
navigationBarTextStyle:‘black’ //导航栏标题颜色,仅支持 black / white
navigationBarBackgroundColor:‘#000000’ //导航栏背景颜色
},
"tabBar": { // 小程序tab页
"list": [{
"pagePath": "pages/index/index",
"text": "首页"
}, {
"pagePath": "pages/logs/index",
"text": "日志"
}]
},
"networkTimeout": { //网络超时时间
"request": 10000,
"downloadFile": 10000
},
"debug": true, //可以在开发者工具中开启 debug 模式,在开发者工具的控制台面板,调试信息以 info 的形式给出,其信息有 Page 的注册,页面路由,数据更新,事件触发等。可以帮助开发者快速定位一些常见的问题。
}
- app.wxss:小程序的全局样式文件
4.2、pages
每个页面包含page.js、page.wxss、page.wxml、page.json
- pages.js
它主要用来监听页面的生命周期,以及页面的数据(类似于state)与处理逻辑(方法的定义);它必须要有;
//pages.js
Page({
data: { //页面的初始数据
text: "This is page data."
},
onLoad: function(options) {
// 页面创建时执行
},
onShow: function() {
// 页面出现在前台时执行
},
onReady: function() {
// 页面首次渲染完毕时执行
},
onHide: function() {
// 页面从前台变为后台时执行
},
onUnload: function() {
// 页面销毁时执行
},
onPullDownRefresh: function() {
// 触发下拉刷新时执行
},
onReachBottom: function() {
// 页面触底时执行
},
onShareAppMessage: function () {
// 页面被用户分享时执行
},
onPageScroll: function() {
// 页面滚动时执行
},
onResize: function() {
// 页面尺寸变化时执行
},
onTabItemTap(item) {
// tab 点击时执行
console.log(item.index)
console.log(item.pagePath)
console.log(item.text)
},
// 事件响应函数
viewTap: function() {
this.setData({
text: 'Set some data for updating view.'
}, function() {
// this is setData callback
})
},
// 自由数据
customData: {
hi: 'MINA'
}
})
-
pages.json
页面配置文件,主要用于组件(component)的注册(要想用公共组件的话,必须在每个页面的json文件中配置引入:自定义组件名+组件的绝对路径)、导航栏、上下拉刷新等,该文件不一定要有
-
pages.wxml
页面结构文件,类似与html文件,主要用于页面的结构显示、数据渲染、事件绑定等,它必须要有;
//示例
<view class="container"> //这边的view标签语义上都相当于是组件,用法上相当于div
<view class="userinfo">
<button wx:if="{{!hasUserInfo && canIUse}}"> 获取头像昵称 </button>
<block wx:else>
<image src="{{userInfo.avatarUrl}}" background-size="cover"></image>
<text class="userinfo-nickname">{{userInfo.nickName}}</text>
</block>
</view>
<view class="usermotto">
<text class="user-motto">{{motto}}</text>
</view>
</view>
-
pages.wxss
WXSS 具有 CSS 大部分的特性,小程序在 WXSS 也做了一些扩充和修改
4.3、component
它是组成页面的一部分,或者可以理解为重用价值价高的页面一部分;它的组成结构和页面一样,也是4个文件(component.js、component.wxss、component.wxml、component.json),如果后续某个页面中要想使用组件的话,那么必须先在要使用页面的json文件中先配置该组件,配置方式见上page.json
疑问:那么就有一个问题了,我们如何区分页面和组件呢?
答案:在component.json文件中有一个component:true来证明它是组件,而非页面;
五、文件夹基本结构规范
- app相关文件都放在根目录下;
- page文件放在单独的pages文件夹下,每个页面有一个单独的文件夹page1,page2…;
- 如果有公共组件,统一在根目录新建一个components文件夹,在它下面新建各个组件名文件夹,每个组件相关的文件都放在对应组件名的文件夹下;
六、WXML语法
- 数据绑定
WXML 中的动态数据均来自对应 Page 的 data
//简单绑定
<view> {{ message }} </view> //在wxml中直接引用变量,用{{}}
Page({
data: {
message: 'Hello MINA!'
}
})
//作为组件属性引入(需要在双引号之内)
<view id="item-{{id}}"> </view>
Page({
data: {
id: 0
}
})
//控制属性(需要在双引号之内)
<view wx:if="{{condition}}"> </view>
Page({
data: {
condition: true
}
})
//关键字(需要在双引号之内)
true:boolean 类型的 true,代表真值。
false: boolean 类型的 false,代表假值。
<checkbox checked="{{false}}"> </checkbox>
注意:不要直接写 checked="false",其计算结果是一个字符串,转成 boolean 类型后代表真值
<view wx:for="{{[1,2,3]}} ">
{{item}}
</view>
等同于
<view wx:for="{{[1,2,3] + ' '}}">
{{item}}
</view>
注意: 花括号和引号之间如果有空格,将最终被解析成为字符串
- 数据传递
//当需要给点击事件传递相应数据时,可以在组件中协商data-xx=xxx的属性,这个xx可以自定义name
//给该view组件绑定了一个点击事件tapName,并传递了参数Weixin
<view id="tapTest" data-hi="Weixin" bindtap="tapName"> Click me! </view>
//js中定义的tapName方法,传递的参数可以在target/currentTarget中的dataset取到传递的数据
Page({
tapName: function(event) {
console.log(event)
}
})
可以看到log出来的信息大致如下:
{
"type":"tap",
"timeStamp":895,
"target": {
"id": "tapTest",
"dataset": {
"hi":"Weixin"
}
},
"currentTarget": {
"id": "tapTest",
"dataset": {
"hi":"Weixin"
}
},
"detail": {
"x":53,
"y":14
},
"touches":[{
"identifier":0,
"pageX":53,
"pageY":14,
"clientX":53,
"clientY":14
}],
"changedTouches":[{
"identifier":0,
"pageX":53,
"pageY":14,
"clientX":53,
"clientY":14
}]
}
- 列表渲染
wx:for:
在组件上使用 wx:for 控制属性绑定一个数组,即可使用数组中各项的数据重复渲染该组件。默认数组的当前项的下标变量名默认为 index,数组当前项的变量名默认为 item
<view wx:for="{{array}}">
{{index}}: {{item.message}} //这里的index和item就可以直接用
</view>
Page({
data: {
array: [{
message: 'foo',
}, {
message: 'bar'
}]
}
})
使用 wx:for-item 可以指定数组当前元素的变量名;
使用 wx:for-index 可以指定数组当前下标的变量名;
<view wx:for="{{array}}" wx:for-index="idx" wx:for-item="itemName">
{{idx}}: {{itemName.message}}
</view>
block wx:for:
也可以将 wx:for 用在标签上,以渲染一个包含多节点的结构块
<block wx:for="{{[1, 2, 3]}}">
<view> {{index}}: </view>
<view> {{item}} </view>
</block>
- 条件渲染
wx:if:
使用 wx:if=“” 来判断是否需要渲染该代码块:
<view wx:if="{{condition}}"> True </view>
也可以用 wx:elif 和 wx:else 来添加一个 else 块:
<view wx:if="{{length > 5}}"> 1 </view>
<view wx:elif="{{length > 2}}"> 2 </view>
<view wx:else> 3 </view>
block wx:if:
因为 wx:if 是一个控制属性,需要将它添加到一个标签上。如果要一次性判断多个组件标签,可以使用一个 标签将多个组件包装起来,并在上边使用 wx:if 控制属性。
<block wx:if="{{true}}">
<view> view1 </view>
<view> view2 </view>
</block>
- 模板
模板:页面的片段,相对于component而言,template更加轻量级,它的功能有限,主要是用于展示。模板只有两个以.wxml 和.wxss结尾的文件
定义模板:使用 name 属性,作为模板的名字。然后在内定义代码片段,如:
<template name="msgItem">
<view>
<text> {{index}}: {{msg}} </text>
<text> Time: {{time}} </text>
</view>
</template>
使用模板:使用 is 属性,声明需要的使用的模板,然后将模板所需要的 data 传入,如:
<template is="msgItem" data="{{...item}}"/>
Page({
data: {
item: {
index: 0,
msg: 'this is a template',
time: '2016-09-15'
}
}
})
is 属性可以使用 Mustache 语法,来动态决定具体需要渲染哪个模板:
<template name="odd">
<view> odd </view>
</template>
<template name="even">
<view> even </view>
</template>
<block wx:for="{{[1, 2, 3, 4, 5]}}">
<template is="{{item % 2 == 0 ? 'even' : 'odd'}}"/>
</block>
引入模板:
<import src='/pages/template/xxx.wxml' /> 在页面的wxml中引入模板
@import '/pages/template/xxx.wxss' //在页面的wxss中引入模板的样式
注意:这个引入方式和组件的不太一样,需要对结构和样式分别引入
- 引用
WXML 提供两种文件引用方式import和include
import:可以在该文件中使用目标文件定义的template,就是上面模板中的引入;
在 item.wxml 中定义了一个叫item的template:
<!-- item.wxml -->
<template name="item">
<text>{{text}}</text>
</template>
在 index.wxml 中引用了 item.wxml,就可以使用item模板:
<import src="item.wxml"/>
<template is="item" data="{{text: 'forbar'}}"/>
注意:import 是有作用域的,它只会 import 目标文件中定义的 template,而不会 import 目标文件 import 的 template。
举个例子:如:C import B,B import A,在C中可以使用B定义的template,在B中可以使用A定义的template,但是C不能使用A定义的template。
七、生命周期
7.1、为什么要有生命周期函数这个东西存在?
答:因为用户在操作手机,使用小程序的过程中会有很多种可能出现的情况,比如启动小程序、把微信退到后台、打开了一个新页面、关闭页面等等,这些操作都会触发不同对象的不同生命周期阶段(这里说的不同对象指小程序种出现的APP对象、page对象、component对象),所以需要我们根据用户的不同操作来监听不同对象,进行相对应的处理,所以生命周期函数还是很重要的;
7.2、APP生命周期:
onLaunch:当小程序初始化完成,会触发,只触发一次;
onShow:当小程序启动,或从后台切到前台显示使用时触发,可以触发多次,每次打开小程序都会触发一次;
onHide:当小程序从前台切到后台时触发,也可以触发多次;
7.3、page页面的生命周期:
onLoad:页面刚开始被加载,这个生命周期函数种可以用来调一些接口时最好的,因为调接口也需要时间,然而页面加载也是需要时间的;这是最开始执行的生命周期函数;
onShow:监听页面显示,就是在这个函数种页面被慢慢显示,还没有渲染结束,是第二个执行的;
onReady:监听页面初次渲染完成;
onHide:监听页面隐藏;该函数是当小程序切到后台了,或者点击底部tabBar切换页面了,当前页面不显示被隐藏了会调用;
onUnload:监听页面被卸载;