结构
index
car.png
index.js
index.json
index.wxml
index.wxss
app.js
app.json
app.wxss
index.js
app
是获取到的全局的应用程序实例- 这里虽然没用到,但是它确保了应用程序实例被正确获取了
javascript
里面的this
,通常指向当前执行上下文的对象- 这里小程序里面的
this
,指向当前页面对象 - 也就是
Page
构造函数的实例 - 另外,
Page
对象的生命周期函数中,例如onLoad
等这些函数,this
指向的是当前页面的对象
- 这里小程序里面的
this.position =
这些代码在这个函数内部定义并初始化的一些属性- 这些属性将被绑定到页面对象上,并且可以在页面的其他方法中访问和操作
- 页面的生命周期一
- 页面生命周期指的是小程序中页面对象的生命周期,页面对象是由
Page
构造函数创建的实例 - 这些页面的实例是由微信客户端来创建和管理的
- 页面生命周期函数是指在页面不同阶段执行的特定函数,用于执行页面相关的逻辑操作
- 如
onLoad
、onShow
、onReady
,onHide
,onUnload
- 页面生命周期指的是小程序中页面对象的生命周期,页面对象是由
- 页面的生命周期函数
- 比如
onLoad
它是页面加载时触发的函数之一,表示页面被加载时执行的逻辑 - 当页面被加载时,微信客户端会创建页面的实例,并执行
onLoad
生命周期函数
此时页面的数据和状态通常是未初始化的 - 然后执行
onLoad
函数,微信客户端会在页面创建完成后立即调用onLoad
函数,执行其中的逻辑代码
在这个函数中,一般进行一些初始化工作,例如获取页面参数初始化数据,发送网络请求等 onLoad
函数执行完成后,微信客户端会开始渲染页面,并等待页面渲染完成
在页面渲染过程中,微信客户端会加载页面的布局、样式和资源,并将其显示在屏幕上- 当页面渲染完成后,微信客户端会触发
onReady
生命周期函数
表示页面渲染完成,可以进行交互操作了
- 比如
- 页面的生命周期二
- 页面隐藏意味着当前页面不再处于前台显示状态,用户无法看到该页面
通常是当前页面跳转到其他页面时,当前页面会被隐藏,新页面显示在前台
当用户点击了底部的tab
切换了页面,当前页面会隐藏
当用户按下设备的home
或切到其他应用时,当前页面会被隐藏 - 页面销毁
当页面被redirectTo
或navigateBack
到上一个页面时,当前页面实例会被销毁
当小程序被关闭时,所有页面实例都会被销毁
当页面通过调用wx.reLaunch
重新加载时,当前页面被销毁,并重新创建一个新的页面实例
当页面的onUnload
生命周期函数被调用时,表示页面即将销毁
- 页面隐藏意味着当前页面不再处于前台显示状态,用户无法看到该页面
- 代码里渲染了小球和汽车,线程的问题
- 通常情况下,小程序的渲染是由主线程负责的,它们是在一个线程里渲染的
- 它们是在渲染层渲染的,而发出渲染请求的
onLoad
这儿,是在逻辑层
- 关于
onLoad
函数里面的渲染循环- 渲染循环会一直执行渲染任务,,但是它不会阻塞在
onLoad
这个函数里面,因requestAnimationFrame
是一个异步操作,他是向渲染层发出了一个绘制请求 - 一旦渲染层收到了绘制请求,它会开始执行相应的绘制工作
包括渲染页面的布局、样式和资源,执行动画效果等
- 渲染循环会一直执行渲染任务,,但是它不会阻塞在
- 关于
canvas
wx.createSelectorQuery()
创建了一个选择器查询对象
用来查询页面中的节点信息select()
指定了要查询的id
为canvas
的节点
小程序中,节点是页面中的组件或者dom
元素fields
这里通过指定参数来返回目标节点的节点本身和size
信息exec
这里表示直线选择器查询,并指定了查询完成后要调用的回调函数init
this.init.bind(this)
就是表示将this.init
函数绑定到当前页面对象上
- 下面代码中,
init
函数定义后作为参数传给了Page
去构造,为什么还需要显示绑定?- 为了确保在
init
函数内部能够正确访问到页面对象的属性和方法,所以需要显示绑定 - 因为
javascript
中,函数的执行上下文(也就是this
),是在函数被调用时确定的,而在上面的代码中,init
是作为回调函数传给Page
的构造函数的,因此当init
被调用时,它的执行上下文this
的值并不是页面对象本身,而是触发回调的事件或对象决定的 - 如果没有绑定,那么在
init
函数中访问页面对象的属性或方法可能会出错,因为this
的值不是页面对象 - 通过显示绑定,可以将
init
函数绑定到指定的执行上下文上,确保init
函数内部访问到的this
值始终指向页面对象,从而保证了函数内部的正确执行
- 为了确保在
- 再理解一下上面的点
- 我们比较清晰的一个点是
onLoad
是由微信客户端调用的,当页面创建完成后,微信客户端会调用这个回调函数 - 而到了
onLoad
函数内部时,this
却是页面对象 - 为什么还要显式去绑定
因为在javascript
里面,函数是可以脱离对象存在的,它们可以作为单独的实体被传递、存储或调用
当函数作为参数传递给其他函数时,或者以其他方式进行引用时,它们可能会丢失原始对象上下文(即函数内部的this
指向) - 在这里的代码中,虽然
init
函数被定义为Page
对象的方法,但是当它作为参数传递给exec
函数时,它实际上成为了exec
函数的一个独立的回调函数 - 而在这个独立的回调函数内部,
this
的上下文可能会丢失,它不在指向Page
对象
因此,为了保证init
内部的this
指向正确,需要显式绑定
- 我们比较清晰的一个点是
this.init.bind(this)
那么这句代码里面,前面的this
和后面this
分别是谁this.init
表示要绑定的函数是当前页面对象中的init
函数bind(this)
,这里的this
表示的是当前页面对象,指向当前页面的实例
this.init.bind()
这个bind
函数是哪里来的,返回了什么bind
是js
中的一个内置函数,它是函数对象的一个方法- 这个方法用于创建一个新的函数,新函数的
this
值被绑定到指定对象,并且在调用时无法改变 bind
方法不会立即调用原函数,而是返回一个新函数,这个新函数可以稍后被调用
- 关于
onLoad
等生命周期函数如果不定义会怎么样- 如果在
Page
中不定义页面生命周期函数(如onLoad
、onShow
、onReady
等),微信小程序客户端会默认认为你没有对应的逻辑需要执行 - 在这种情况下,微信小程序客户端会跳过这些生命周期函数的调用,不会执行任何与这些生命周期函数相关的逻辑
- 如果在
init
的参数exec
方法会在查询完成时,会调用之前那个回调函数(即通过bind
新建的回调函数)
它会将查询结果作为参数传递给这个回调函数
getSystemInfoSync
- 获取当前设备的像素比
像素比是指设备上物理像素与逻辑像素的比例,反映了设备的屏幕分辨率和设备像素密度之前的关系 - 通常情况,值为1表示标准屏幕
值大于1,表示高清屏幕。值小于1,表示低分辨率屏幕 - 根据像素比,将
canvas
的宽度和高度进行相应调整,使得canvas
的绘图区域能够适应设备的像素密度
假如像素比为2,canvas
宽度和高度分别为300px
和150px
,则设置canvas
的宽度和高度为600px
和300px
,以保证在高清屏幕上显示效果更清晰
- 获取当前设备的像素比
ctx.scale(dpr, dpr)
- 对
canvas
上下文进行缩放,将绘图环境的坐标系进行缩放,是的绘制的图形能够与设备的物理像素匹配 - 可以避免绘制的图形在高清屏幕上出现模糊或失真的情况
- 对
const renderLoop = () => {}
- 使用箭头函数的语法定义了一个函数,没有显式的参数,但是在函数体内部使用了外部作用域的变量
canvas
和ctx
,属于隐式引用 requestAnimationFrame(renderLoop)
实现了动画效果
这个方法的作用实际上是通过请求的方式,把回调函数这个参数传给渲染层存起来
然后,等渲染层真正绘制完一次,准备重新绘制的时候,它会先检查这个回调函数参数,发现有这么个回调函数,然后就调用了- 调用到
renderLoop
里面的时候,先render
渲染,并再次通过请求的方式执行这个回调函数参数
这样等下次渲染完成的时候,它又循环起来了 - 那么什么时候开始的第一次绘制,因为上面设置的回调函数参数只是告诉渲染层下次重绘之前,检查一下这个参数
- 使用箭头函数的语法定义了一个函数,没有显式的参数,但是在函数体内部使用了外部作用域的变量
- 在浏览器中,第一次绘制是发生在页面加载完成后进行的
- 当页面的
dom
结构和样式加载完成,并且所有的js
代码执行完毕后 ,浏览器会触发页面的第一次绘制 - 在微信小程序中,当页面加载完成时,微信客户端会通知渲染层开始进行第一次绘制
这个时候,渲染层会根据页面的结构和样式,以及js
代码的执行情况,开始进行页面的绘制工作 - 也就是,走到
onLoad
这里的时候,表示页面加载工作已经完成了,渲染层是可以开始绘制的
不过,由于它要给回调函数内部设置参数的机会,所以它会立刻先调用回调函数
所以正在的第一次渲染工作,渲染层是在onLoad
函数执行完毕后开始的
- 当页面的
- 关于后面的图片加载
- 先创建了一个图片对象
- 然后设置了一个回调函数,当图片加载完成的时候,会调用这个回调函数
代码中回调函数的功能就是把img
存到页面对象的_img
属性里面 - 图片的真正加载,当执行到
img.src = './car.png'
这一行的时,才会开始加载指定路径的图片资源
关于这一点
其实是图片对象内部有能力监听图片资源路径的变化,一旦发现变化了,它就会以通知或请求的方式告诉渲染层加载指定的图片资源
- 也就是说,在
onLoad
里面创建了图片对象,并设置了资源路径的图片资源,渲染层会先于页面绘制开始渲染- 但是,这两部分的渲染工作的完成所需要的时间是不确定的,所以谁先完成绘制是不确定的
- 也就是说,谁先完成渲染,谁先显示在浏览器上
- 另外,关于
Z
序的问题,谁后创建的,谁在下面,也就是说,在比较靠近的位置,onLoad
里面指定的图片,会被网页上绘制的图片盖在上面
code
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 101 |
const app = getApp() Page({ data: {}, onLoad: function () { this.position = { x: 150, y: 150, vx: 2, vy: 2 } this.x = -100 // 通过 SelectorQuery 获取 Canvas 节点 wx.createSelectorQuery() .select('#canvas') .fields({ node: true, size: true, }) .exec(this.init.bind(this)) }, init(res) { const width = res[0].width const height = res[0].height const canvas = res[0].node const ctx = canvas.getContext('2d') const dpr = wx.getSystemInfoSync().pixelRatio canvas.width = width * dpr canvas.height = height * dpr ctx.scale(dpr, dpr) const renderLoop = () => { this.render(canvas, ctx) canvas.requestAnimationFrame(renderLoop) } canvas.requestAnimationFrame(renderLoop) const img = canvas.createImage() img.onload = () => { this._img = img } img.src = './car.png' }, render(canvas, ctx) { ctx.clearRect(0, 0, 300, 300) this.drawBall(ctx) this.drawCar(ctx) }, drawBall(ctx) { const p = this.position p.x += p.vx p.y += p.vy if (p.x >= 300) { p.vx = -2 } if (p.x <= 7) { p.vx = 2 } if (p.y >= 300) { p.vy = -2 } if (p.y <= 7) { p.vy = 2 } function ball(x, y) { ctx.beginPath() ctx.arc(x, y, 5, 0, Math.PI * 2) ctx.fillStyle = '#1aad19' ctx.strokeStyle = 'rgba(1,1,1,0)' ctx.fill() ctx.stroke() } ball(p.x, 150) ball(150, p.y) ball(300 - p.x, 150) ball(150, 300 - p.y) ball(p.x, p.y) ball(300 - p.x, 300 - p.y) ball(p.x, 300 - p.y) ball(300 - p.x, p.y) }, drawCar(ctx) { if (!this._img) return if (this.x > 350) { this.x = -100 } ctx.drawImage(this._img, this.x++, 150 - 25, 100, 50) ctx.restore() } }) |
本文为原创文章,版权归Aet所有,欢迎分享本文,转载请保留出处!
你可能也喜欢
- ♥ 【Javascript】数组,可迭代对象04/04
- ♥ CMake生成器10/02
- ♥ COM组件_101/31
- ♥ Python编程基础10/31
- ♥ Linux 高性能服务器编程:网络基础编程二11/28
- ♥ Make&&Makefile03/23