小程序的架构模型
◼ 谁是小程序的宿主环境呢?微信客户端
宿主环境为了执行小程序的各种文件:wxml文件、wxss文件、js文件
◼ 当小程序基于 WebView 环境下时, WebView 的 JS 逻辑、 DOM 树创建、 CSS 解析、样式计算、 Layout 、 Paint (Composite) 都发生
在同一线程,在 WebView 上执行过多的 JS 逻辑可能阻塞渲染,导致界面卡顿。
◼ 以此为前提,小程序同时考虑了性能与安全,采用了目前称为「双线程模型」的架构。
小程序的架构模型
◼ 双线程模型:
WXML模块和WXSS样式运行于 渲染层,渲染层使用
WebView线程渲染(一个程序有多个页面,会使用多个 WebView的线程)。
JS脚本(app.js/home.js等)运行于 逻辑层,逻辑层使 用JsCore运行JS脚本。
这两个线程都会经由微信客户端(Native)进行中转交互
小程序的配置文件
◼ 小程序的很多 开发需求 被规定在了 配置文件 中。
◼ 为什么这样做呢?
这样做可以更有利于我们的开发效率;
并且可以保证开发出来的小程序的某些风格是比较一致的;
比如导航栏 – 顶部TabBar,以及页面路由等等。
◼ 常见的配置文件有哪些呢?
project.config.json:项目配置文件, 比如项目名称、appid等;
➢ developers.weixin.qq.com/miniprogram…
sitemap.json:小程序搜索相关的;
➢ developers.weixin.qq.com/miniprogram…
app.json:全局配置;
page.json:页面配置;
全局app配置文件
◼ 全局配置比较多, 我们这里将几个比较重要的. 完整的查看官方文档.
developers.weixin.qq.com/miniprogram…
◼ pages: 页面路径列表
用于指定小程序由哪些页面组成,每一项都对应一个页面的 路径(含文件名) 信息。
小程序中所有的页面都是必须在pages中进行注册的。
◼ window: 全局的默认窗口展示
用户指定窗口如何展示, 其中还包含了很多其他的属性
◼ tabBar: 顶部tab栏的展示
具体属性稍后我们进行演示
AppService线程,渲染线程,Raster教程
Flutter->React native
配置案例实现
◼ 我们来做如下的效果:
页面page配置文件
◼ 每一个小程序页面也可以使用 .json 文件来对本页面的窗口表现进行配置。
页面中配置项在当前页面会覆盖 app.json 的 window 中相同的配置项。
developers.weixin.qq.com/miniprogram…
sitemap.js
{
"desc": "关于本文件的更多信息,请参考文档 https://developers.weixin.qq.com/miniprogram/dev/framework/sitemap.html",
"rules": [{
"action": "allow",
"page": "*"
}]
}
favor.json
{
"usingComponents": {},
"enablePullDownRefresh": true
}
app.json
{
"pages": [
"pages/index/index",
"pages/favor/favor",
"pages/order/order",
"pages/profile/profile",
"pages/01test/index"
],
"window": {
"backgroundTextStyle": "dark",
"navigationBarBackgroundColor": "#ff8189",
"navigationBarTitleText": "弘源旅途",
"navigationBarTextStyle": "white"
},
"tabBar": {
"selectedColor": "#ff8189",
"list": [
{
"text": "首页",
"pagePath": "pages/index/index",
"iconPath": "assets/tabbar/home.png",
"selectedIconPath": "assets/tabbar/home_active.png"
},
{
"text": "收藏",
"pagePath": "pages/favor/favor",
"iconPath": "assets/tabbar/category.png",
"selectedIconPath": "assets/tabbar/category_active.png"
},
{
"text": "订单",
"pagePath": "pages/order/order",
"iconPath": "assets/tabbar/cart.png",
"selectedIconPath": "assets/tabbar/cart_active.png"
},
{
"text": "我的",
"pagePath": "pages/profile/profile",
"iconPath": "assets/tabbar/profile.png",
"selectedIconPath": "assets/tabbar/profile_active.png"
}
]
},
"style": "v2",
"sitemapLocation": "sitemap.json"
}
profile针对页面进行配置的
<!--pages/profile/profile.wxml-->
<text>pages/profile/profile.wxml</text>
<view class="list">
<block wx:for="{{listCount}}" wx:key="*this">
<view>列表数据:{{ item }}</view>
</block>
</view>
profile.json
{
"usingComponents": {},
"navigationBarTitleText": "个人信息",
"navigationBarBackgroundColor": "#f00",
"enablePullDownRefresh": true,下拉刷新
"onReachBottomDistance": 100
}
// pages/profile/profile.js
Page({
data: {
avatarURL: "",
listCount: 30
},
// 监听下拉刷新
onPullDownRefresh() {
console.log("用户进行下拉刷新~");
// 模拟网络请求: 定时器
setTimeout(() => {
this.setData({ listCount: 30 })
// API: 停止下拉刷新
wx.stopPullDownRefresh({
success: (res) => {
console.log("成功停止了下拉刷新", res);
},
fail: (err) => {
console.log("失败停止了下拉刷新", err);
}
})
}, 1000)
},
// 监听页面滚动到底部
onReachBottom() {
console.log("onReachBottom");
this.setData({
listCount: this.data.listCount + 30
})
}
})
小程序的介绍,
各个平台的小程序介绍
注册小程序 – App函数
◼ 每个小程序都需要在 app.js 中调用 App 函数 注册小程序示例
在注册时, 可以绑定对应的生命周期函数;
在生命周期函数中, 执行对应的代码;
developers.weixin.qq.com/miniprogram…
◼ 我们来思考:注册App时,我们一般会做什么呢?
1. 判断小程序的进入场景
2. 监听生命周期函数,在生命周期中执行对应的业务逻辑,比如在某个生命周期函数中进行登录操作或者请求网络数据;
3. 因为App()实例只有一个,并且是全局共享的(单例对象),所以我们可以将一些共享数据放在这里;
App函数的参数
// app.js
App({
// 作用二: 共享数据
// 数据不是响应式, 这里共享的数据通常是一些固定的数据
globalData: {
token: "",
userInfo: {}
},
onLaunch(options) {
// 0.从本地获取token/userInfo
const token = wx.getStorageSync("token")
const userInfo = wx.getStorageSync("userInfo")
// 1.进行登录操作(判断逻辑)
if (!token || !userInfo) {
// 将登录成功的数据, 保存到storage
console.log("登录操作");
wx.setStorageSync("token", "kobetoken")
wx.setStorageSync("userInfo", { nickname: "kobe", level: 100 })
}
// 2.将获取到数据保存到globalData中
this.globalData.token = token
this.globalData.userInfo = userInfo
// 3.发送网络请求, 优先请求一些必要的数据
// wx.request({ url: 'url'})
},
onShow(options) {
// 作用一: 判断小程序的进入场景
console.log("onShow:", options);
},
onHide() {
console.log("onHide");
}
})
// 页面中
// 1.初体验: favor
// 2.页面配置/下拉刷新/上拉加载: profile
// 3.在页面中, 使用app中的数据: order
作用一:判断打开场景
◼ 小程序的打开场景较多:
常见的打开场景:群聊会话中打开、小程序列表中打开、微信扫一扫打开、另一个小程序打开
developers.weixin.qq.com/miniprogram…
◼ 如何确定场景?
在onLaunch和onShow生命周期回调函数中,会有options参数,其中有scene值;
作用二:定义全局App的数据
◼ 作用二:可以在Object中定义全局App的数据
◼ 定义的数据可以在其他任何页面中访问
// pages/order/order.js
Page({
data: {
userInfo: {}
},
onLoad() {
// 获取共享的数据: App实例中数据
// 1.获取app实例对象
const app = getApp()
// 2.从app实例对象获取数据
const token = app.globalData.token
const userInfo = app.globalData.userInfo
console.log(token, userInfo);
// 3.拿到token目的发送网络请求
// 4.将数据展示到界面上面
// this.data.userInfo = userInfo
this.setData({ userInfo })
console.log(this.data.userInfo);
}
})
// pages/order/order.js
Page({
data: {
userInfo: {}
},
onLoad() {
// 获取共享的数据: App实例中数据
// 1.获取app实例对象
const app = getApp()
// 2.从app实例对象获取数据
const token = app.globalData.token
const userInfo = app.globalData.userInfo
console.log(token, userInfo);
// 3.拿到token目的发送网络请求
// 4.将数据展示到界面上面
// this.data.userInfo = userInfo
this.setData({ userInfo })
console.log(this.data.userInfo);
}
})
作用三 – 生命周期函数
◼ 作用二:在生命周期函数中,完成应用程序启动后的初始化操作
比如登录操作(这个后续会详细讲解);
比如读取本地数据(类似于token,然后保存在全局方便使用)
比如请求整个应用程序需要的数据;
onLaunch
1.进行用户登录
2.保存的护具token/userinfo
3.发送一些必要的网络请求
注册页面 – Page函数
◼ 小程序中的每个页面, 都有一个对应的js文件, 其中调用 Page函数 注册页面示例
在注册时, 可以绑定初始化数据、生命周期回调、事件处理函数等。
developers.weixin.qq.com/miniprogram…
◼ 我们来思考:注册一个Page页面时,我们一般需要做什么呢?
1.在生命周期函数中发送网络请求,从服务器获取数据;
2.初始化一些数据,以方便被wxml引用展示;
3.监听wxml中的事件,绑定对应的事件函数;
4.其他一些监听(比如页面滚动、上拉刷新、下拉加载更多等);
注册Page时做什么呢?
Page页面的生命周期
// pages/01_初体验/index.js
Page({
data: {
banners: [],
recommends: [],
// 2.作用二: 定义本地固定的数据
counter: 100,
btns: ["red", "blue", "green", "orange"]
},
// 1.作用一: 发送网络请求, 请求数据
onLoad() {
console.log("onLoad");
// 发送网络请求
wx.request({
url: "http://123.207.32.32:8000/home/multidata",
success: (res) => {
const data = res.data.data
const banners = data.banner.list
const recommends = data.recommend.list
this.setData({ banners, recommends })
}
})
},
// 3.绑定wxml中产生事件后的回调函数
onBtn1Click() {
console.log("onBtn1Click");
},
onBtnClick(event) {
console.log("btn click:", event.target.dataset.color);
},
// 4.绑定下拉刷新/达到底部/页面滚动
onPullDownRefresh() {
console.log("onPullDownRefresh");
},
onReachBottom() {
console.log("onReachBottom");
},
onPageScroll(event) {
console.log("onPageScroll:", event);
},
// 生命周期函数:
onShow() {
console.log("onShow");
},
onReady() {
console.log("onReady");
},
onHide() {
console.log("onHide");
},
onUnload() {
console.log("onUnload");
}
})
index.wxml
<!--pages/01_初体验/index.wxml-->
<view class="banner">
<swiper circular autoplay indicator-dots="{{true}}">
<block wx:for="{{banners}}" wx:key="acm">
<swiper-item>
<!-- image组件默认宽度和高度: 320x240 -->
<image mode="widthFix" src="{{item.image}}"></image>
</swiper-item>
</block>
</swiper>
</view>
<view class="counter">
<view>当前计数: {{ counter }}</view>
</view>
<view class="buttons">
<button bindtap="onBtn1Click">按钮1</button>
<block wx:for="{{btns}}" wx:key="*this">
<button
class="btn"
style="background: {{item}};"
bindtap="onBtnClick"
data-color="{{item}}"
>
{{ item }}
</button>
</block>
</view>
<view class="list">
<block wx:for="{{30}}" wx:key="*this">
<view>列表数据:{{ item }}</view>
</block>
</view>
developers.weixin.qq.com/miniprogram…
上拉和下拉的监听
◼ 监听页面的下拉刷新和上拉加载更多:
步骤一:配置页面的json文件;
步骤二:代码中进行监听;
二. 注册App实例的函数,以及注册该实例时,通常可能进行哪些操作?
- 判断小程序的进入场景
-
- 在生命周期函数中有一个参数options options中的scene记录着从什么场景进入的小程序
- 场景列表地址 developers.weixin.qq.com/miniprogram…
- 监听生命周期函数
-
- 在对应的生命周期函数中执行刚开始的业务逻辑 比如登录操作或者初始化时请求全局的网络数据
- App()实例只有一个 所以可以创建一个globalData的对象 存放全局的共享数据
三. 注册Page实例的函数,以及注册该实例时,通常可能进行哪些操作?
- 在生命周期函数中发送网络请求
- 初始化数据 方便页面展示
- 监听wxml中的事件
- 进行页面滚动 下拉加载 上拉刷新的事件监听
四. 根据文档,自己查找3个组件进行练习(比如Swiper等组件)
五. 什么是rpx?rpx如何进行的屏幕适配?
rpx: responsive pixel : 可以根据屏幕宽度进行自适应 规定屏幕宽度为750rpx
- 建议开发中将 iPhone6 作为视觉稿的标准
-
- iPhone6 屏幕宽度为375px 750物理像素 所以 750rpx = 375px = 750物理像素
- 1rpx = 0.5px
- 因此如果想定义一个100px宽度的view 则需要设置width为 200rpx
下面的预习
六. wx:if和hidden属性有什么区别?开发中如何选择?
wx:if是 组件是否渲染
hidden指的是hidden属性是否添加
开发中选择:
- 如果操作很频繁 则使用hidden
- 如果不频繁 则使用 wx:if
七. wx:for为什么需要绑定key?绑定key的方式有哪些?
为什么要绑定key:
- 当我们希望处于同一层的VNode 进行插入 删除 新增 节点时 可以更好的进行节点的复用 就需要key属性来判断
绑定key的方式有哪些:
- 字符串: 表示 for循环array中item的某个属性(property) 该property是列表中的唯一的字符串或数字
- 保留关键字 *this 表示item本身 此时item本身是唯一的字符串或数字
八. WXS的作用是什么?如何使用?
作用:
- 小程序的一套脚本语言 和JavaScript基本一致
- 为了在wxml中调用函数来处理对应的数据
如何使用:
- 写在 wxs标签中
- 写在 .wxs结尾的文件中 以cjs的方式导出 以cjs的方式在wxml文件中引入 进行使用