1.邂逅小程序开发
什么是小程序?
微信小程序是一种全新的连接用户与服务的方式,它可以在微信内被便捷地获取和传播,同时具有出色的使用体验
小程序是微信生态的一部分, 它提供了一种更加方便和高效的用户交互方式.
小程序的出现到底带来了什么呢?
-
用户使用的便捷性
普通的APP我们需要的使用过程:了解APP - 下载 - 打开 - 注册 - 使用
小程序版本的APP的使用过程:了解APP - 打开(扫码/搜索) - 使用 -
远好于公众号和H5页面的体验
比如寄顺丰快递,使用公众号和小程序的体验差异非常大; -
释放手机内存空间
对于手机空间不大的人来说, 安装很多App会带来灾难, 经常面临空间不足; 小程序不需要安装, 而且有规定的大小(目前不能超过8M,包括在使用分包的情况下); -
让手机桌面更加简洁
不需要下载App, 就不需要花时间来管理自己的App了;
小程序开发的必要性
由于小程序各种好处,使用小程序的用户会越来越多
那么从公司角度,有自己的小程序就变得非常有必要
一方面,为了给用户带来更加便捷的使用体验,需要开发对应一款小程序:
开发出来的小程序,用户体验优于H5的体验,并且底层可以调用原生的各种接口;
而且可以做到:一端开发,多端运行(iOS端、Android端);
另一方面,必须抢占小程序的市场:
你不开发,你竞争对手也会开发,当大量用户为了使用方便涌入你的竞争对手时,你就来不及了;
所以现在公司经常出现,让前端或客户端程序员,甚至是服务端程序员去帮公司做一个小程序。
小程序的诞生
我们知道,任何新的技术或者模式的产生,都是为了解决行业的痛点:小程序就是在这样的背景下诞生的
小程序正是大家期盼已久的产物,它有什么特点呢:
1.类似于Web 开发模式,入门的门槛低:基本上是类似于html+css+js;
2.可直接云端更新:微信审核,无需经过App Store等平台;
3.提升用户体验:通过提供基础能力、原生组件结合等方式,提升用户体验;
4.平台管控能力:小程序提供云端更新,通过代码上传、审核等方式,增强对开发者的管控能力;
5.双线程模型:逻辑层和渲染层分开加载,提供了管控型和安全性(沙盒环境运行JS代码,不允许执行任何和浏览器相关的接口,比如跳转页面、操作DOM等);
目前小程序已经在用户和开发者中普及起来,并且依附于微信平台大量的人群基数,正在快速的发展
小程序预备知识
小程序的开发主要分成三部分:
页面布局:WXML,类似HTML
页面样式:WXSS,几乎就是CSS(某些不支持,某些进行了增强)
页面脚本:JavaScript+WXS,(JS,以及WeixinScript后续学习)
也就是学习微信小程序还是需要大家具备基本的前端知识
开发前准备工作
申请AppID和下载开发工具不再演示
开发工具介绍
应用程序的结构
小程序结构划分:最上层App -> 多个Page -> 多个组件
应用目录的结构
从零搭建项目
删除项目中原有的文件(保留project.config.js – sitemap.json)
找不到app.json, 所以创建一个app.json文件
在app.json最外层添加对象:
缺少一个字段pages
保存上面的操作, 就会看到如下页面:
修改代码,显示 你好,月光
修改样式:
补齐app.js和app.wxss:
小程序初体验
2.小程序构架和配置
配置小程序
小程序的很多开发需求被规定在了配置文件中。
为什么这样做呢?
1.这样做可以更有利于我们的开发效率;
2.并且可以保证开发出来的小程序的某些风格是比较一致的;
比如导航栏 – 顶部TabBar,以及页面路由等等。
常见的配置文件有哪些呢?
project.config.json:项目配置文件, 比如项目名称、appid等;
https://developers.weixin.qq.com/miniprogram/dev/devtools/projectconfig.html
sitemap.json:小程序搜索相关的;
https://developers.weixin.qq.com/miniprogram/dev/framework/sitemap.html
app.json:全局配置;
page.json:页面配置;
全局配置
全局配置比较多, 我们这里将几个比较重要的. 完整的查看官方文档.
https://developers.weixin.qq.com/miniprogram/dev/reference/configuration/app.html
pages: 页面路径列表
用于指定小程序由哪些页面组成,每一项都对应一个页面的 路径(含文件名) 信息。
小程序中所有的页面都是必须在pages中进行注册的。
window: 全局的默认窗口展示
用户指定窗口如何展示, 其中还包含了很多其他的属性
tabBar: 顶部tab栏的展示
案例实现
页面配置
每一个小程序页面也可以使用 .json 文件来对本页面的窗口表现进行配置。
页面中配置项在当前页面会覆盖 app.json 的 window 中相同的配置项。
小程序的双线程模型
谁是小程序的宿主环境呢?微信客户端
宿主环境为了执行小程序的各种文件:wxml文件、wxss文件、js文件, 提供了小程序的双线程模型
双线程模型:
WXML模块和WXSS样式运行于 渲染层,渲染层使用WebView线程渲染(一个程序有多个页面,会使用多个WebView的线程)。
JS脚本(app.js/home.js等)运行于 逻辑层,逻辑层使用JsCore运行JS脚本。
这两个线程都会经由微信客户端(Native)进行中转交互。
小程序的启动流程
注册小程序 – 参数解析
每个小程序都需要在 app.js 中调用 App 方法注册小程序示例
在注册时, 可以绑定对应的生命周期函数, 在生命周期函数中, 执行对应的代码.
https://developers.weixin.qq.com/miniprogram/dev/reference/api/App.html
注册小程序 - 代码演示
注册页面
小程序中的每个页面, 都有一个对应的js文件, 其中调用Page方法注册页面示例
在注册时, 可以绑定初始化数据、生命周期回调、事件处理函数等。
https://developers.weixin.qq.com/miniprogram/dev/reference/api/Page.html
注册一个Page页面时,我们一般需要做什么呢?
1.在生命周期函数中发送网络请求,从服务器获取数据;
2.初始化一些数据,以方便被wxml引用展示;
3.监听wxml中的事件,绑定对应的事件函数;
4.其他一些监听(比如页面滚动、上拉刷新、下拉加载更多等);
3.常见内置组件
Text组件
Text组件用于显示文本, 类似于span标签, 是行内元素
selectable属性决定文本内容是否可以让用户选中
space有三个取值
decode是否解码
Text组件演练
Button组件解析
Button组件用于创建按钮,默认块级元素
常见属性:
Button组件演练
open-type的取值
open-type用户获取一些特殊性的权限,可以绑定一些特殊的事件:
View组件
视图组件(块级元素,独占一行,通常用作容器组件)
View组件演练
Image组件介绍
Image组件用于显示图片,有如下常见属性:
其中src可以是本地图片,也可以是网络图片
Mode属性使用也非常关键,详情查看官网:
https://developers.weixin.qq.com/miniprogram/dev/component/image.html
注意:image组件默认宽度320px、高度240px
Image组件演练
Input组件的介绍
Input组件用于接收用户的输入信息,也是开发中非常常见的,有如下属性:
Input组件演练
scroll-view组件介绍
scroll-view可以实现局部滚动,常见属性如下:
注意事项:
实现滚动效果必须添加scroll-x或者scroll-y属性(只需要添加即可,属性值相当于为true了)
垂直方向滚动必须设置scroll-view一个高度
scroll-view代码演练
共同属性
所有wxml标签(组件)都支持的属性称之为共同属性,有如下共同属性
4.WXSS&WXML
页面样式写法
页面样式的三种写法:
行内样式、页面样式、全局样式
三种样式都可以作用于页面的组件
如果有相同的样式
优先级依次是:行内样式 > 页面样式 > 全局样式
wxss的扩展 – 尺寸单位
尺寸单位
rpx(responsive pixel): 可以根据屏幕宽度进行自适应。规定屏幕宽750rpx。
如在 iPhone6 上,屏幕宽度为375px,共有750个物理像素,则750rpx =375px = 750物理像素,1rpx = 0.5px = 1物理像素
建议: 开发微信小程序时设计师可以用 iPhone6 作为视觉稿的标准。
wxss的扩展 – 样式导入
为什么使用样式导入?
在某些情况下,我们可能会将样式分在多个wxss文件中,方便对样式的管理。
这个时候,我们就可以使用样式导入,来让单独的wxss生效
我们可以在一个wxss中导入另一个wxss文件:
1.使用@import进行导入
2. @import后跟需要导入的外联样式表的相对路径(或者绝对路径也可以),用;表示语句结束。
导入的位置在哪里?
可以在app.wxss中导入这个样式
也可以在page.wxss导入这个样式
官方样式库
为了减少开发者样式开发的工作量,小程序官方提供了WeUI.wxss基本样式库
https://github.com/Tencent/weui-wxss
Mustache语法
WXML基本格式:
类似于HTML代码:比如可以写成单标签,也可以写成双标签
必须有严格的闭合:没有闭合会导致编译错误
大小写敏感:class和Class是不同的属性
开发中, 界面上展示的数据并不是写死的, 而是会根据服务器返回的数据, 或者用户的操作来进行改变.
如果使用原生JS或者jQuery的话, 我们需要通过操作DOM来进行界面的更新.
小程序和Vue/React一样, 提供了插值语法: Mustache语法(双大括号)
Mustache语法不仅仅可以直接显示数据, 也可以使用表达式:
并且可以绑定到属性:
逻辑判断 wx:if – wx:elif – wx:else
某些时候, 我们需要根据条件来决定一些内容是否渲染:
当条件为true时, view组件会渲染出来
当条件为false时, view组件不会渲染出来
根据按钮点击, 决定是否渲染:
也可以有多个条件:
逻辑判断补充
hidden属性:
hidden是所有的组件都默认拥有的属性,
当hidden属性为true时, 组件会被隐藏
当hidden属性为false时, 组件会显示出来
hidden和wx:if的区别
hidden控制隐藏和显示控制是否添加hidden属性
wx:if是控制组件是否渲染的
列表渲染 – wx:for基础
为什么使用wx:for?
我们知道,在实际开发中,服务器经常返回各种列表数据,我们不可能一一从列表中取出数据进行展示;
需要通过for循环的方式,遍历所有的数据,一次性进行展示;
在组件中,我们可以使用wx:for来遍历一个数组 (字符串 - 数字)
默认情况下,遍历后在wxml中可以使用一个变量index,保存的是当前遍历数据的下标值。
数组中对应某项的数据,使用变量名item获取。
block标签
什么是block标签?
某些情况下,我们需要使用 wx:if 或 wx:for时,可能需要包裹一组组件标签
我们希望对这一组组件标签进行整体的操作,这个时候怎么办呢?
方式一:使用一个view组件包裹:
方式二:使用block标签
block标签的意义
注意:
并不是一个组件,它仅仅是一个包装元素,不会在页面中做任何渲染,只接受控制属性。
使用block有两个好处:
1.将需要进行遍历或者判断的内容进行包裹。
2.将遍历和判断的属性放在block便签中,不影响普通属性的阅读,提高代码的可读性。
列表渲染 – item/index名称
默认情况下,item – index的名字是固定的
但是某些情况下,我们可能想使用其他名称
或者当出现多层遍历时,名字会重复
这个时候,我们可以指定item和index的名称:
列表渲染 – key作用
我们看到,使用wx:for时,会报一个警告:
这个提示告诉我们,可以添加一个key来提供性能。
为什么需要这个key属性呢?
这个其实和小程序内部也使用了虚拟DOM有关系(和Vue、React很相似)。
当某一层有很多相同的节点时,也就是列表节点时,我们希望插入一个新的节点
我们希望可以在B和C之间加一个F,Diff算法默认执行起来是这样的。
即把C更新成F,D更新成C,E更新成D,最后再插入E,是不是很没有效率?
所以我们需要使用key来给每个节点做一个唯一标识
Diff算法就可以正确的识别此节点
找到正确的位置区插入新的节点。
所以一句话,key的作用主要是为了高效的更新虚拟DOM。
模板用法
WXML提供模板(template),可以在模板中定义代码片段,在不同的地方调用。(是一种wxml代码的复用机制)
使用 name 属性,作为模板的名字, 然后在 template 内定义代码片段
wxml的引入
小程序wxml中提供了两种引入文件的方式:import和include
Import引入:import 可以在该文件中使用目标文件定义的 template
比如下面的演练:
在item.wxml中定义一个item的template
在home.wxml中引入,并且使用template
注意:wxml中不能递归引入(也就是A引入了B的template,不会引入B中引入C的template)
include引入
include 可以将目标文件中除了 template、wxs 外的整个代码引入,相当于是拷贝到 include 位置:
5.事件处理
事件的介绍
什么时候会产生事件呢?
小程序需要经常和用户进行某种交互,比如点击界面上的某个按钮或者区域,比如滑动了某个区域;
这些交互都会产生各种各样的事件;
事件如何处理呢?
事件是通过bind/catch这个属性绑定在组件上的(和普通的属性写法很相似, 以key=“value”形式);
key以bind或catch开发, 从1.5.0版本开始, 可以在bind和catch后加上一个冒号;
同时在当前页面的Page构造器中定义对应的事件处理函数tapName, 如果没有对应的函数, 触发事件时会报错
当用户点击该button区域时,达到触发条件生成事件tap,该事件处理函数tapName会被执行,同时还会收到一个事件对象event。
事件的简单演练
事件的简单演练:
常见事件类型
某些组件会有自己特性的事件类型,大家可以在使用组件时具体查看对应的文档
比如input有bindinput/bindblur/bindfocus等
比如scroll-view有bindscrolltowpper/bindscrolltolower等
这里我们讨论几个组件都有的, 并且也比较常见的事件类型:
事件类型演练
事件类型的演练
有两个注意点:
Touchcancle: 在某些特定场景下才会触发(比如来电打断等)
tap事件和longpress事件通常只会触发其中一个
事件对象介绍
当某个事件触发时, 会产生一个事件对象, 并且这个对象被传入到回调函数中, 事件对象有哪些常见的属性呢?
touches和changedTouches的区别
1.在touchend中不同
2.多手指触摸时不同
currentTarget和target的区别
事件参数的传递
当视图层发生事件时,某些情况需要事件携带一些参数到执行的函数中, 这个时候就可以通过data-属性来完成:
格式:data-属性的名称
获取:e.currentTarget.dataset.属性的名称
参数传递的练习
6.组件化开发
什么是组件化?
人面对复杂问题的处理方式:
任何一个人处理信息的逻辑能力都是有限的
所以,当面对一个非常复杂的问题时,我们不太可能一次性搞定一大堆的内容。
但是,我们人有一种天生的能力,就是将问题进行拆解。
如果将一个复杂的问题,拆分成很多个可以处理的小问题,再将其放在整体当中,你会发现大的问题也会迎刃而解。
组件化也是类似的思想:
如果我们将一个页面中所有的处理逻辑全部放在一起,处理起来就会变得非常复杂,而且不利于后续的管理以及扩展。
但如果,我们将一个页面拆分成一个个小的功能块,每个功能块完成属于自己这部分独立的功能,那么之后整个页面的管理和维护就变得非常容易了。
小程序组件化思想
小程序在刚刚推出时是不支持组件化的, 也是为人诟病的一个点.
但是从v1.6.3开始, 小程序开始支持自定义组件开发, 也让我们更加方便的在程序中使用组件化.
组件化思想的应用:
有了组件化的思想,我们在之后的开发中就要充分的利用它。
尽可能的将页面拆分成一个个小的、可复用的组件。
这样让我们的代码更加方便组织和管理,并且扩展性也更强。
创建一个自定义组件
类似于页面,自定义组件由 json wxml wxss js 4个文件组成。
我们会先在根目录下创建一个文件夹components, 里面存放我们之后自定义的公共组件.
常见一个自定义组件 my-cpn: 包含对应的四个文件.
自定义组件的步骤:
1.首先需要在 json 文件中进行自定义组件声明(将
component 字段设为 true 可使这一组文件设为自定义组件):
2.在wxml中编写属于我们组件自己的模板
3.在wxss中编写属于我们组件自己的相关样式
4.在js文件中, 可以定义数据或组件内部的相关逻辑
使用自定义组件和细节注意事项
一些需要注意的细节:
因为 WXML 节点标签名只能是 小写字母、中划线和下划线 的组合,所以自定义组件的标签名也只能包含这些字符。
自定义组件也是可以引用自定义组件的,引用方法类似于页面引用自定义组件的方式(使用usingComponents 字段)。
自定义组件和页面所在项目根目录名 不能以“wx-”为前缀,否则会报错。
如果在app.json的usingComponents声明某个组件,那么所有页面和组件可以直接使用该组件。
组件的样式细节
课题一:组件内的样式对外部样式的影响
结论一:组件内的class样式,只对组件wxml内的节点生效, 对于引用组件的Page页面不生效。
结论二:组件内不能使用id选择器、属性选择器、标签选择器
课题二:外部样式对组件内样式的影响
结论一:外部使用class的样式,只对外部wxml的class生效,对组件内是不生效的
结论二:外部使用了id选择器、属性选择器不会对组件内产生影响
结论三:外部使用了标签选择器,会对组件内产生影响
整体结论:
组件内的class样式和组件外的class样式, 默认是有一个隔离效果的;
为了防止样式的错乱,官方不推荐使用id、属性、标签选择器;
样式的相互影响
课题三:如何让class可以相互影响
在Component对象中,可以传入一个options属性,其中options属性中有一个styleIsolation(隔离)属性。
styleIsolation有三个取值:
isolated 表示启用样式隔离,在自定义组件内外,使用 class 指定的样式将不会相互影响(默认取值);
apply-shared 表示页面 wxss 样式将影响到自定义组件,但自定义组件 wxss 中指定的样式不会影响页面;
shared 表示页面 wxss 样式将影响到自定义组件,自定义组件 wxss 中指定的样式也会影响页面和其他设置了
其他一些相关样式细节,参考官网:
https://developers.weixin.qq.com/miniprogram/dev/framework/custom-component/wxml-wxss.html
组件和页面通信
很多情况下,组件内展示的内容(数据、样式、标签),并不是在组件内写死的,而是可以由使用者来决定。
向组件传递数据 - properties
给组件传递数据:
大部分情况下,组件只负责布局和样式,内容是由使用组件的对象决定的。
所以,我们经常需要从外部传递数据给我们的组件,让我们的组件来进行展示。如何传递呢?
使用properties属性:
支持的类型:
String、Number、Boolean
Object、Array、null(不限制类型)
向组件传递样式 - externalClasses
给组件传递样式:
有时候,我们不希望将样式在组件内固定不变,而是外部可以决定样式。
这个时候,我们可以使用externalClasses属性:
1.在Component对象中,定义externalClasses属性
2.在组件内的wxml中使用externalClasses属性中的class
3.在页面中传入对应的class,并且给这个class设置样式
组件向外传递事件 – 自定义事件
页面直接调用组件方法
this.selectComponent
什么是插槽
slot翻译为插槽:
在生活中很多地方都有插槽,电脑的USB插槽,插板当中的电源插槽。
插槽的目的是让我们原来的设备具备更多的扩展性。
比如电脑的USB我们可以插入U盘、硬盘、手机、音响、键盘、鼠标等等。
组件的插槽:
组件的插槽也是为了让我们封装的组件更加具有扩展性。
让使用者可以决定组件内部的一些内容到底展示什么。
例子:移动网站中的导航栏。
移动开发中,几乎每个页面都有导航栏。
导航栏我们必然会封装成一个插件,比如nav-bar组件。
一旦有了这个组件,我们就可以在多个页面中复用了。
单个插槽的使用
除了内容和样式可能由外界决定之外,也可能外界想决定显示的方式
比如我们有一个组件定义了头部和尾部,但是中间的内容可能是一段文字,也可能是一张图片,或者是一个进度条。
在不确定外界想插入什么其他组件的前提下,我们可以在组件内预留插槽:
多个插槽的使用
有时候为了让组件更加灵活, 我们需要定义多个插槽:
7.小程序系统API
网络请求 – 基本使用
微信提供了专属的API接口,用于网络请求: wx.request(Object object)
比较关键的几个属性解析:
url: 必传, 请求地址.
data: 请求参数
method: 请求的方式
success: 成功时的回调
fail: 失败时的回调
网络请求 – 代码演练
网络请求 – 请求封装
目前我们采用的网络请求是非常古老的请求方式, 我们将它封装成Promise的方式:
展示弹窗
小程序中展示弹窗有四种方式: showToast、showModal、showLoading、showActionSheet
页面分享
分享是小程序扩散的一种重要方式,小程序中有两种分享方式:
点击右上角的菜单按钮,之后点击转发
点击某一个按钮,直接转发
当我们转发给好友一个小程序时,通常小程序中会显示一些信息:
如何决定这些信息的展示呢?通过 onShareAppMessage
界面跳转
界面的跳转有两种方式:
通过navigator组件 和 通过wx的API跳转
navigator组件主要就是用于界面的跳转的:
open-type的取值
redirect:关闭当前页面,跳转到应用内的某个页面。但是不允许跳转到 tabbar 页面,并且不能返回。(不是一个压栈)
switchTab:跳转到 tabBar 页面,并关闭其他所有非 tabBar 页面。(需要在tabBar中定义)
reLaunch:关闭所有的页面,打开应用中某个页面。(直接展示某个页面,并且可以跳转到tabBar页面)
导航返回
导航返回有两个属性来起作用:
open-type:navigateBack(表示该navigator组件用于返回)
delta:返回的层级(指定返回的层级,open-type必须是navigateBack才生效)
代码的跳转和返回
很多情况下,我们并不喜欢使用navigator组件来进行跳转:
可能我们希望用户点击了某个button或者view时,对该button或者view进行监听
之后,通过相关的代码逻辑实现跳转
对此,微信也提供了对应的API接口:
wx.navigateTo(url[, ])
wx.navigateBack([delta])