微信小程序开发笔记
初始化项目文件说明
官方文档:
https://developers.weixin.qq.com/miniprogram/dev/reference/configuration/app.html
├── app.js
├── app.json
├── app.wxss
├── pages
│ │── index
│ │ ├── index.wxml
│ │ ├── index.js
│ │ ├── index.json
│ │ └── index.wxss
│ └── logs
│ ├── logs.wxml
│ └── logs.js
└── utils
App(Object object)
注册小程序。接受一个 Object
参数,其指定小程序的生命周期回调等。
App() 必须在 app.js
中调用,必须调用且只能调用一次。不然会出现无法预期的后果
// app.js
App({
onLaunch: function () {
if (!wx.cloud) {
console.error('请使用 2.2.3 或以上的基础库以使用云能力');
} else {
wx.cloud.init({
// env 参数说明:
// env 参数决定接下来小程序发起的云开发调用(wx.cloud.xxx)会默认请求到哪个云环境的资源
// 此处请填入环境 ID, 环境 ID 可打开云控制台查看
// 如不填则使用默认环境(第一个创建的环境)
// env: 'my-env-id',
traceUser: true,
});
}
this.globalData = {};
}
});
页面配置
app.json
中的部分配置,也支持对单个页面进行配置,可以在页面对应的 .json
文件来对本页面的表现进行配置。
页面中配置项在当前页面会覆盖 app.json
中相同的配置项(样式相关的配置项属于 app.json
中的 window
属性,但这里不需要额外指定 window
字段),具体的取值和含义可参考全局配置文档中说明。
// app.json
// 用于指定小程序由哪些页面组成,每一项都对应一个页面的 路径(含文件名) 信息。文件名不需要写文件后缀,框架会自动去寻找对应位置的 .json, .js, .wxml, .wxss 四个文件进行处理。
未指定 entryPagePath 时,数组的第一项代表小程序的初始页面(首页)。
小程序中新增/减少页面,都需要对 pages 数组进行修改。
{
"pages": [
"pages/index/index",
"pages/getOpenId/index",
"pages/getMiniProgramCode/index",
"pages/deployService/index",
"pages/createCollection/index",
"pages/uploadFile/index",
"pages/selectRecord/index",
"pages/updateRecord/index",
"pages/updateRecordResult/index",
"pages/updateRecordSuccess/index",
"pages/sumRecord/index",
"pages/sumRecordResult/index"
],
"window": { // 用于设置小程序的状态栏、导航条、标题、窗口背景色。
"backgroundColor": "#F6F6F6",
"backgroundTextStyle": "light",
"navigationBarBackgroundColor": "#F6F6F6",
"navigationBarTitleText": "云开发 QuickStart",
"navigationBarTextStyle": "black"
},
"sitemapLocation": "sitemap.json",
"style": "v2"
}
sitemap 配置
小程序根目录下的 sitemap.json
文件用于配置小程序及其页面是否允许被微信索引,文件内容为一个 JSON 对象,如果没有 sitemap.json
,则默认为所有页面都允许被索引
{
"desc": "关于本文件的更多信息,请参考文档 https://developers.weixin.qq.com/miniprogram/dev/framework/sitemap.html",
"rules": [{
"action": "allow",
"page": "*"
}]
}
/**app.wxss**/ 公共
.container {
display: flex;
flex-direction: column;
align-items: center;
box-sizing: border-box;
}
button {
background: initial;
}
button:focus{
outline: 0;
}
button::after{
border: none;
}
page {
background: #f6f6f6;
display: flex;
flex-direction: column;
justify-content: flex-start;
}
WXML
WXML(WeiXin Markup Language)是框架设计的一套标签语言,结合基础组件、事件系统,可以构建出页面的结构
数据绑定
<!--wxml-->
<view> {{message}} </view>
// page.js
Page({
data: {
message: 'Hello MINA!'
}
})
小程序
- data中初始化数据
- 修改数据:
this.setData()
- 修改数据的行为始终是同步的
- 数据流:
- 单项:
Model ---> View
- 单项:
Vue
- data中初始化数据
- 修改数据:
this.key = value
- 数据流:
- Vue是单项数据流: Model —> View
- Vue中实现了双向数据绑定: v-model
React
- state中初始化状态数据
- 修改数据:
this.setState()
- 自身钩子函数中(componentDidMount)异步的
- 非自身的钩子函数中(定时器的回调)同步的
- 数据流:
- 单项: Model —> View
获取用户基本信息
- 用户未授权(首次登陆)
button open-type=‘getUserInfo’
- 用户已经授权(再次登陆)
wx.getUserInfo
前后端交互
- 语法:
wx.request()
- 注意点:
- 协议必须是
https
协议 - 一个接口最多配置20个域名
- 并发限制上限是10个
- 开发过程中设置不校验合法域名: 开发工具 —> 右上角详情 ----> 本地设置 —> 不校验
- 协议必须是
本地存储
- 语法:
wx.setStorage() || wx.setStorageSync() || .....
- 注意点:
- 建议存储的数据为
json
数据 - 单个 key 允许存储的最大数据长度为 1MB,所有数据存储上限为 10MB
- 属于永久存储,同H5的localStorage一样
- 建议存储的数据为
组件属性(需要在双引号之内)
<view id="item-{{id}}"> </view>
Page({
data: {
id: 0
}
})
控制属性(需要在双引号之内)
<view wx:if="{{condition}}"> </view>
Page({
data: {
condition: true
}
})
关键字(需要在双引号之内)
true
:boolean 类型的 true,代表真值。
false
: boolean 类型的 false,代表假值。
<checkbox checked="{{false}}"> </checkbox>
特别注意:不要直接写 checked="false"
,其计算结果是一个字符串,转成 boolean 类型后代表真值
还有一些使用方法参考官方文档!!!
组合
也可以在 Mustache 内直接进行组合,构成新的对象或者数组。
数组
<view wx:for="{{[zero, 1, 2, 3, 4]}}"> {{item}} </view>
Page({
data: {
zero: 0
}
})
最终组合成数组[0, 1, 2, 3, 4]
。
对象
<template is="objectCombine" data="{{for: a, bar: b}}"></template>
Page({
data: {
a: 1,
b: 2
}
})
最终组合成的对象是 {for: 1, bar: 2}
也可以用扩展运算符 ...
来将一个对象展开
<template is="objectCombine" data="{{...obj1, ...obj2, e: 5}}"></template>
Page({
data: {
obj1: {
a: 1,
b: 2
},
obj2: {
c: 3,
d: 4
}
}
})
最终组合成的对象是 {a: 1, b: 2, c: 3, d: 4, e: 5}
。
如果对象的 key 和 value 相同,也可以间接地表达。
<template is="objectCombine" data="{{foo, bar}}"></template>
Page({
data: {
foo: 'my-foo',
bar: 'my-bar'
}
})
最终组合成的对象是 {foo: 'my-foo', bar:'my-bar'}
。
注意:上述方式可以随意组合,但是如有存在变量名相同的情况,后边的会覆盖前面,如:
<template is="objectCombine" data="{{...obj1, ...obj2, a, c: 6}}"></template>
Page({
data: {
obj1: {
a: 1,
b: 2
},
obj2: {
b: 3,
c: 4
},
a: 5
}
})
最终组合成的对象是 {a: 5, b: 3, c: 6}
。
注意: 花括号和引号之间如果有空格,将最终被解析成为字符串
<view wx:for="{{[1,2,3]}} ">
{{item}}
</view>
等同于
<view wx:for="{{[1,2,3] + ' '}}">
{{item}}
</view>
列表渲染
wx:for
在组件上使用 wx:for
控制属性绑定一个数组,即可使用数组中各项的数据重复渲染该组件。
默认数组的当前项的下标变量名默认为 index
,数组当前项的变量名默认为 item
<!--wxml-->
<view wx:for="{{array}}"> {{item}} </view>
// page.js
Page({
data: {
array: [1, 2, 3, 4, 5]
}
})
使用 wx:for-item
可以指定数组当前元素的变量名,
使用 wx:for-index
可以指定数组当前下标的变量名
block wx:for
类似 block wx:if
,也可以将 wx:for
用在<block/>
标签上,以渲染一个包含多节点的结构块。例如:
wx:key
如果列表中项目的位置会动态改变或者有新的项目添加到列表中,并且希望列表中的项目保持自己的特征和状态(如 input 中的输入内容,switch 的选中状态),需要使用 wx:key
来指定列表中项目的唯一的标识符。
wx:key
的值以两种形式提供
- 字符串,代表在 for 循环的 array 中 item 的某个 property,该 property 的值需要是列表中唯一的字符串或数字,且不能动态改变。
- 保留关键字
*this
代表在 for 循环中的 item 本身,这种表示需要 item 本身是一个唯一的字符串或者数字。
当数据改变触发渲染层重新渲染的时候,会校正带有 key 的组件,框架会确保他们被重新排序,而不是重新创建,以确保使组件保持自身的状态,并且提高列表渲染时的效率。
如不提供 wx:key
,会报一个 warning
, 如果明确知道该列表是静态,或者不必关注其顺序,可以选择忽略。
条件渲染
wx:if
在框架中,使用 wx:if=""
来判断是否需要渲染该代码块
也可以用 wx:elif
和 wx:else
来添加一个 else 块:
<!--wxml-->
<view wx:if="{{view == 'WEBVIEW'}}"> WEBVIEW </view>
<view wx:elif="{{view == 'APP'}}"> APP </view>
<view wx:else="{{view == 'MINA'}}"> MINA </view>
// page.js
Page({
data: {
view: 'MINA'
}
})
block wx:if
因为 wx:if
是一个控制属性,需要将它添加到一个标签上。如果要一次性判断多个组件标签,可以使用一个 <block/>
标签将多个组件包装起来,并在上边使用 wx:if
控制属性。
<block wx:if="{{true}}">
<view> view1 </view>
<view> view2 </view>
</block>
注意: <block/>
并不是一个组件,它仅仅是一个包装元素,不会在页面中做任何渲染,只接受控制属性。
wx:if
vs hidden
因为 wx:if
之中的模板也可能包含数据绑定,所以当 wx:if
的条件值切换时,框架有一个局部渲染的过程,因为它会确保条件块在切换时销毁或重新渲染。
同时 wx:if
也是惰性的,如果在初始渲染条件为 false
,框架什么也不做,在条件第一次变成真的时候才开始局部渲染。
相比之下,hidden
就简单的多,组件始终会被渲染,只是简单的控制显示与隐藏。
一般来说,wx:if
有更高的切换消耗而 hidden
有更高的初始渲染消耗。因此,如果需要频繁切换的情景下,用 hidden
更好,如果在运行时条件不大可能改变则 wx:if
较好。
模板
WXML提供模板(template),可以在模板中定义代码片段,然后在不同的地方调用。
定义模板
使用 name 属性,作为模板的名字。然后在<template/>
内定义代码片段,如:
<!--
index: int
msg: string
time: string
-->
<template name="msgItem">
<view>
<text> {{index}}: {{msg}} </text>
<text> Time: {{time}} </text>
</view>
</template>
使用模板
使用 is 属性,声明需要的使用的模板,然后将模板所需要的 data 传入,如:
<template is="msgItem" data="{{...item}}"/>
Page({
data: {
item: {
index: 0,
msg: 'this is a template',
time: '2016-09-15'
}
}
})
is 属性可以使用 Mustache 语法,来动态决定具体需要渲染哪个模板:
<template name="odd">
<view> odd </view>
</template>
<template name="even">
<view> even </view>
</template>
<block wx:for="{{[1, 2, 3, 4, 5]}}">
<template is="{{item % 2 == 0 ? 'even' : 'odd'}}"/>
</block>
模板的作用域
模板拥有自己的作用域,只能使用 data 传入的数据以及模板定义文件中定义的 <wxs />
模块。
引用
WXML 提供两种文件引用方式import
和include
。
import
import
可以在该文件中使用目标文件定义的template
,如:
在 item.wxml 中定义了一个叫item
的template
:
<!-- item.wxml -->
<template name="item">
<text>{{text}}</text>
</template>
在 index.wxml 中引用了 item.wxml,就可以使用item
模板:
<import src="item.wxml"/>
<template is="item" data="{{text: 'forbar'}}"/>
import 的作用域
import 有作用域的概念,即只会 import 目标文件中定义的 template,而不会 import 目标文件 import 的 template。
如:C import B,B import A,在C中可以使用B定义的template
,在B中可以使用A定义的template
,但是C不能使用A定义的template
。
<!-- A.wxml -->
<template name="A">
<text> A template </text>
</template>
<!-- B.wxml -->
<import src="a.wxml"/>
<template name="B">
<text> B template </text>
</template>
<!-- C.wxml -->
<import src="b.wxml"/>
<template is="A"/> <!-- Error! Can not use tempalte when not import A. -->
<template is="B"/>
include
include
可以将目标文件除了 <template/>
<wxs/>
外的整个代码引入,相当于是拷贝到 include
位置,如:
<!-- index.wxml -->
<include src="header.wxml"/>
<view> body </view>
<include src="footer.wxml"/>
<!-- header.wxml -->
<view> header </view>
<!-- footer.wxml -->
<view> footer </view>
路由
https://developers.weixin.qq.com/miniprogram/dev/api/route/wx.switchTab.html
wx.navigateTo(Object object)
Object object
属性 | 类型 | 默认值 | 必填 | 说明 |
---|---|---|---|---|
url | string | 是 | 需要跳转的应用内非 tabBar 的页面的路径 (代码包路径), 路径后可以带参数。参数与路径之间使用 ? 分隔,参数键与参数值用 = 相连,不同参数用 & 分隔;如 ‘path?key=value&key2=value2’ | |
events | Object | 否 | 页面间通信接口,用于监听被打开页面发送到当前页面的数据。基础库 2.7.3 开始支持。 | |
success | function | 否 | 接口调用成功的回调函数 | |
fail | function | 否 | 接口调用失败的回调函数 | |
complete | function | 否 | 接口调用结束的回调函数(调用成功、失败都会执行) |
object.success 回调函数
参数
Object res
属性 | 类型 | 说明 |
---|---|---|
eventChannel | EventChannel | 和被打开页面进行通信 |
页面生命周期
双线程,视图层和服务层
服务层生命周期:
onLoad
/**
* 生命周期函数--监听页面加载
*/
onShow
:会执行多次!
/**
* 生命周期函数--监听页面显示
*/
onReady
/**
* 生命周期函数--监听页面初次渲染完成
*/
onHide
/**
* 生命周期函数--监听页面隐藏
*/
onUnload
/**
* 生命周期函数--监听页面卸载
*/
onPullDownRefresh
/**
页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh: function () {
},
onReachBottom
/**
页面上拉触底事件的处理函数
*/
onReachBottom: function () {
},
onShareAppMessage
/**
用户点击右上角分享
*/
onShareAppMessage: function () {
}
全局配置-tabBar的使用
tabBar
如果小程序是一个多 tab 应用(客户端窗口的底部或顶部有 tab 栏可以切换页面),可以通过 tabBar 配置项指定 tab 栏的表现,以及 tab 切换时显示的对应页面。
属性 | 类型 | 必填 | 默认值 | 描述 | 最低版本 |
---|---|---|---|---|---|
color | HexColor | 是 | tab 上的文字默认颜色,仅支持十六进制颜色 | ||
selectedColor | HexColor | 是 | tab 上的文字选中时的颜色,仅支持十六进制颜色 | ||
backgroundColor | HexColor | 是 | tab 的背景色,仅支持十六进制颜色 | ||
borderStyle | string | 否 | black | tabbar 上边框的颜色, 仅支持 black / white | |
list | Array | 是 | tab 的列表,详见 list 属性说明,最少 2 个、最多 5 个 tab | ||
position | string | 否 | bottom | tabBar 的位置,仅支持 bottom / top | |
custom | boolean | 否 | false | 自定义 tabBar,见详情 | 2.5.0 |
其中 list 接受一个数组,只能配置最少 2 个、最多 5 个 tab。tab 按数组的顺序排序,每个项都是一个对象,其属性值如下:
属性 | 类型 | 必填 | 说明 |
---|---|---|---|
pagePath | string | 是 | 页面路径,必须在 pages 中先定义 |
text | string | 是 | tab 上按钮文字 |
iconPath | string | 否 | 图片路径,icon 大小限制为 40kb,建议尺寸为 81px * 81px,不支持网络图片。 当 position 为 top 时,不显示 icon。 |
selectedIconPath | string | 否 | 选中时的图片路径,icon 大小限制为 40kb,建议尺寸为 81px * 81px,不支持网络图片。 当 position 为 top 时,不显示 icon。 |
组件
https://developers.weixin.qq.com/miniprogram/dev/component/
API
https://developers.weixin.qq.com/miniprogram/dev/api/
FLY.JS
一个支持所有JavaScript运行环境的基于Promise的、支持请求转发、强大的http请求库
目前Fly.js支持的平台包括:Node.js 、微信小程序 、Weex 、React Native 、Quick App 和浏览器,这些平台的 JavaScript 运行时都是不同的。更多的平台正在持续添加中,请保持关注。
https://wendux.github.io/dist/#/doc/flyio/readme
jsonwebtoken(jwt)
https://github.com/auth0/node-jsonwebtoken
加密
解密
分包
在小程序启动时,默认会下载主包并启动主包内页面,当用户进入分包内某个页面时,客户端会把对应分包下载下来,下载完成后再进行展示。
目前小程序分包大小有以下限制:
- 整个小程序所有分包大小不超过 20M
- 单个分包/主包大小不能超过 2M
分包形式
常规分包、独立分包、分包预下载
https://developers.weixin.qq.com/miniprogram/dev/framework/subpackages.html
常规分包
开发者通过在 app.json
----subpackages
字段声明项目分包结构:
{
"pages":[
"pages/index",
"pages/logs"
],
"subpackages": [
{
"root": "packageA",
"pages": [
"pages/cat",
"pages/dog"
]
}, {
"root": "packageB",
"name": "pack2",
"pages": [
"pages/apple",
"pages/banana"
]
}
]
}
subpackages
中,每个分包的配置有以下几项:
字段 | 类型 | 说明 |
---|---|---|
root | String | 分包根目录 |
name | String | 分包别名,分包预下载时可以使用 |
pages | StringArray | 分包页面路径,相对与分包根目录 |
independent | Boolean | 分包是否是独立分包 |
打包原则
- 声明
subpackages
后,将按subpackages
配置路径进行打包,subpackages
配置路径外的目录将被打包到 app(主包) 中 - app(主包)也可以有自己的 pages(即最外层的 pages 字段)
subpackage
的根目录不能是另外一个subpackage
内的子目录tabBar
页面必须在 app(主包)内
引用原则
packageA
无法 requirepackageB
JS 文件,但可以 requireapp
、自己 package 内的 JS 文件;使用 分包异步化 时不受此条限制packageA
无法 importpackageB
的 template,但可以 requireapp
、自己 package 内的 templatepackageA
无法使用packageB
的资源,但可以使用app
、自己 package 内的资源
特点:
a) 加载小程序的时候先加载主包, 当需要访问分包的页面时候才加载分包内容
b) 分包的页面可以访问主包的文件, 数据, 图片等资源
c) 主包:
i. 主包来源: 除了分包以外的内容都会被打包到主包中
ii. 通常放置启动页/tabBar
页面
独立分包
独立分包是小程序中一种特殊类型的分包,可以独立于主包和其他分包运行。从独立分包中页面进入小程序时,不需要下载主包。当用户进入普通分包或主包内页面时,主包才会被下载。
开发者可以按需将某些具有一定功能独立性的页面配置到独立分包中。当小程序从普通的分包页面启动时,需要首先下载主包;而独立分包不依赖主包即可运行,可以很大程度上提升分包页面的启动速度。
一个小程序中可以有多个独立分包
开发者通过在app.json
的subpackages
字段中对应的分包配置项中定义independent
字段声明对应分包为独立分包。
{
"pages": [
"pages/index",
"pages/logs"
],
"subpackages": [
{
"root": "moduleA",
"pages": [
"pages/rabbit",
"pages/squirrel"
]
}, {
"root": "moduleB",
"pages": [
"pages/pear",
"pages/pineapple"
],
"independent": true
}
]
}
限制
独立分包属于分包的一种。普通分包的所有限制都对独立分包有效。独立分包中插件、自定义组件的处理方式同普通分包。
此外,使用独立分包时要注意:
- 独立分包中不能依赖主包和其他分包中的内容,包括 js 文件、template、wxss、自定义组件、插件等(使用 分包异步化 时 js 文件、自定义组件、插件不受此条限制)
- 主包中的
app.wxss
对独立分包无效,应避免在独立分包页面中使用app.wxss
中的样式; App
只能在主包内定义,独立分包中不能定义App
,会造成无法预期的行为;- 独立分包中暂时不支持使用插件。
使用场景
a) 通常某些页面和当前小程序的其他页面关联不大的时候可进行独立分包
b) 如: 临时加的广告页 || 活动页
分包预下载
开发者可以通过配置,在进入小程序某个页面时,由框架自动预下载可能需要的分包,提升进入后续分包页面时的启动速度。对于独立分包,也可以预下载主包。
分包预下载目前只支持通过配置方式使用,暂不支持通过调用API完成。
配置方法
预下载分包行为在进入某个页面时触发,通过在 app.json
增加 preloadRule
配置来控制。
{
"pages": ["pages/index"],
"subpackages": [
{
"root": "important",
"pages": ["index"],
},
{
"root": "sub1",
"pages": ["index"],
},
{
"name": "hello",
"root": "path/to",
"pages": ["index"]
},
{
"root": "sub3",
"pages": ["index"]
},
{
"root": "indep",
"pages": ["index"],
"independent": true
}
],
"preloadRule": {
"pages/index": {
"network": "all",
"packages": ["important"]
},
"sub1/index": {
"packages": ["hello", "sub3"]
},
"sub3/index": {
"packages": ["path/to"]
},
"indep/index": {
"packages": ["__APP__"]
}
}
}
preloadRule
中,key
是页面路径,value
是进入此页面的预下载配置,每个配置有以下几项:
字段 | 类型 | 必填 | 默认值 | 说明 |
---|---|---|---|---|
packages | StringArray | 是 | 无 | 进入页面后预下载分包的 root 或 name 。__APP__ 表示主包。 |
network | String | 否 | wifi | 在指定网络下预下载,可选值为: all : 不限网络 wifi : 仅wifi下预下载 |
限制
同一个分包中的页面享有共同的预下载大小限额 2M,限额会在工具中打包时校验。
如,页面 A 和 B 都在同一个分包中,A 中预下载总大小 0.5M 的分包,B中最多只能预下载总大小 1.5M 的分包。
分包异步化
在小程序中,不同的分包对应不同的下载单元;因此,除了非独立分包可以依赖主包外,分包之间不能互相使用自定义组件或进行 require
。「分包异步化」特性将允许通过一些配置和新的接口,使部分跨分包的内容可以等待下载后异步使用,从而一定程度上解决这个限制
跨分包自定义组件引用
一个分包使用其他分包的自定义组件时,由于其他分包还未下载或注入,其他分包的组件处于不可用的状态。通过为其他分包的自定义组件设置 占位组件,我们可以先渲染占位组件作为替代,在分包下载完成后再进行替换。例如:
// subPackageA/pages/index.json
{
"usingComponents": {
"button": "../../commonPackage/components/button",
"list": "../../subPackageB/components/full-list",
"simple-list": "../components/simple-list"
},
"componentPlaceholder": {
"button": "view",
"list": "simple-list"
}
}
在这个配置中,button
和 list
两个自定义组件是跨分包引用组件,其中 button
在渲染时会使用内置组件 view
作为替代,list
会使用当前分包内的自定义组件 simple-list
作为替代进行渲染;在这两个分包下载完成后,占位组件就会被替换为对应的跨分包组件。
跨分包 JS 代码引用
一个分包中的代码引用其它分包的代码时,为了不让下载阻塞代码运行,我们需要异步获取引用的结果。如:
// subPackageA/index.js
// 使用回调函数风格的调用
require('../subPackageB/utils.js', utils => {
console.log(utils.whoami) // Wechat MiniProgram
})
// 或者使用 Promise 风格的调用
require.async('../commonPackage/index.js').then(pkg => {
pkg.getPackageName() // 'common'
})
在其它分包中的插件也可以通过类似的方法调用:
// 使用回调函数风格的调用
requirePlugin('live-player-plugin', livePlayer => {
console.log(livePlayer.getPluginVersion())
})
// 或者使用 Promise 风格的调用
requirePlugin.async('live-player-plugin').then(livePlayer => {
console.log(livePlayer.getPluginVersion())
})
扩展内容
1. 事件流的三个阶段
- 捕获: 从外向内
- 执行目标阶段
- 冒泡: 从内向外
2. 事件委托
- 什么是事件委托
- 将子元素的事件委托(绑定)给父元素
- 事件委托的好处
- 减少绑定的次数
- 后期新添加的元素也可以享用之前委托的事件
- 事件委托的原理
- 冒泡
- 触发事件的是谁
- 子元素
- 如何找到触发事件的对象
- event.target
- currentTarget VS target
- currentTarget要求绑定事件的元素一定是触发事件的元素
- target绑定事件的元素不一定是触发事件的元素
3. 定义事件相关
- 分类
- 标准DOM事件
- 自定义事件
- 标准DOM事件
- 举例: click,input。。。
- 事件名固定的,事件由浏览器触发
- 自定义事件
- 绑定事件
- 事件名
- 事件的回调
- 订阅方:
PubSub.subscribe
(事件名,事件的回调) - 订阅方式接受数据的一方
- 触发事件
- 事件名
- 提供事件参数对象, 等同于原生事件的event对象
- 发布方:
PubSub.publish
(事件名,提供的数据) - 发布方是提供数据的一方
- 绑定事件