面试常被问到的小程序问题

7,338 阅读8分钟

本文章同步发布在我的博客:xueshiming.cn

Tips: 先来一些干货

wx:key 不仅仅是唯一标识

列表数据发生改变重新出发页面渲染的时候,列表中的项目可以保持自身状态 比如在input组件里,输入了内容之后 在页面渲染之后,不希望input 内容发生改变,需要用此属性 这个属性,在页面重新渲染的时候,确保带有 key 的组件 会重新排序,而不是重新渲染,从而提高页面渲染性能的效率

另外:如不提供 wx:key,会报一个 warning, 如果明确知道该列表是静态,或者不必关注其顺序,可以选择忽略。

Block是一个包装元素,不是组件,渲染之后页面看不出来
wx:if 和hidden 区别

wx:if在切换时有局部渲染的过程,从而保证条件块渲染时,可以销毁并重新渲染,有更高的切换消耗 hidden始终渲染。可以控制视图上的显示和隐藏,有更高的初始化渲染消耗, 所以元素频繁切换的话,使用hidden

wxml支持文件引用

import: 只能引用我们定义模板文件的模板内容块

作用域的概念:只能引用目标文件定义的template模板,如果目标文件内嵌套了其他模板,是不会被引用的,避免了引用模板死循环的问题

include : 把目标 文件内除了模板代码块外的 所有代码都引入,相当于拷贝到了include位置这里

Wxss和css对比

尺寸单位rpx

先了解几个概念:

  • 设备像素: 设备能控制的显示的最小物理单位 这个最小物理单位是屏幕上一个个点,点是固定不变的
  • CSS像素:外部编程的概念,css代码中使用的逻辑像素
  • PPI/DPI:每英寸拥有的像素数目

  • DPR:手机的某一方向上设备像素和css像素之比

虽然wxss支持rem,但是我们知道rem是根据html根元素的fontSize大小来适配的, wxss不能直接操作html的样式属性,所以rem适配方案就失效了。 rpx应运而生,规定屏幕宽度为750rpx,从而我们可以根据屏幕宽度来自适应,rpxrem实现方式是相似的,而且rpx最终转换为rem

样式导入

  • 外联样式引入:@import ‘./ss.wxss’

  • 内连样式引入:style 一般用来写动态的样式

选择器

优先级

一般想要修改他人插件样式的时候使用!import


小程序运行机制

小程序两种启动方式:冷启动,热启动

  • 热启动:假如用户已经打开了某个小程序,在一定时间内再次打开小程序的话,这个时候我们就不再需要重新启动了,这需要把我们的后台打开的小程序切换到前台来使用。
  • 冷启动:用户首次打开小程序或被微信主动销毁再次打开的情况,此时小程序需要重新加载启动。

小程序什么时候会主动销毁?

  1. 小程序在进入后台之后,客户端会帮我们在一定时间内维持我们的一个状态,超过五分钟后,会被微信主动销毁
  2. 当我们在短时间内连续两次收到系统告警的时候,微信就会主动销毁,短时间间隔是5s

小程序更新机制:

小程序在冷启动的时候遇到版本更新,小程序会异步加载,帮我们下载最新版本的代码包,并同时使用微信本地版本的代码包启动,也就是说最新的代码包,将在小程序下次启动才去加载。如果偏要使用最新版本的代码包,我们可以使用api来处理

wx.getUpdateManager

const updateManager = wx.getUpdateManager()

updateManager.onCheckForUpdate(function (res) {
  // 请求完新版本信息的回调
  console.log(res.hasUpdate)
})

updateManager.onUpdateReady(function () {
  wx.showModal({
    title: '更新提示',
    content: '新版本已经准备好,是否重启应用?',
    success(res) {
      if (res.confirm) {
        // 新的版本已经下载好,调用 applyUpdate 应用新版本并重启
        updateManager.applyUpdate()
      }
    }
  })
})

updateManager.onUpdateFailed(function () {
  // 新版本下载失败
})

小程序加载机制:

小程序的启动流程图里面:

左侧的部分是在启动的时候,微信客户端里面的视图层和逻辑层一些交互逻辑以及数据缓存的存取操作,在小程序启动的时候,会向cdn请求最新代码包,第一次启动必须等到代码包下载完毕,注入到webView容器内执行之后,才能看到小程序页面,所以在网络不好的情况下,我们会感觉到页面打开比较慢,客户端会帮我们把代码包缓存到本地,当我们下一次启动的时候,我们会从 cdn 请求是否有最新版本的代码包。


小程序应用和页面的生命周期:

小程序应用生命周期:onLaunch,onShow,onHide,onError

首次进入小程序,从 cdn 或者小程序本地拿到代码包注入到运行环境, 微信客户端会给我们逻辑层app.jsapp实例来派发onLaunch事件, 在逻辑层,app.jsapp 构造器的参数里面的onLaunch方法就会被调用。 当用户使用home件或者点击右上角小程序关闭按钮,来关闭小程序时,小程序是没有被直接销毁的,这时app构造器的参数里面的onHiede方法就会被调用,当我们再次打开小程序时,微信唤起小程序,onShow方法就会被调用, 当小程序脚本发现错误时,或api调用失败时,会调用onError

小程序页面的生命周期:onLoad,onShow,onReady,onHide,onUnload,

页面未被销毁之前,onLoad只会调用一次, 页面显示之后,会调用page实例里面的onShow 当页面初次渲染之后,onReady就会被调用,页面未被销毁之前,只会调用一次 onReady触发之后,逻辑层和视图层进行交互, 当我们在当前页面打开新的页面之后,当前页面会触发onHide, 如果关闭当前页,会触发onUnload

负责页面视图的view线程和处理数据的服务以及服务的服务线程,AppService, 协同完成生命周期周期调用


小程序事件模型

1. 事件捕获阶段

绑定的事件从最外层节点向下传递到目标节点元素,依次检查,所经过的节点是否绑定了同一事件类型的监听回调函数,如果有则执行对应的事件回调函数

2. 事件处理阶段

事件在到达目标节点之后,会触发目标节点所绑定的监听回调函数

3. 事件冒泡阶段

事件从目标节点,向上冒泡到最外层节点,依次检查经过的节点是否绑定了,同样事件类型的监听回调函数,如果有,会执行这个回调函数

target属性: 触发事件的当前组件 currentTarget属性: 触发事件的根源组件

eg: 如果有外层view还有个里层view嵌套,都通过bind绑定了点击事件,target为外层view组件的事件对象,currentTarget为底层view组件的事件对象

  • type 触发事件的触发类型
  • timestamp 触发事件的时间戳
  • target 触发事件的根源组件,包括触发事件根源组件的id自定义属性的集合
  • currenTarget 事件绑定额当前组件 ,包括当前组件的id,类型,data自定义属性的集合
  • touches 是一个数组,每一个元素都是一个touch对象 ,标识当前停留在屏幕上的触摸点和信息
  • changedTouches 是一个数据,标识有变化的 触摸点,即当前触摸点从有到无或从无到有的变化
  • detail 标识各个事件带有的数据,点击事件: ‘触摸点距离文档左上角的距离’ 媒体事件,触发事件的时候播放状态,以及时间戳

小程序运行环境:

在不同环境下的javascript脚本运行环境是不同的,微信小程序运行在三端:iOS(iPhone/iPad)Android 和 用于调试的开发者工具。

三端的脚本执行环境以及用于渲染非原生组件的环境是各不相同的:

  • iOS 上,小程序逻辑层的 javascript 代码运行在 JavaScriptCore 中,视图层是由 WKWebView 来渲染的,环境有 iOS8iOS9iOS10

  • Android 上,

    • 旧版本,小程序逻辑层的 javascript 代码运行中 X5 JSCore 中,视图层是由 X5 基于 Mobile Chrome 57 内核来渲染的
    • 新版本,小程序逻辑层的 javascript 代码运行在 V8 中,视图层是由自研 XWeb 引擎基于 Mobile Chrome 67 内核来渲染的;
  • 在 开发工具上,小程序逻辑层的 javascript 代码是运行在 NW.js 中,视图层是由 Chromium 60 Webview 来渲染的。

结语:我们在开发小程序的同时,也别忘记去理解一些原理性和细节性问题,因为这是提升的关键。to be an engineer,not a coder.