一、小程序的运行环境
小程序一般运行在以下三种环境:IOS、Android、以及小程序开发平台上面(一般用于调试与测试);
小程序在启动后,页面被展示给用户,此时的小程序处于前台状态。
当用户点击手机右上角的关闭按钮时或者Home键离开微信时,小程序并未完全终止运行,而是进入了后台状态在运行一段时间。
当用户在一次进入微信小程序时,它又会从后台进入前台。
但是有两种情况会使得小程序销毁:1、用户长时间不使用; 2、系统的资源配置紧张;
(注:开发者工具仅供调试使用,最终的表现以客户端为准。两者之间存在些许不同,但总体上不会有什么变化)
二、小程序的运行机制
小程序的启动:冷启动和热启动两种方式;
冷启动:用户首次使用小程序(或小程序被销毁后再一次被用户使用)
热启动:用户使用过小程序,在一段时间过后又再一次使用(即从后台又重新返回前台)
简单的一句话,当你使用的时候它就会启动,在你长时间不使用的时候它就会关闭。
三、小程序的更新机制
1、未启动时的更新:开发者在管理后台发布新版本的小程序之后,如果某个用户本地有小程序的历史版本,此时打开的可能还是旧版本。微信客户端会有若干个时机去检查本地缓存的小程序有没有更新版本,如果有则会静默更新到新版本。总的来说,开发者在后台发布新版本之后,无法立刻影响到所有现网用户,但最差情况下,也在发布之后 24 小时之内下发新版本信息到用户。用户下次打开时会先更新最新版本再打开。
2、冷启动时的更新:小程序每次冷启动时,都会检查是否有更新版本,如果发现有新版本,将会异步下载新版本的代码包,并同时用客户端本地的包进行启动,即新版本的小程序需要等下一次冷启动才会应用上。
总的来说,微信小程序的更新机制给予用户良好的体验,在程序更新(异步更新)过程中也不会影响用户的使用。
四、自定义组件
开发者可以将页面的功能或者复杂的页面拆分成多个低耦合的模块,以此来增加代码的复用和增强其维护性;
创建方式:在 json
文件中进行自定义组件声明(将 component
字段设为 true
可将这一组文件设为自定义组件),还要在 wxml
文件中编写组件模板,在 wxss
文件中加入组件样式,它们的写法与页面的写法类似。在自定义组件的 js
文件中,需要使用 Component()
来注册组件,并提供组件的属性定义、内部数据和自定义方法。
使用方式:在页面的 json
文件中进行引用声明。此时需要提供每个自定义组件的标签名和对应的自定义组件文件路径
//wxml页面
<!--pages/A/A.wxml-->
<text class="inner">{{info}}</text>
<view style="background-color:blue; height:80rpx;" bindtap="customMethod">{{innerText}}</view> //wxml页面模板
//js页面
Component({
properties: {
// 这里定义了innerText属性,属性值可以在组件使用时指定
innerText: String
},
data: {
// 这里是一些组件内部数据
"info":"页面A内部数据"
},
methods: {
// 这里是一个自定义方法
customMethod: function () {
console.log(this.innerText)
}
}
}) //自定义组件的js,properties为外部数据,data内部数据
//methods页面处理方法
//json
{
"usingComponents": {} ,
"component": true //将其设置为自定义组件
}
/* pages/A/A.wxss */
page{
text-align: center;
}
.inner {
color: red;
} //自定义组件的样式
//自定义控件的使用
<view>
<!-- 以下是对一个自定义组件的引用 -->
<component-tag-name inner-text="从外部页面传递的数据,非A页面"></component-tag-name>
</view>
//使用页面的json页面
{
"usingComponents": {
"component-tag-name": "../A/A" //使用的自定义组件的路径
}
}
//component-tag-name可以由用户定义,即任意定义,但使用的时候要用对应的名称
细节注意事项:
- 因为 WXML 节点标签名只能是小写字母、中划线和下划线的组合,所以自定义组件的标签名也只能包含这些字符。
- 自定义组件也是可以引用自定义组件的,引用方法类似于页面引用自定义组件的方式(使用
usingComponents
字段)。 - 自定义组件和页面所在项目根目录名不能以“wx-”为前缀,否则会报错。
- 组件和引用组件的页面不能使用id选择器(
#a
)、属性选择器([a]
)和标签名选择器,请改用class选择器。 - 组件和引用组件的页面中使用后代选择器(
.a .b
)在一些极端情况下会有非预期的表现,如遇,请避免使用。 - 子元素选择器(
.a>.b
)只能用于view
组件与其子节点之间,用于其他组件可能导致非预期的情况。 - 继承样式,如
font
、color
,会从组件外继承到组件内。 - 除继承样式外,
app.wxss
中的样式、组件所在页面的的样式对自定义组件无效(除非更改组件样式隔离选项)。
(说的简单点在样式中貌似只能使用类选择器了,哈哈)
默认情况下,一个组件的wxml中只能有一个slot。需要使用多slot时,可以在组件js中声明启用
options: {
multipleSlots: true // 在组件定义时的选项中启用多slot支持
}
只需要在js中配置上述语句,对于在代码中的slot可以定义其的名字(唯一),并且在使用时也可以通过
定义的名字将内容插入到对应的slot下面
默认情况下,自定义组件的样式只受到自定义组件 wxss 的影响。除非以下两种情况:
app.wxss
或页面的wxss
中使用了标签名选择器(或一些其他特殊选择器)来直接指定样式,这些选择器会影响到页面和全部组件。通常情况下这是不推荐的做法。- 指定特殊的样式隔离选项
styleIsolation
。(用于隔离样式)
options: {
styleIsolation: 'isolated'
} //只需要将样式隔离的值定义为isolated,也写在js的option字段下
isolated 表示启用样式隔离,在自定义组件内外,使用 class 指定的样式将不会相互影响(一般情况下的默认值);
apply-shared 表示页面 wxss 样式将影响到自定义组件,但自定义组件 wxss 中指定的样式不会影响页面;
shared 表示页面 wxss 样式将影响到自定义组件,自定义组件 wxss 中指定的样式也会影响页面和其他设置了 apply-shared 或 shared 的自定义组件。(这个选项在插件中不可用。)
第一种是组件内外的样式不会相互影响,即内外实现绝对分离。
第二种外部会影响内部,但内部对外部不会产生影响。
第三种,两种样式相互影响。(对于这一条属性字段一般不会使用默认为隔离状态,不会影响对方)
纯数据字段:纯数据字段是一些不用于界面渲染的 data 字段,可以用于提升页面更新性能。
options: {
pureDataPattern: /^_/ // 指定所有 _ 开头的数据字段为纯数据字段
//为一个正则表达式,字段名符合这个正则表达式的字段将成为纯数据字段。
}
(注:纯数据字段不会被应用到 WXML 上,但可以在js中使用)
五、文件系统
文件主要分为两大类:
- 代码包文件:代码包文件指的是在项目目录中添加的文件。(小程序源码以及简单的数据信息)
- 本地文件:通过调用接口本地产生,或通过网络下载下来,存储到本地的文件。
其中本地文件又分为三种:
- 本地临时文件:临时产生,随时会被回收的文件。不限制存储大小。
- 本地缓存文件:小程序通过接口把本地临时文件缓存后产生的文件,不能自定义目录和文件名。
- 本地用户文件:小程序通过接口把本地临时文件缓存后产生的文件,允许自定义目录和文件名。
代码包文件的访问方式是从项目根目录开始写文件路径,不支持相对路径的写法。代码包内的文件无法在运行后动态修改或删除,修改代码包文件需要重新发布版本。(即代码包文件路径不能修改,且访问是从根目录开始)
本地文件指的是小程序被用户添加到手机后,会有一块独立的文件存储区域,以用户维度隔离。(和我们无关……)其定义格式为{{协议名}}://文件路径。(就是个URL)
清理策略:本地临时文件只保证在小程序当前生命周期内,一旦小程序被关闭就可能被清理,即下次冷启动不保证可用。本地缓存文件和本地用户文件的清理时机跟代码包一样,只有在代码包被清理的时会被清理。(临时文件关闭程序的时候回被清理,另外两种文件只有在小程序被清理时才会被清理)
六、画布(动画效果)
所有在canvas中的画图必须用 JavaScript 完成(即必须用js进行操作)
const ctx = wx.createCanvasContext('myCanvas') //canvas的获取,一般定义为常量
绘制图像一般与bindtouchstart,bindtouchmove,bindtouchend一起使用。以此来实现动态的绘制图像
对于获取坐标位置,一般通过e.touches[0].x和e.touches[0].y来获取当前的坐标(x,y)位置;
createLinearGradient(x, y, x1, y1) | 创建一个线性的渐变 |
createCircularGradient(x, y, r) | 创建一个从圆心开始的渐变 |
addColorStop(position, color) | 指定颜色渐变点的位置和颜色,position,位置必须位于0到1之间 |
setFillStyle() & setStrokeStyle() | 设置填充或描边样式 |
rgb(num1, num2, num3) | rgb颜色 |
setShadow(X,Y,blur,color) | 设置阴影,X和Y用于设置偏移,blur设置模糊级别,color颜色 |
setLineWidth(lineWidth) | 设置线条的宽度 |
moveTo(x,y) | 把路径移动到画布中的指定点,不创建线条。 |
lineTo(x,y) | 增加一个新点,然后创建一条从上次指定点到目标点的线。 |
stroke() | 绘制线条 |
drew(reserve,callback) | reserve为true继续绘制,false为清空绘制,callback为回调函数 |
scale(scaleWidth,scaleHeight) | 长宽的缩放倍数 |
rotate(degrees * Math.PI/180;) | 进行图像的旋转指定的角度 |
translate(x,y) | 对当前坐标系的原点(0, 0)进行变换,默认的坐标系原点为页面左上角。 |
setGlobalAlpha(alpha) | 设置透明度。alpha为0-1 |
drawImage(src,x,y,width,height) | 绘制一幅图片 |
save()和restore() | 保存图片 |
fillText(text,x,y) | 在对应位置绘制文本信息 |
setFontSize(fontSize) | 设置文本大小 |
setTextAlign(align) | align=[ 'left'、'center'、'right'],设置对齐方式 |
arcTo(x1, y1, x2, y2, radius) | 根据控制点和半径绘制圆弧路径。 |
通过canvas可以实现简单的画板功能:(详见下代码和运行结果)
<canvas canvas-id="myCanvas" style="border: 1px solid black; width:95%; height:660rpx; margin:150rpx auto;" bindtouchmove="move" bindtouchstart="start" bindtouchend="end">
</canvas>
// pages/mywx/mywx.js
let ctx = wx.createCanvasContext("myCanvas") //获取此画板
Page({
/**
* 页面的初始数据
*/
data: {
x:"0",
y:"0" //用于保存上一次的坐标位置
},
onLoad:function(){
},
start:function(e){
ctx.moveTo(e.touches[0].x, e.touches[0].y) //初始化坐标位置
//起始坐标
console.log(e)
this.setData({
x: e.touches[0].x,
y: e.touches[0].y //修改坐标位置
})
},
move:function(e){
ctx.moveTo(this.data.x, this.data.y)
ctx.setStrokeStyle("red")
ctx.lineTo(e.touches[0].x,e.touches[0].y) //绘制点到点的线段
ctx.stroke()
ctx.draw(true)
this.setData({
x: e.touches[0].x,
y: e.touches[0].y //重新更新起始位置
})
},
end:function(e){
//ctx.draw()
}
})
运行结果:
一步一步,慢慢走。
心跳小程序:(canvas实战)
点击两个按钮分别触发心跳和停止心跳。
// pages/mywx/mywx.js 后台处理部分
let ctx = wx.createCanvasContext("myCanvas")
Page({
/**
* 页面的初始数据
*/
data: {
id:""
},
onLoad:function(){
ctx.drawImage("../images/捕获1.png",0.93,5)
ctx.draw()
ctx.save()
},
click: function (e) {
var circleCount=0
this.data.id=setInterval(function () {
circleCount++
if(circleCount%2==0){
ctx.scale(1, 1)
ctx.drawImage("../images/捕获1.png", 0.93, 5)
}
else{
ctx.scale(0.9, 0.9)
ctx.drawImage("../images/捕获1.png", 15.5, 10)
}
ctx.draw()
if (circleCount == 1000) {
circleCount = 0;
}
} , 800)
},
stopclick:function(){
clearInterval(this.data.id)
}
})
//wxml代码部分
<canvas canvas-id="myCanvas" style="width:95%; height:650rpx; margin:50rpx auto;" >
</canvas>
<button bindtap="click">Click me!</button>
<view style="height:20rpx;"></view>
<button bindtap="stopclick">Stop!</button>