小程序基础入门
小程序基础入门
一、课程介绍
二、本章任务
-
了解小程序的概念以及优势和劣势
-
掌握小程序的申请和创建流程
-
掌握小程序的基本模板语法
-
掌握小程序代码组成
-
了解小程序的渲染模型
-
掌握小程序事件的使用
三、本章目标
-
了解小程序是什么,以及小程序的优势和劣势
-
能够申请并且创建小程序
-
能够独立完成小程序界面的搭建和开发
-
实现Todo List的功能
四、知识点
1. 小程序介绍
小程序是什么?
-
小程序是一种新的开放能力,开发者可以快速地开发一个小程序。小程序可以在微信内被便捷地获取和传播,同时具有出色的使用体验。
-
任何一个普通的开发者,经过简单的学习和练习后,都可以轻松地完成一个小程序的开发和发布。
小程序的发展史
-
早年,随着微信越来越流行,微信逐渐成为移动互联网中一个主要的入口,越来越多的人会通过微信来分享和浏览网站。
-
微信基于WebView实现了前端界面的渲染,为了丰富微信中H5页面的功能,微信提供了JS-SDK,开放了拍摄、录音、语音识别、二维码、地图、支付、分享、卡券等几十个API。给所有的 Web 开发者打开了一扇全新的窗户,让所有开发者都可以使用到微信的原生能力,去完成一些之前做不到或者难以做到的事情了。
-
JS-SDK 解决了移动网页能力不足的问题,通过暴露微信的接口使得 Web 开发者能够拥有更多的能力,然而在更多的能力之外,JS-SDK 的模式并没有解决使用移动网页遇到的体验不良的问题。
-
用户在访问网页的时候,在浏览器开始显示之前都会有一个的白屏过程,在移动端,受限于设备性能和网络速度,白屏会更加明显。
-
除了白屏,影响 Web 体验的问题还有缺少操作的反馈,主要表现在两个方面:页面切换的生硬和点击的迟滞感。
-
-
为了提高用户体验和使用的流畅度,微信研发设计并且推出了微信小程序。
微信小程序的优势和劣势
优势
-
微信助理,容易推广。在微信中,小程序拥有众多入口,例如附近的小程序、小程序码、分享、发现-小程序等五十多个的入口。这些入口有助于企业更好的获取流量,从而进行转化、变现。
-
使用便捷。用户在使用小程序时,只需要轻轻点一下就可以使用,更加符合用户对使用方便、快捷的需求,所以小程序的用户数量不断增加。
-
体验良好,有接近原生app的体验。在微信生态里,小程序在功能和体验上是可以秒杀掉 H5 页面的,H5 页面经常出现卡顿、延时、加载慢、权限不足等原因,而这些问题在小程序里都不会出现。
-
成本更低,从开发成本到运营推广成本,小程序的花费仅为APP的十分之一,无论是对创业者还是传统商家来说都是一大优势。
不足
-
单个包大小限制为2M,这导致无法开发大型的应用,采用分包最大是16M(这个值一直在变化,以官网为准)。
-
需要像app一样审核上架,这点相对于H5的发布要麻烦一些。
-
处处受微信限制。例如不能直接分享到朋友圈,涉及到积分,或者虚拟交易的时候,小程序也是不允许的。
如何学习微信小程序
- 借助官方文档学习。 微信小程序有非常完善的官方文档,可以在官方文档上查到我们需要的所有东西。
https://developers.weixin.qq.com/miniprogram/dev/framework/
https://developers.weixin.qq.com/ebook?action=get_post_info&docid=0008aeea9a8978ab0086a685851c0a
- 可以通过社区进行学习,社区提供了很多优质的资源,可以加快小程序的开发效率,提升小程序的开发体验。
https://github.com/justjavac/awesome-wechat-weapp
2. 小程序的申请和创建流程
账号的申请
开发小程序首先要进行小程序的账号申请。
https://mp.weixin.qq.com/wxopen/waregister?action=step1&token=&lang=zh_CN
下载开发工具
这里大家可以从官方网站下载最新版的开发工具。因为这个开发工具一直在更新,所以建议大家直接从官网下载。
https://developers.weixin.qq.com/miniprogram/dev/devtools/download.html
获取AppId
登录后台管理系统获取AppId。
创建项目
3. 项目的目录结构
-
pages:
-
wxml: 编写小程序界面结构的地方
-
wxss: 编写小程序样式的地方
-
json:编写界面配置的地方
-
js:编写界面逻辑的地方
-
-
utils: 编写工具类的地方
-
app.js:创建程序实例的位置
-
app.json: 编写全局配置地方
-
app.wxss: 编写全局样式的地方
-
project.config.json: 项目的配置文件
-
sitemap.json:配置哪些页面可以被检索到
4. 小程序常用配置
https://developers.weixin.qq.com/miniprogram/dev/reference/configuration/app.html
配置导航窗口
https://developers.weixin.qq.com/miniprogram/dev/reference/configuration/app.html#window
配置页面
一般情况下我们会给每个页面创建一个文件夹,所以我们首先在pages下创建一个文件夹。
小程序直接给我们提供了创建页面的功能,右键这个文件夹,点击创建新建Page即可直接生成页面所需的文件。
生成文件之后,所有的页面都需要在app.json的pages属性中声明之后,才可以访问,小程序会默认先加载pages属性中第一个页面。如果开发过程如果我们需要调试别的页面,我们可以添加一个新的编译模式。
配置tabbar
https://developers.weixin.qq.com/miniprogram/dev/reference/configuration/app.html#tabBar
在移动端经常会涉及到tabbar的使用,小程序直接给我们提供了配置tabbar的方法。
这里需要注意的是,tabbar的图标不能是线上的地址,需要提前准备好放到项目里,一般情况下,这些静态资源可以放在assets文件夹下。这些图标大家可以从阿里矢量图标库中进行下载https://www.iconfont.cn/。
"tabBar": {
"list": [{
"pagePath": "pages/index/index",
"text": "首页",
"iconPath": "assets/icons/index.png",
"selectedIconPath": "assets/icons/index-active.png"
},{
"pagePath": "pages/my/index",
"text": "我的",
"iconPath": "assets/icons/wode.png",
"selectedIconPath": "assets/icons/wode-active.png"
}]
},
总结
小程序中的配置还有很多,大家也不用全部记住,需要的时候在查就可以了,大家需要掌握的是如何查阅文档。
5. 小程序模板语法WXML
WXML 全称是 WeiXin Markup Language,是小程序框架设计的一套标签语言,结合小程序的基础组件、事件系统,可以构建出页面的结构。
标签的使用
在小程序中没有H5提供的那些标签了,这里我们需要使用小程序给我们提供的组件。小程序给我们提供的标签很多,这里我们就介绍几个常用的,剩下的大家可以结合文档使用。
view标签是我们开发过程中最常用的标签了,这个就相当于Html中的div。
text标签也是我们开发中常用的,这个相当于Html中的span
image标签相当于我们Html中的img。
...
剩下的大家可以结合官方文档使用
https://developers.weixin.qq.com/miniprogram/dev/component/
数据绑定
用户界面呈现会因为当前时刻数据不同而有所不同,或者是因为用户的操作发生动态改变,这就要求程序的运行过程中,要有动态的去改变渲染界面的能力。
在 Web 开发中,开发者使用 JavaScript 通过Dom 接口来完成界面的实时更新。在小程序中,使用 WXML 语言所提供的数据绑定功能,来完成此项功能。
数据定义
在界面对应的JS文件中的data属性上定义数据
data: {
msg:\"hello world\",
num: 18,
},
引用数据
通过{{}}的方式可以引用数据。
除了引用数据之外,这里还可以进行一些计算,最终显示的结果是计算之后得到的结果。
<view>{{msg}},{{num + 10}}</view>
小程序中任何需要获取数据的地方都需要用{{}},包括标签内的属性。
逻辑渲染
WXML 中,使用 wx:if="{{condition}}" 来判断是否需要渲染该代码块:
<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>
因为 wx:if 是一个控制属性,需要将它添加到一个标签上。如果要一次性判断多个组件标签,可以使用一个 <block/> 标签将多个组件包装起来,并在上边使用 wx:if 控制属性。
<block wx:if="{{true}}">
<view> view1 </view>
<view> view2 </view>
</block>
除此之外微信小程序还可以通过hidden属性进行条件渲染。wx:if在不满足条件的时候会删除掉对应的DOM,hidden属性则是通过display属性设置为none来进行条件渲染。
<view hidden="{{condition}}">
隐藏
</view>
列表渲染
在组件上使用 wx:for 控制属性绑定一个数组,即可使用数组中各项的数据重复渲染该组件。默认数组的当前项的下标变量名默认为 index,数组当前项的变量名默认为 item。
<!-- array 是一个数组 -->
<view wx:for="{{array}}">
{{index}}: {{item.name}}
</view>
<!-- 对应的脚本文件
Page({
data: {
array: [{
name: '天亮教育',
}, {
name: '尚云科技'
}]
}
})
-->
使用 wx:for-item 指定数组当前元素的变量名,使用 wx:for-index 指定数组当前下标的变量名。
<view wx:for="{{array}}" wx:for-index="idx" wx:for-item="itemName">
{{idx}}: {{itemName.name}}
</view>
Key
如果列表中项目的位置会动态改变或者有新的项目添加到列表中,并且希望列表中的项目保持自己的特征和状态(如 <input/> 中的输入内容, <switch/> 的选中状态),需要使用 wx:key 来指定列表中项目的唯一的标识符。
wx:key 的值以两种形式提供:
-
字符串,代表在 for 循环的 array 中 item 的某个 property,该 property 的值需要是列表中唯一的字符串或数字,且不能动态改变。
-
保留关键字 this 代表在 for 循环中的 item 本身,这种表示需要 item 本身是一个唯一的字符串或者数字。
当数据改变触发渲染层重新渲染的时候,会校正带有 key 的组件,框架会确保他们被重新排序,而不是重新创建,以确保使组件保持自身的状态,并且提高列表渲染时的效率。
这里大家可以先体会一下key的概念,等到我们介绍到数据变化的时候在演示key作用。
6. 小程序样式wxss
WXSS(WeiXin Style Sheets)是一套用于小程序的样式语言,用于描述WXML的组件样式,也就是视觉上的效果。
WXSS与Web开发中的CSS类似。为了更适合小程序开发,WXSS对CSS做了一些补充以及修改。
尺寸单位
在WXSS中,引入了rpx(responsive pixel)尺寸单位。引用新尺寸单位的目的是,适配不同宽度的屏幕,开发起来更简单。
在小程序中,规定所有手机的屏幕宽度都是750rpx,所以在不同尺寸的屏幕下1rpx的宽度都不同。
1rpx = (屏幕宽度/750)px
在iphone6手机下,屏幕宽度是375px,所以1rpx=0.5px。
样式的导入
在小程序中,样式引用是这样写:
@import './test_0.wxss'
由于WXSS最终会被编译打包到目标文件中,用户只需要下载一次,在使用过程中不会因为样式的引用而产生多余的文件请求。
小程序中的样式选择器
目前支持的选择器。
小程序中会大量使用flex布局。多用一用flex布局。
7. 小程序中的JS
小程序中的js和浏览器中和node中的区别
浏览器中JS:
-
ES
-
DOM
-
BOM
Node中的JS:
-
ES
-
NPM
-
Native
小程序中的JS:
-
ES
-
小程序框架
-
小程序API
小程序中js的模块化
在小程序中实现JS模块化,和node中、ES6中是一致的,大家还可以使用之前的方式进行JS的模块化编程。
小程序中js的加载执行顺序
小程序的执行的入口文件是 app.js 。并且会根据其中 require 的模块顺序决定文件的运行顺序。
案例:JS文件模块化
小程序中js的执行环境
小程序目前可以运行在三大平台:
-
iOS平台,包括iOS9、iOS10、iOS11
-
Android平台
-
小程序IDE
8. 小程序中的数据渲染
小程序和浏览器中有什么不同
浏览器中渲染是单线程的。
而在小程序中的运行环境分成渲染层和逻辑层,第2章提到过 WXML 模板和 WXSS 样式工作在渲染层,JS 脚本工作在逻辑层。
小程序中如何渲染
我们看看小程序是如何把脚本里边的数据渲染在界面上的。
WXML模板使用 view 标签,其子节点用 {{ }} 的语法绑定一个 msg 的变量。
<view>{{ msg }}</view>
在 JS 脚本使用 this.setData 方法把 msg 字段设置成 "Hello World"。
Page({
onLoad: function () {
this.setData({ msg: 'Hello World' })
}
})
从这个例子我们可以看到3个点:
1.渲染层和数据相关。
2.逻辑层负责产生、处理数据。
3.逻辑层通过 Page 实例的 setData 方法传递数据到渲染层。
小程序中通讯模型
小程序的渲染层和逻辑层分别由2个线程管理:
渲染层的界面使用了WebView 进行渲染;
逻辑层采用JsCore线程运行JS脚本。
一个小程序存在多个界面,所以渲染层存在多个WebView线程,这两个线程的通信会经由微信客户端(下文中也会采用Native来代指微信客户端)做中转,逻辑层发送网络请求也经由Native转发。
生命周期示意图
数据驱动的思想
在开发UI的过程中,程序需要维护很多变量状态,同时要操作对应的UI元素。随着页面越来越复杂,我们需要维护的变量越来越多,同时要处理的界面上的交互也越来越多,整个程序会变的越来越复杂。
通常情况下视图和变量的状态是相关联的,如果有某种方法可以让状态和视图绑定在一起,那就可以让我们省去修改视图的工作,这个方法就叫做数据驱动。
在有了框架之后,我们一般很少会采用直接去修改视图的方式,更新界面了,绝大多数情况,都会通过操作数据的方式,来更新视图。通过数据去驱动视图渲染。
9. 程序和界面
程序
"小程序"指的是产品层面的程序,而"程序"指的是代码层面的程序实例,为了避免误解,下文采用App来代替代码层面的"程序"概念。
App({
onLaunch: function(options) {},
onShow: function(options) {},
onHide: function() {},
onError: function(msg) {},
globalData: 'I am global data'
})
宿主环境提供了 App() 构造器用来注册一个程序App,需要留意的是App() 构造器必须写在项目根目录的app.js里,App实例是单例对象,在其他JS脚本中可以使用宿主环境提供的 getApp() 来获取程序实例。
-
onLaunch: 当小程序初始化完成时,会触发 onLaunch(全局只触发一次)
-
onShow:当小程序启动,或从后台进入前台显示,会触发 onShow
-
onHide:当小程序从前台进入后台,会触发 onHide
-
onError:当小程序发生脚本错误,或者 API 调用失败时,会触发 onError 并带上错误信息。
-
其他字段:可以添加任意的函数或数据到 Object 参数中,在App实例回调用 this 可以访问。
小程序全局数据
我们在前面说到小程序的JS脚本是运行在JsCore的线程里,小程序的每个页面各自有一个WebView线程进行渲染,所以小程序切换页面时,小程序逻辑层的JS脚本运行上下文依旧在同一个JsCore线程中。
在上文中说道App实例是单例的,因此不同页面直接可以通过App实例下的属性来共享数据。App构造器可以传递其他参数作为全局属性以达到全局共享数据的目的。
在其他JS中可以通过getApp()获取App实例,之后可以获取到定义在App实例上的数据。
Page
一个小程序可以有很多页面,每个页面承载不同的功能,页面之间可以互相跳转。
页面构造器
Page({
data: { text: "This is page data." },
onLoad: function(options) { },
onReady: function() { },
onShow: function() { },
onHide: function() { },
onUnload: function() { },
onPullDownRefresh: function() { },
onReachBottom: function() { },
onShareAppMessage: function () { },
onPageScroll: function() { }
})
生命周期
onLoad:生命周期函数--监听页面加载,触发时机早于onShow和onReady
onReady:生命周期函数--监听页面初次渲染完成
onShow:生命周期函数--监听页面显示,触发事件早于onReady
onHide:生命周期函数--监听页面隐藏
onUnload:生命周期函数--监听页面卸载
数据
WXML可以通过数据绑定的语法绑定从逻辑层传递过来的数据字段,这里所说的数据其实就是来自于页面Page构造器的data字段,data参数是页面第一次渲染时从逻辑层传递到渲染层的数据。
在JS脚本中如果需要获取到data上的数据,需要通过this.data获取。
<!-- page.wxml -->
<view>{{text}}</view>
// page.js
Page({
data: {
text: '天亮教育',
},
onLoad(){
console.log(this.data.text)
}
})
如果涉及到更新,这里可以调用Page实例提供的setData把数据传递给渲染层,从而达到更新界面的目的。由于小程序的渲染层和逻辑层分别在两个线程中运行,所以setData传递数据实际是一个异步的过程,所以setData的第二个参数是一个callback回调,在这次setData对界面渲染完毕后触发。
setData其一般调用格式是 setData(data, callback),其中data是由多个key: value构成的Object对象。
// page.js
Page({
onLoad: function(){
this.setData({
text: 'change data'
}, function(){
// 在这次setData对界面渲染完毕后触发
})
}
})
注意事项:
-
直接修改 Page实例的this.data 而不调用 this.setData 是无法改变页面的状态的,还会造成数据不一致。
-
由于setData是需要两个线程的一些通信消耗,为了提高性能,每次设置的数据不应超过1024kB。
-
不要把data中的任意一项的value设为undefined,否则可能会有引起一些不可预料的bug。
页面的用户行为:
onPullDownRefresh 下拉刷新
监听用户下拉刷新事件,需要在app.json的window选项中或页面配置page.json中设置enablePullDownRefresh为true。当处理完数据刷新后,wx.stopPullDownRefresh可以停止当前页面的下拉刷新。
onReachBottom 上拉触底
监听用户上拉触底事件。可以在app.json的window选项中或页面配置page.json中设置触发距离onReachBottomDistance。在触发距离内滑动期间,本事件只会被触发一次。
onPageScroll 页面滚动
监听用户滑动页面事件,参数为 Object,包含 scrollTop 字段,表示页面在垂直方向已滚动的距离(单位px)。
onShareAppMessage 用户转发
只有定义了此事件处理函数,右上角菜单才会显示"转发"按钮,在用户点击转发按钮的时候会调用,此事件需要return一个Object,包含title和path两个字段,用于自定义转发内容,如代码清单3-13所示。
// page.js
Page({
onShareAppMessage: function () {
return {
title: '自定义转发标题',
// 自定义点击链接需要跳转的页面,默认当前页面
path: '/page/user?id=123'
}
}
})
10. 事件
事件定义
在小程序中绑定事件可以以bind开头然后跟上事件的类型,如bindtap绑定一个点击事件,对应的值是一个字符串,需要在page构造器中定义同名函数,每次触发事件之后就会执行对应函数的内容。
<view bindtap="handleTap">点击事件</view>
<view bind:tap="handleTap">另一种写法</view>
// pages/my/index.js
Page({
handleTap(){
console.log("执行了点击事件");
}
})
常见的事件类型
-
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 动画完成时触发
事件传参
在小程序中进行事件传参不能像传统的Web项目中一样,在括号里写参数。在小程序中需要在标签上通过data-方式定义事件所需的参数。
<!-- data-参数名='参数值' -->
<view bindtap="handleTap" data-msg="我是事件的参数">点击事件</view>
每个事件回调触发时,都会收到一个事件对象,通过这个对象可以获取路由传递的参数。
handleTap(e){
console.log("执行了点击事件");
// 通过currentTarget中的dataset属性可以获取时间参数
console.log(e.currentTarget.dataset.msg);
}
关于这个事件对象其他属性
-
type 事件类型
-
timeStamp 页面打开到触发事件所经过的毫秒数
-
target 触发事件的组件的一些属性值集合
-
currentTarget 当前组件的一些属性值集合
-
detail 额外的信息
-
touches 触摸事件,当前停留在屏幕中的触摸点信息的数组
-
changedTouches 触摸事件,当前变化的触摸点信息的数组
这里需要注意的是target和currentTarget的区别,currentTarget为当前事件所绑定的组件,而target则是触发该事件的源头组件。
阻止事件冒泡
在小程序中除了通过bind之外,还可以通过catch进行事件绑定,通过catch绑定的事件不会触发事件冒泡。
事件捕获
事件的触发分为两个阶段,首先是捕获阶段,其次是冒泡阶段。默认情况下事件都是在冒泡阶段触发。如果希望事件可以在捕获阶段触发,可以通过capture-bind进行事件绑定。