# 微信
**Repository Path**: ouzai-zai/wechat
## Basic Information
- **Project Name**: 微信
- **Description**: No description available
- **Primary Language**: Unknown
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2022-01-04
- **Last Updated**: 2022-01-05
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# 微信小程序
[TOC]
**官方文档**https://developers.weixin.qq.com/miniprogram/dev/framework/
## 一、小程序与普通网页开发的区别
- **运行环境不同**
- 网页运行在**浏览器**环境中,小程序运行在**微信**环境中
- API不同
- 由于运行环境不同,所以小程序中无法调用DOM,BOM的API。但是,小程序中可以调用微信环境提供的各种API,如地理定位,扫码,支付
- 开发模式不同
- 网页开发模式:浏览器 + 代码编辑器
- 小程序有自己的一套标准开发模式:①申请小程序开发账号。②安装小程序开发者工具。③创建和配置小程序项目
## 二、注册小程序账号
> 进入网址:`https://mp.weixin.qq.com/`
点击右上角立即注册
点击小程序注册
填写信息即可注册完成
## 三、找到小程序ID
登录完跳转到小程序后台管理界面,找到左边的导航栏,开发管理选项,点击开发设置则能看见开发ID
## 四、安装开发者工具
### 4.1、了解微信开发者工具
微信开发者工具是官方推荐使用的小程序开发工具,它提供的主要功能如下
- 快速创建小程序项目
- 代码的查看和编辑
- 对小程序功能进行调试
- 小程序的预览和发布
### 4.2、下载
`https://developers.weixin.qq.com/miniprogram/dev/devtools/stable.html`
### 4.3、创建项目

## 五、小程序代码构成
### 5.1、项目结构
> **基本项目结构**

1. page 用来存放所有小程序的页面
2. utils 用来存放工具性质的模块
3. app.js 小程序项目的入口文件
4. app.json 小程序项目的全局配置文件
5. app.wxss 小程序项目的全局样式文件
6. project.config.json 项目的配置文件
7. sitemap.json 用来配置小程序及页面是否允许被微信索引
> **页面组成部分**
小程序官方建议吧所有小程序页面放在page目录下,以单独的文件夹存在

每个页面由4个基本文件组成,分别是
1. .js 文件(页面的脚本文件,存放页面的数据,事件处理函数等)
2. .json 文件(当前页码的配置文件,配置窗口的外观,表现等)
3. .wxml 文件(页面的模板结构文件)
4. .wxss 文件(当前页面的样式表文件
### 5.2、JSON 配置文件
> JSON 配置文件的作用
JSON 是一种数据格式,实际开发中,JSON 总是以配置文件的形式出现,通过不同的.json配置文件,可以对小程序项目进行不同级别的配置
- app.json
- project.config.json
- sitemap.json
- 每个页面文件夹中也有 .json 配置文件
> app.json 文件
app.json 是小程序的全局配置,包括了**页面路径**、**窗口外观**、**界面表现**,**底部tab**等

- page:用来记录当前小程序的所有页面的路径
- window:全局定义小程序所有页面的背景颜色,文字颜色
- style:定义小程序组件所使用的样式版本
- sitemapLocation:用来指明sitemap.json 的位置
> project.config.json 文件
project.config.json 是配置项文件,用来记录我们对小程序开发工具所做的个性化配置
- setting 中保存了编译相关的配置
- projectname 中保存的是项目名称
- appid 中保存的是小程序的账号ID
> sitemap.json 文件
微信现已开放小程序内搜索,效果类似于 PC 网页的 SEO,此文件用来配置小程序页面是否允许被微信索引。
把文件中字段action 的值改为 disallow 则不会被索引
当开发者允许微信索引时,微信会通过爬虫的形式,为小程序的页面内容建立索引。当用户搜索关键字和页面的索引匹配成功时,小程序的页面将可以展示在搜索结果中。
注意:sitemap 的索引提示是默认开启的,关闭需要在project.config.json 的 setting 中配置字段 checkSiteMap 为 false
> 页面中的 .json 文件
小程序中的每一个页面,可以使用 .json 文件来对本页面的窗口外观进行配置,页面中的配置会覆盖app.json 的 window 中相同的配置项

> 新建小程序页面
只需在 app.json -> page 字段中新增页面存放路径,开发工具会直接生成

> 修改项目首页
将 pages 对象中需要设置为首页的页面的路径放在第一位
### 5.3、WXML 模板
- 标签名不同
- HTML(div,span,img,a)
- WXML(view,text,image,navigator)
- 属性节点不同
- `超链接`
- ``
- 提供了类似于 vue 中的模板语法
- 数据绑定
- 列表渲染
- 条件渲染
### 5.4、WXSS 样式
> 什么是 WXSS
WXSS是一套样式语言,用于描述WXML的组件样式,类似于css
> WXSS 和 CSS 区别
1. 新增了 rpx 尺寸单位
1. css 中需要手动进行单位换算。
2. WXSS 在底层支持新的尺寸单位 rpx,会自动换算
2. 提供了全局样式和局部样式
1. 根目录中的 app.wxss 会作用于所有小程序页面
2. 局部页面的 .wxss 样式仅对当前页面生效
3. WXSS 仅支持部分 css 选择器
1. .class 和 #id
2. element
3. 并集选择器,后代选择器
4. 伪类选择器
### 5.5、JS 逻辑交互
> .js 文件分类
1. app.js
1. 是整个小程序项目的入口文件,通过调用App()函数启动整个项目
2. 页面的 .js 文件
1. 是页面的入口文件,通过调用Page()函数来创建并运行页面
3. 普通的 .js 文件
1. 是普通的功能模块文件,用来封装公共的函数或属性
## 六、小程序的宿主环境
### 6.1、宿主环境简介
> 什么是宿主环境
宿主环境指的是程序运行所**必须的依赖环境**
**Android** 和 **iOS** 是两个不同的宿主环境,安卓版的微信 App 是不能在 iOS下运行的,所以Android 是安卓软件的宿主环境,**脱离了宿主环境的软件是没有任何意义的**
> 小程序的宿主环境
手机微信就是小程序的宿主环境

> 小程序宿主环境包括的内容
1. 通信模型
2. 运行机制
3. 组件
4. API
### 6.2、通信模型
> 通信的主体
小程序中通信的主体是渲染层和逻辑层
1. WXML 模板和 WXSS 样式工作在渲染层
2. JS 脚本工作在逻辑层
### 6.3、运行机制
> 小程序启动的过程
1. 把小程序的代码包下载到本地
2. 解析 app.json 全局配置文件
3. 执行 app.js 小程序入口文件,调用 App() 创建小程序实例
4. 渲染小程序首页
5. 小程序启动完成
> 页面渲染的过程
1. 加载解析页面的 .json 配置文件
2. 加载页面的 .wxml 模板和 .wxss 样式
3. 执行页面的 .js 文件,调用Page() 创建页面实例
4. 页面渲染完成
### 6.4、组件
> 小程序中组件的分类
小程序中的组件是由宿主环境提供,官方把小程序分为九大类(加粗常用)
1. **视图容器**
2. **基础内容**
3. **表单组件**
4. **导航组件**
5. **媒体组件**
6. map 地图组件
7. canvas 画布组件
8. 开放能力
9. 无障碍访问
> 常见的视图容器类组件
- view
- 普通视图区域
- 等同于 div,是个块级元素
- scroll-view
- 可滚动的视图区域
- 用来实现滚动列表效果
- swiper 和 swiper-item
- 轮播图容器组件 和 轮播图 item 组件
> 常用的基础内容组件
- text
- 文本组件
- 类似于 span 标签,行内元素
- 实现长按复制,使用到 selectable 属性
- `123321456789`
- rich-text
- 副文本组件
- 支持把 HTML 字符串渲染为 WXML 结构,需要添加nodes属性节点,
- ``
- button
- 按钮组件
- 功能比 HTML 的 button 丰富
- 通过 open-type 属性可以调用微信提供的各种功能(客服,转发,获取用户授权等)
- image
- 图片组件
- 默认宽高约为:300xp,240px

- navigator
- 页面导航组件
- 类似于 a 标签
### 6.5、API
> 小程序API概述
小程序中的API是由宿主环境提供的,通过这些API,开发者可以方便的调用微信提供的能力。
> API 三大类
1. 事件监听 API
1. 特点:以on开头,用来监听某些事件的触发
2. 例如:wx.onWindowResize(function callback) 监听窗口尺寸变化的事件
2. 同步 API
1. 特点:以Sync结尾的 API 都是同步 API
2. 特点:同步 API 的执行结果,可以通过函数的返回值直接获取,如果执行出错会抛出异常
3. 例如:wx.setStorageSync(' key ' , ' value ')向本地存储写入内容
3. 异步 API
1. 特点:类似于 jQuery 中的 $.ajax(options) 函数,需要通过success、fail、complete接收调用的结果
2. 例如:wx.request()发起网络请求,通过success回调函数接收数据
## 七、WXML 模板语法
### 7.1、数据绑定
>数据绑定基本原则
在 data 中定义数据
在 WXML 中使用数据
使用规则和 Vue 一样
### 7.2、事件绑定
> 什么是事件
事件是渲染层到逻辑层的通讯方式,通过事件可以将用户在渲染层产生的行为,反馈到逻辑层进行业务处理
> 常用的事件
| 类型 | 绑定方法 | 事件描述 |
| ------ | ------------------------- | --------------------------------------------- |
| tap | bindtap 或 band:tap | 手指触摸后马上离开,类似于 HTML 的 click 事件 |
| input | bindinput 或 band:input | 文本框的输入事件 |
| change | bindchange 或 bind:change | 状态改变时触发 |
> 事件对象的属性列表
>
> 当事件回调触发的时候,会收到一个事件对象event,详细属性如下:
| 属性 | 类型 | 说明 |
| -------------- | ---------- | -------------------------------------------- |
| type | String | 事件类型 |
| timeStamp | integer | 页面打开到触发事件所经过的毫秒数 |
| **target** | **Object** | **触发事件的组件的一些属性值集合** |
| currentTarget | Object | 当前组件的一些属性值集合 |
| **detail** | **Object** | **额外的信息** |
| touches | Array | 触摸事件,当前停留在屏幕中的触摸点信息的数组 |
| changedTouches | Array | 触摸事件,当前变化的触摸点信息的数组 |
> target 和 currentTarget 的区别
target 是触发该事件的源头组件,而 currentTarget 则是当前时间所绑定的组件

现在点击事件 bindtap 绑定在最外层的view上,当点击内部按钮时,点击事件以莫冒泡的方式向外扩散,会触发到 view 的 tap 事件处理函数,此时对于 view 来说:
- e.target 指向的是触发事件的源头组件,也就是内部的按钮组件
- e.currentTarget 指向的是当前正在触发事件的那个组件,也就是当前的 view 组件
> bandtap 的语法格式
定义一个点击事件
在对应的js文件中定义该方法的回调函数,事件函数和data同级

> 重新给页面数据赋值
通过调用 this.setData(dataObject) 方法,可以给页面 data 中的数据重新赋值


> 事件传参
可以为组件提供 **data-*** 自定义属性传参,其中 *** 代表的是参数的名字**
```html
// info 会被解析为参数名字
// 数值 2 会被解析为参数值
```
通过event.target.dataset.[参数名],获取具体参数的值
```js
btntap(event){
// dataset 是一个对象,包含了所有通过 data-* 传递过来的参数项
console.log(event.target.dataset)
console.log(event.target.dataset.info)
}
```
> bindinput 的语法格式
通过 input 事件来响应文本框的输入事件
```html
```
```js
input(e){
console.log(e.detail.value)
}
```
### 7.3、条件渲染
> wx:if 与 hidden 的对比
- wx:if 以动态创建和移出元素的方式,控制元素的展示与隐藏
- hidden 以切换样式的方式(display:none/block)控制元素的展示与隐藏
> wx:for 循环
```html
{{index}},{{item}}
```
{{ index }}为索引值
{{ item }}为当前项
> 改变 wx:for 循环的索引和当前项的变量名
```html
{{ id }},{{ abc }}
```
{{ id }}为索引值
{{ abc }}为当前项
> wx:key 的使用
类似于 Vue 列表渲染的 :key,加上key值可以提高渲染效率
```js
data:{
list:[
{id:1,name:'keqing'},
{id:2,name:'youla'},
{id:3,name:'linghua'},
]
}
```
```html
{{item.name}}
```
## 八、WXSS 模板样式
### 8.1、rpx
在 i6 中 1rpx = 0.5px,所以2rpx = 1px
### 8.2、全局样式——局部样式
- 全局样式
- 定义在 app.wxss 中的样式为全局样式
- 局部样式
- 在页面的 .wxss 中定义的样式为局部样式
## 九、全局配置
全局配置为根目录下的 app.json 文件
### 9.1、window
> window 节点常用的配置项
| 属性名 | 类型 | 默认值 | 说明 |
| ---------------------------- | -------- | ------ | ---------------------------------------------- |
| navigationBarTitleText | String | 字符串 | 导航栏标题文字内容 |
| navigationBarBackgroundColor | HexColor | #000 | 导航栏背景颜色 |
| navigationBarTextStyle | String | white | 导航栏标题颜色 |
| backgroundColor | HexColor | #fff | 窗口的背景颜色 |
| backgroundTextStyle | String | dark | 下拉 loading 的样式,支持dark / light |
| enablePullDownRefresh | Boolean | false | 是否全局开启下拉刷新 |
| onReachBottonDistance | Number | 50 | 页面上拉触底事件,触底时距页面底部距离,单位px |
### 9.2、tabBar
> tabBar的组成

1. backgroundColor:tabBar 的背景颜色
2. selectedlconPath:选中时的图片路径
3. borderStyle:tabBar 上边框颜色
4. iconPath:未选中的图片路径
5. selectedColor:tab上的文字选中时的颜色
6. color:tab 上文字的默认(未选中时)颜色
> tabBar 节点的配置项
| 属性 | 类型 | 必填 | 默认值 | 描述 |
| --------------- | -------- | ---- | ------ | --------------------------------------- |
| position | String | 否 | bottom | tabBar 的位置,仅支持bottom / top |
| borderStyle | String | 否 | black | tabBar 上边框颜色,仅支持 black / white |
| color | HexColor | 否 | | tab 上文字的默认(未选中)颜色 |
| selectedColor | HexColor | 否 | | tab 上文字选中时的颜色 |
| backgroundColor | HexColor | 否 | | tabBar 的背景颜色 |
| list | Array | 是 | | tab 页签列表,<2 <5 |
> 每个tab 项的配置选项
| 属性 | 类型 | 必填 | 描述 |
| ---------------- | ------ | ---- | ------------------------------------------ |
| pagePath | String | 是 | 页面路径,页面必须在pages中预先定义 |
| text | String | 是 | tab 上显示的文字 |
| iconPath | String | 否 | 未选中时的图标路径,position 为 top 不显示 |
| selectedlconPath | String | 否 | 选中时的图标路径,position 为 top 不显示 |
## 十、页面配置
> 页面配置项
| 属性 | 类型 | 默认值 | 描述 |
| ---------------------------- | -------- | ------- | -------------------------------------------- |
| navigationBarBackgroundColor | HexColor | #000000 | 当前页面导航栏背景颜色 |
| navigationBarTextStyle | String | white | 当前页面导航栏标题颜色,black / white |
| navigationBarTitleText | String | | 当前页码导航栏标题文字内容 |
| backgroundColor | HexColor | #ffffff | 当前页面窗口的背景色 |
| backgroundTextStyle | String | dark | 下拉loading 样式,dark / light |
| enablePullDownRefresh | Boolean | false | 是否为当前页面开启下拉刷新效果 |
| onReachBottomDistance | Number | 50 | 页面上拉触底事件,触底时页面底部距离,单位px |
## 十一、网络数据请求
### 11.1、网络请求的限制
出于安全考虑,官方对数据接口的请求做出两个限制
1. 只能请求 HTTP 类型接口
2. 必须将接口的域名添加到信任列表中
### 11.2、配置 request 合法域名
配置步骤:微信小程序管理后台 》 开发 》 开发管理 》 开发设置 》 服务器域名 》 编辑
注意事项:
1. 域名只支持 https 协议
2. 域名不能使用 IP 地址或 localhost
3. 域名必须经过 ICP 备案
4. 服务器域名一个月内最多申请五次修改
### 11.3、发起GET、POST请求
都是调用 **wx.request** 方法来实现
```js
wx.request({
url: 'https://www.escook.cn/api/get',
method:'GET',
// url: 'https://www.escook.cn/api/post',
//method:'POST',
data:{
name:'zs',
age:21
},
success:(res)=>{
console.log(res);
}
})
```
### 11.4、onLoad 生命周期函数
类似于Vue 中的mounted,组件渲染时会调用
## 十二、页面导航
### 12.1、声明式导航
> 声明式导航跳转页面
1. 在页面上声明一个``导航组件
2. 通过点击``组件实现页面跳转
3. 需要指定 url 属性和 open-type 属性
1. url 表示要跳转的页面地址,必须**以 / 开头**
2. open-type 表示跳转的方式,必须**为 switchTab**
```html
```
**注意,如果是非 tabBar 组件则不需要加 open-type 属性**
> 后退导航
如果要后退到上一页或多级页面,则需要指定 open-type 属性和 dalta 属性
- **open-type** 的值必须是 **navigateBack** 表示要进行后退导航
- **dalta** 的值必须是**数字**,表示要后退的层级
```html
返回
```
**注意:如果只后退到上一页,则可以省略 dalta属性,默认值为 1**
### 12.2、编程式导航
> 跳转到tabBar页面
1. 调用小程序的导航API,实现页面跳转
2. 调用 wx.switchTab(Object object)方法,参数属性列表如下
| 属性 | 类型 | 是否必选 | 说明 |
| -------- | -------- | -------- | ---------------------------------------------- |
| url | string | 是 | 需要跳转到的tabBar页面路径,路径后不能带参数 |
| success | function | 否 | 接口调用成功的回调函数 |
| fail | function | 否 | 接口调用失败的回调函数 |
| complete | function | 否 | 接口调用接收的回调函数(调用成功、失败都执行) |
案例:
```html
```
```js
// 跳转到message页面
goMessage(){
wx.switchTab({
url: '/pages/message/message',
})
}
```
> 跳转到非tabBar页面
- 调用wx.navigateTo(Object object)方法,参数属性列表如下
| 属性 | 类型 | 是否必选 | 说明 |
| -------- | -------- | -------- | ---------------------------------------------- |
| url | string | 是 | 需要跳转到的tabBar页面路径,路径后不能带参数 |
| success | function | 否 | 接口调用成功的回调函数 |
| fail | function | 否 | 接口调用失败的回调函数 |
| complete | function | 否 | 接口调用接收的回调函数(调用成功、失败都执行) |
案例:
```html
```
```js
// 跳转到message页面
goMessage(){
wx.navigateTo({
url: '/pages/set/set',
})
}
```
> 后退导航
- 调用wx.navigateBack(Object object) 方法,参数属性列表如下
| 属性 | 类型 | 默认值 | 是否必选 | 说明 |
| -------- | -------- | ------ | -------- | --------------------------------------------------- |
| dalta | number | 1 | 否 | 返回的页面数,如果delta大于现有页面数,则返回到首页 |
| success | function | | 否 | 接口调用成功的回调函数 |
| fail | function | | 否 | 接口调用失败的回调函数 |
| complete | function | | 否 | 接口调用接收的回调函数(调用成功、失败都执行) |
### 12.3、导航传参
> 声明式导航传参
navigator 组件的 url 属性用来指定将要跳转到的页面路径,路径后面还可以携带参数:
- **参数**与**路径**之间用 **?** 分隔
- **参数键**与**参数值**用 **=** 相连
- **不同参数**用 **&** 分隔
```html
```
> 编程式导航传参
调用wx.navigateTo(Object object)方法跳转页面,也可以携带参数
```html
```
```js
goMessage(){
wx.navigateTo({
url: '/pages/set/set?name=ls&age=19',
})
}
```
### 12.3、接收传参
通过**声明式导航传参**和**编程式导航传参**所携带的**参数**,可以直接在**onLoad事件**中直接获取到
```js
onLoad: function (options) {
console.log(options);
},
```
## 十三、页面事件
### 13.1、下拉刷新
下拉刷新是移动端专有名词,指的是通过手指在屏幕上的下拉滑动操作,从而重新加载页面数据
```js
{
"enablePullDownRefresh": true, // 开启下来刷新
"backgroundTextStyle": "dark", // 小黑点样式
"backgroundColor": "#ff0000" // 背景颜色
}
```
### 13.2、监听页面的下拉刷新事件
在页面的 .js 文件中,通过 onPullDownRefresh() 函数即可监听当前页面的下拉刷新事件
```js
// 和 data 同级
onPullDownRefresh() {
this.setData({
count: 0
})
}
```
### 13.3、停止下拉刷新效果
在页面中打开下拉刷新效果时,下拉刷新是不会复原的,需要通过调用wx.stopPullDownRefresh()可以停止当前页面的下拉刷新
```js
onPullDownRefresh() {
this.setData({
count: 0
})
wx.stopPullDownRefresh()
},
```
### 13.4、上拉触底事件
> 什么是上拉触底
上拉触底是移动端专有名词,通过手指在屏幕上上拉滑动操作,从而加载更多数据的行为
> 监听上拉触底事件
在页面的 js 文件中,通过 onReachBottom()函数即可监听当前页面的上拉触底事件
```js
onReachBottom() {
console.log('到底了');
}
```
> 配置上拉触底距离
上拉触底距离是指触发上拉触底事件时,滚动条页面底部的距离
可以在全局或页面的 json 配置文件中,通过onReachBottomDistance 属性来配置上拉触底的距离,默认值是50px
## 十四、生命周期
**生命周期函数**:是由小程序框架提供的**内置函数**,会伴随生命周期,自动按次序执行
**生命周期函数的作用**:允许程序员在**特定的时间点,执行某些特定操作**,如页面刚加载是调用 onLoad 生命周期函数来初始化页面的数据
注意:**生命周期**强调的是**时间段**,**生命周期函数**强调的是**时间点**
### 14.1、生命周期的分类
- 应用生命周期
- 特指小程序从启动 -》 运行 -》销毁的过程
- 页面生命周期
- 特指小程序中,每个页面的加载 -》 渲染 -》 销毁的过程
### 14.2、应用的生命周期函数
小程序的应用生命周期函数需要在 app.js 中进行声明
```js
App({
// 小程序初始化完成是,执行的函数,全局只调用一次
onLaunch:function(options){},
// 小程序启动,或从后台进入前台显示时触发
// 前台是指在屏幕上运行,后台是指按home键返回到桌面
onShow:function(option){},
// 小程序从前台进入后台时触发
onHide:function(){}
})
```
### 14.3、页面生命周期函数
```js
Page({
// 监听页面加载,一个页面只调用一次
onLoad:function(option){},
// 监听页面显示
onShow:function(){},
// 监听页面初次渲染完成,只调用一次
onReady:function(){},
// 监听页面隐藏
onHide:function(){},
// 监听页面卸载,只调用一次
onUnload:function(){},
})
```
## 十五、WXS脚本
### 15.1、基础语法
> 内嵌 wxs 脚本
wxs 代码可以编写在 wxml 文件中的``标签内
wxml 文件中的每一个``标签,必须提供 module 属性,用来指定当前 wxs 的模块名称
```html
{{m1.toUpper(unsername)}}
module.exports.toUpper=function(str){
//toUpperCase()是将小写转成大写
return str.toUpperCase()
}
```
```js
Page({
data: {
unsername:'zs'
}
)}
```
> 创建外联 wxs 脚本
wxs 代码可以编写在以 .wxs 为后缀名的文件内
```js
// tools.wxs 文件
function toLower(str) {
// toLowerCase为将字母转换成小写
return str.toLowerCase()
}
// 对外暴露
module.exports = {
toLower: toLower
}
```
> 使用外联 wxs 脚本
```html
{{m2.toLower(try)}}
```
```js
Page({
data: {
try:'WS'
}
)}
```
### 15.2、WXS 的特点
> 不能作为组件的事件回调
wxs 典型的运用场景就是 **过滤器**,经常配合 **Mustache** 语法使用
```html
{{m2.toLower(try)}}
```
wxs 中定义的函数**不能作为组件的事件回调**,错误用法
```html
```
> 隔离性
**隔离性**是指 wxs 的运行环境和其他JavaScript代码是隔离的,体现在如下:
1. wxs 不能调用js中定义的函数
2. wxs 不能调用小程序提供的API
> 性能好
1. 在 **iOS 设备**上,小程序内的 wxs 会比 JavaScript 代码快 2~20倍
2. 在 **Android** 上,无差异
## 十六、使用 NPM 包
### 16.1、小程序对于 npm 的支持和限制
- 不支持依赖于 Node.js内置库的包
- 不支持依赖于浏览器内置对象的包
- 不支持依赖于 C++ 插件的包
### 16.2、Vant Weapp
Vant Weapp 是一套小程序 UI 组件库,助力快速开发搭建小程序应用
官方文档: https://youzan.github.io/vant-weapp/#/home
> 安装Vant组件库
官方文档:https://youzan.github.io/vant-weapp/#/quickstart
- 初始化一个包管理文件
```shell
npm init -y
```
- 通过 npm 安装
```shell
npm i @vant/weapp@1.3.3 -S --production
```
- 在工具列表点击 工具 -》 构建npm ,完成之后点击详情,将使用 npm 模块勾选上
- 
- 在app.json将 "style": "v2" 删掉
> 使用Vant Weapp
安装完 Vant 组件库之后,可以在 app.json 的 usingComponents 节点中引入需要的组件
```js
"usingComponents": {
// 引用button组件
"van-button": "@vant/weapp/button/index"
}
```
```html
// 使用
```
### 16.3、定制全局主体样式(css变量)
> 使用方法
创建:
- 声明一个自定义属性,属性名需要以两个减号(--)开始,属性值可以是任何有效的css,element为标签,是有作用域的,若定义在 .content 下,则只有 content下的子元素能使用
```css
page {
--main-bg-color: brown
}
```
使用:
```css
page {
background-color: var(--main-bg-color)
}
```
### 16.4、定制全局主体颜色
官方文档:https://github.com/youzan/vant-weapp/blob/dev/packages/common/style/var.less
在app.wxss中,写入css变量,即可对全局生效
注意:--button-danger-background-color官方文档的定义的名称
```css
page{
--button-danger-background-color: #c00000;
--button-danger-border-color: #d60000;
}
```
### 16.5、Promise
在小程序中实现 API Promise 主要依赖于 miniprogram-api-promise 第三方包
> 安装:
```shell
npm install --save miniprogram-api-promise@1.0.4
```
> 配置:
```js
//app.js
// 需要调用一次 promisifyAll()方法,即可实现异步API的 promise
import { promisifyAll } from 'miniprogram-api-promise'
const wxp = wx.p = {}
promisifyAll(wx, wxp)
```
> 调用:
```html
按钮
```
```js
async getInfo() {
// {data:res}表示为结构出一个data字段,并重命名为res
const {data: res} = await wx.p.request({
method: 'GET',
url: 'https://www.escook.cn/api/get',
data: {
name: 'zs',
age: 20
}
})
console.log(res)
},
```
## 十七、自定义组件
### 17.1、组件样式隔离
注意点:
- app.wxss 中的全局样式对组件无效(组件就是非tabBar组件)
- 只有 class 选择器会有样式隔离的效果,id、属性选择器、标签选择器不受样式隔离影响
### 17.2、修改组件样式隔离
默认情况下,自定义组件的样式隔离特性能够防止组件内外样式互相干扰的问题,有时候又希望外界能控制组件内部样式,可以通过 stylelsolation 修改组件样式隔离选项
```js
// 在组件的 js 文件中新增配置
Component({
option:{
stylelsolation:'isolated'
}
})
```
```json
// 或在组件的 JSON 文件中新增配置
{
stylelsolation:'isolated'
}
```
> stylelsolation可选值
| 可选值 | 默认值 | 描述 |
| ------------ | ------ | ------------------------------------------------------------ |
| isolated | 是 | 表示**启用样式隔离**,在自定义组件内外,使用class 指定的样式将不会影响页面 |
| apply-shared | 否 | 表示页面 wxss 样式将**影响到自定义组件**,但自定义组件的样式不会影响页面 |
| shared | 否 | 表示页面 wxss 样式将**影响到自定义组件**,自定义组件 wxss 中指定的样式也会**影响页面**和其他**设置 apply-shared 或 shared 的自定义组件** |
### 17.3、创建自定义组件
1. 在根目录下右键创建一个Components -》 test 文件夹
2. 在文件上右键点击'新建Components '
3. 输入组件名之后就会生成四个文件 .js .json .wxss .wxml
### 17.4、引用组件
组件的引用分为 **局部引用** 和 **全局引用**
- 局部引用:组件只能在当前被引用的页面使用
- 全局引用:组件可以在每一个页面中使用
> 局部引用
在页面的 .json 配置文件中引用组件
```json
{
"usingComponents":{
"my-test1":"/components.text1/test1"
}
}
```
```html
// 使用
```
> 全局引用
在 app.json 全局配置文件中引用组件
```json
{
"page":[],
"window":[],
"usingComponents":{
"my-test1":"/components.text1/test1"
}
}
```
```html
// 使用
```
### 17.5、数据、方法和属性
> data 数据
用于组件模板渲染的私有数据,需要定义到data 节点中
```js
Component({
data:{
count:0
}
})
```
> methods方法
小程序中,事件处理函数和自定义方法需要定义到methods中
建议自定义方法以 _ 开头
```js
Component({
methods: {
a(){
console.log(123)
}
}
})
```
> properties 属性
小程序中,properties 是组件的对外属性,用来接收外界传递到组建中的数据
```js
Component({
properties: {
max:{ // 完整定义属性的方式
type: Number, // 属性值的数据类型
value:10 // 属性默认值
},
max:Number // 简化定义属性的方式
}
})
```
```html
// 传递一个数据 10
```
> 区别
在小程序中,properties 属性和data 属性的用法相同,都可读可写的,只不过:
- data 更倾向于存储组件的私有数据
- properties 更倾向于存储外界传递到组件的数据

### 17.6、数据监听器
数据监听器用来监听和响应任何属性和数据字段的变化,从而执行特定的操作,类似于Vue中的watch 侦听器
> 监听属性 字段
```js
Component({
observers:{
// 字段A新值,字段B新值 和 定义字段的顺序一样
'字段A','字段B':function(字段A新值,字段B新值){
}
}
})
```
> 监听对象
```js
Component({
observers:{
// 字段A新值,字段B新值 和 定义字段的顺序一样
'对象.属性A','对象.属性B':function(属性A新值,属性B新值){
// 当为属性A或B其中一个赋新值时会触发
// 直接给对象加一个属性C 也会触发
}
}
})
```
如果对象中需要监听的属性太多,可以使用通配符 ** 来监听对象中所有的属性变化
```js
Component({
data:{
name:{
one: 1,
two: 2,
three: 3,
four : 4
}
},
observers:{
'name.**':function(obj){
// 每个属性值就是obj.one,obj.two,....
}
}
})
```
### 17.7、纯数据字段
概念:纯数据字段指的是那些不用于界面渲染的 data 字段
好处:有助于提升页面更新的性能
> 使用规则
在 component 构造器的 options 节点中,指定 pureDataPattern 为一个正则表达式,字段名符合正则的将成为纯数据字段
```js
Component({
data:{
a: true, // 普通字段
_b: flase // 纯数据字段
},
options:{
// 正则表达式为开头为 _ 的字段为纯数据字段
pureDataPattern:/^_/
}
})
```
### 17.8、组件的生命周期
> 所有生命周期函数
| 生命周期函数 | 参数 | 描述说明 |
| ------------ | ------------ | ---------------------------------------- |
| **created** | **无** | **在组实例刚被创建出来执行** |
| **attached** | **无** | **在组件实例进入页面节点树时执行** |
| ready | 无 | 在组件在视图层布局完成后执行 |
| moved | 无 | 在组件实例被移动到节点树另一个位置时执行 |
| **detached** | **无** | **在组件实例被从页面节点树移除时执行** |
| error | Object Error | 每当组件方法抛出错误时执行 |
> 组件主要的生命周期函数
- **created**
- 组件实例**刚被创建好时**,触发
- 此时还不能调用 setData
- 通常在这个生命周期函数中,只应该用于给组件的this添加一些自定义的属性字段
- **attached**
- 在组件**完成初始化完毕,进入页面节点树时**触发
- 此时,this.data 已被初始化完毕
- 这个生命周期很有用,绝大多数初始化过程可以在这个时机进行(例如发送请求)
- **detached**
- 在组件**离开页面节点树**触发
- 退出一个页面,会触发页面每个自定义组件的detached生命周期函数
- 此时适合做一些清理性质的工作
> 使用生命周期函数
生命周期函数可以直接定义在component 构造器第一节参数中,也可以定义在lifetimes字段内,(推荐,其优先级最高)
```js
Component({
lifetimes:{
created(){},
}
})
```
### 17.9、组件所在页面的生命周期
**自定义组件的行为依赖于页面状态的变化**,此时需要用到**组件所在的页面的生命周期**
| 生命周期函数 | 参数 | 描述 |
| :----------- | ----------- | :------------------------------- |
| show | 无 | 组件所在的页面被展示时执行 |
| hide | 无 | 组件所在的页面被隐藏时执行 |
| resize | Object size | 组件所在的页面尺寸发生变化时执行 |
> 使用组件所在页面的生命周期函数,需要定义在 pageLifetimes 节点中
```js
Component({
pageLifetimes :{
show:function(){},
hide:function(){},
resize:function(size){}
}
})
```
### 17.10、插槽
在小程序中需要使用多个插槽,默认是不支持的,但是可以在组件 js 文件中,进行启用
```js
Component({
options:{
multipleSlots:true
}
})
```
> 使用多个插槽
在组件中定义插槽,并设置name属性
```html
// test3.wxml
ahhhhhhhhhhhhhh
```
在页面中
```html
上面
下面
```
### 17.11、父子组件通信
- 属性绑定
- 用于父组件向子组件的指定属性设置数据,仅能设置JSON兼容的数据
- 事件绑定
- 用于子组件向父组件传递数据,可以是任意数据
- 获取组件实例
- 父组件还可以通过 this.selectComponent() 获取子组件实例对象
- 可以直接访问子组件的任意数据和方法
> 属性绑定——> 父传子
用于实现父传子,只能传递普通类型的数据
```js
父组件 data
Page({
data:{
count:0
}
})
```
```html
// 父组件 wxml
```
子组件接收
```js
Component({
properties:{
count: Number
}
})
```
```html
count为{{count}}
```
> 事件绑定——> 子传父
用于实现子传父,可以传递任何类型的数据
1. 在**父组件**的js中,定义一个函数,这个函数即将通过自定义事件传递给子组件
```js
sync(e) {
console.log(e)
}
```
1. 在**父组件**的wxml中,通过自定义事件的形式,将定义在js中的函数传递给子组件
```html
```
1. 在**子组件**的js中,通过调用 **this.triggerEvent ('自定义事件名称' , { /* 参数对象 */ })**,将数据发送给父组件
```js
data:{
count:2333
}
methods:{
add() {
this.triggerEvent('sync', {
value: this.data.count
})
}
}
```
1. 在**父组件**的js中,通过 **e.detail** 获取到子组件传递过来的数据
1. 参数 e 为返回的数据
```js
sync(e) {
this.setData({
count: e.detail.value
})
}
```
> 获取组件实例
可在父组件中调用 this.selectComponent( id 或 class 选择器 ),获取子组件的实例对象,从而直接访问子组件的任意数据和方法,调用时需传入一个选择器,例如 this.selectComponent(".my-component")
```js
getChild() {
const child = this.selectComponent('.customA')
// console.log(child);
child.setData({
count: child.data.count + 1
})
},
```
### 17.12、behaviors
behaviors 是小程序中 用于实现组件间代码共享的特性,类似于 mixins
每个behaviors 可以包含一些属性,数据,生命周期函数和方法,组件引用它时,它的属性、数据和方法会被合并到组件中
> 创建 Behavior
调用 Behavior(Object object) 方法即可创建一个共享的 behavior 实例对象

> 使用Behavior
在组件中,使用 require() 方法导入需要的 Behavior,挂在后即可访问 Behavior 中的数据或方法

> Behavior中可用的节点
| 可用节点 | 类型 | 是否必填 | 描述 |
| ---------- | ------------ | -------- | -------------------- |
| properties | Object Map | 否 | 同组件属性 |
| data | Object | 否 | 同组件数据 |
| methods | Object | 否 | 同自定义组件方法 |
| behaviors | String Array | 否 | 引入其他的 behaviors |
| created | Function | 否 | 生命周期函数 |
| attached | Function | 否 | 生命周期函数 |
| ready | Function | 否 | 生命周期函数 |
| moved | Function | 否 | 生命周期函数 |
| detached | Function | 否 | 生命周期函数 |
>同名字段的覆盖和组合规则
- 如果有**同名的属性或方法**:
- 若组件本身有这个属性或方法,则组件的属性或方法会覆盖 **behavior**中的同名属性或方法;
- 若组件本身无这个属性或方法,则在组件的 **behavior**字段中定义靠后的 **behavior**的属性或方法会覆盖靠前的同名属性或方法;
- 在 2 的基础上,若存在嵌套引用 **behavior** 的情况,则规则为:父 **behavior** 覆盖子 **behavior** 中的同名属性或方法。
- 如果有**同名的数据字段**:
- 若同名的数据字段都是对象类型,会进行对象合并;
- 其余情况会进行数据覆盖,覆盖规则为:组件 > 父 **behavior** > 子 **behavior** 、 靠后的 behavior > 靠前的 behavior。(优先级高的覆盖优先级低的,最大的为优先级最高)
- 生命周期函数**不会相互覆盖**,而是在对应触发时机被逐个调用:
- 对于不同的生命周期函数之间,遵循组件生命周期函数的执行顺序;
- 对于同种生命周期函数,遵循如下规则:
- **behavior** 优先于组件执行;
- 子 **behavior** 优先于 父 **behavior** 执行;
- 靠前的 **behavior**优先于靠后的 **behavior** 执行;
- 如果同一个 `behavior` 被一个组件多次引用,它定义的生命周期函数只会被执行一次。
## 十八、全局数据共享
**全局数据共享**,又叫状态管理,是为了解决**组件之间数据共享**的问题
> 全局数据共享方案
- mobx-miniprogram 用来创建 Store 实例对象
- mobx-miniprogram-bindings 用来吧 Store 中的共享数据或方法,绑定到组件或页面中使用
> 安装:
```shell
npm install --save mobx-miniprogram@4.13.2 mobx-miniprogram-bindings@1.2.1
```
> 创建 store 实例
- 在根目录下创建 store -》 store.js 文件
- 引入mobx-miniprogram中的 observable 方法
- 使用 observable 方法并对外暴露供组件使用
```js
import { observable } from 'mobx-miniprogram'
export const store = observable({
// 数据字段
numA: 1,
numB: 2,
// 计算属性,get 是计算属性的修饰符,说明sum这个方法是只读的,重新赋值
get sum() {
return this.numA + this.numB
},
})
```
> 创建普通字段
```js
import { observable } from 'mobx-miniprogram'
export const store = observable({
// 数据字段
numA: 1,
numB: 2,
})
```
> 计算属性
```js
import { observable } from 'mobx-miniprogram'
export const store = observable({
// 数据字段
numA: 1,
numB: 2,
// 计算属性,get 是计算属性的修饰符,说明sum这个方法是只读的,重新赋值
get sum() {
return this.numA + this.numB
},
})
```
> 修改 store 中的数据
需要引入 actions 方法,用来修改 store 中的数据
```js
import { observable, action } from 'mobx-miniprogram'
export const store = observable({
// 数据字段
numA: 1,
numB: 2,
//action
updateNum1: action(function (step) {
this.numA += step
}),
updateNum2: action(function (step) {
this.numB += step
}),
})
```
> 在页面中使用 store(页面非组件)
首先导入需要的文件
```js
import { createStoreBindings } from 'mobx-miniprogram-bindings'
import { store } from '../../store/store'
```
在页面的onLoad生命周期函数中使用 createStoreBindings 方法,第一个参数是this,第二个参数是一个配置对象,store:数据源,fields:字段名,actions:方法
```js
Page({
onLoad: function (options) {
// this.storeBindings 是自定义属性,是createStoreBindings的返回值,用来在监听页面卸载的生命周期函数中使用
this.storeBindings = createStoreBindings(this, {
store, // 数据源
fields: ['numA', 'numB', 'sum'], // 字段名
actions: ['updateNum1'] // 方法
})
},
onUnload: function () {
// detroyStoreBindings() 清理数据
this.storeBindings.detroyStoreBindings()
},
})
```
> 在组建中使用 store
```js
import { createStoreBindings } from 'mobx-miniprogram-bindings'
import { store } from '../../store/store'
```
```js
Component({
behaviors:[createStoreBindings], // 通过 createStoreBindings 来实现自动绑定
storeBindings:{
store, // 指定要绑定的 store
fields:{ // 指定要绑定的字段数据
numA:()=>store.numA, // 绑定字段的第一种方式
numB:(store)=>store.numB, // 第二种方式
sun:'sum' // 第三种方式
},
actions:{ // 指定要绑定的方法
updataNum2:'updataNum2'
}
}
})
```
## 十九、分包
### 19.1、目录结构

### 19.2、使用分包
> 打包原则
1. 小程序会按 subpackages 的配置进行分包,subpackages 之外的目录将被打包到主包中
2. 主包也可以有自己的 pages(即最外层的 pages 字段)
3. tabBar 页面必须在主包内
4. 分包之间不能互相嵌套
> 引用原则
1. 主包无法引用分包内的私有资源
2. 分包之间不能互相引用私有资源
3. 分包可以引用主包内的公共资源

### 19.3、独立分包
**独立分包本质上也是分包**,只不过比较特殊,**可以独立于主包和其他分包而单独运行**
> 配置方法

就是在分包的配置中新增一个属性 independent 为 true,即可声明某分包为独立分包
> 引用原则
独立分包和普通分包以及主包之间,是互相隔绝的,不能互相引用彼此的资源
1. 主包**无法使用**独立分包的私有资源
2. 独立分包之间**不能互相引用**私有资源
3. 独立分包和普通分包之间**不能互相引用**私有资源
4. **!!独立分包不能引用主包的公共资源**
### 19.4、分包预下载
指:进入小程序某个页面时,由框架自动预下载可能需要的分包,提升后续的启动速度
> 配置分包预下载
预下载分包的行为,会在进入指定的页面触发
在 app.json 中,建立 preloadRule 节点定义分包的预下载规则
```js
{
"preloadRule":{ // 分包预下载规则
"pages/contact/contact":{ // 触发分包预下载的页面路径
"network":"all", // network 表示在指定的网络模式下进行预下载,可选值为:all(不限制)、WiFi(wifi模式下)
"packages":"['pakgA']" // packages 表示进入页面后,预下载哪些包,可以通过 root 或 name 属性指定预下载的包
}
}
}
```
> 分包预下载限制
同一个分包中的页面享有 共同的预下载大小限额 2M

# Uni-shop
项目开发地址:https://www.escook.cn/docs-uni-shop/
开发环境:HBuilderX ——— https://www.dcloud.io/hbuilderx.html
## 一、uni-app
uni-app 是一个使用 [Vue.js](https://vuejs.org/) 开发所有前端应用的框架,开发者编写一套代码,可发布到iOS、Android、Web(响应式)、以及各种小程序

## 二、将项目运行到微信开发者工具中
填写自己的微信小程序AppID

在 HBuilderX 中,配置“微信开发者工具”的安装路径
在微信开发者工具中,通过 设置 -> 安全设置 面板,开启“微信开发者工具”的**服务端口**

在 HBuilderX 中,点击菜单栏中的 `运行 -> 运行到小程序模拟器 -> 微信开发者工具`,将当前 uni-app 项目编译之后,自动运行到微信开发者工具中

在项目根目录中新建 `.gitignore` 忽略文件
```text
/node_modules
/unpackage/dist
```
> 注意:由于我们忽略了 unpackage 目录中**仅有的** dist 目录,因此默认情况下, unpackage 目录不会被 Git 追踪
> 此时,为了让 Git 能够正常追踪 unpackage 目录,按照惯例,我们可以在 unpackage 目录下创建一个叫做 `.gitkeep` 的文件进行占位
## 三、配置 tabBar 效果
> 添加tabBar路径
项目根目录中的 `pages.json` 配置文件,新增 `tabBar` 的配置
```json
{
"tabBar": {
"selectedColor": "#C00000",
"list": [
{
"pagePath": "pages/home/home",
"text": "首页",
"iconPath": "static/tab_icons/home.png",
"selectedIconPath": "static/tab_icons/home-active.png"
},
{
"pagePath": "pages/cate/cate",
"text": "分类",
"iconPath": "static/tab_icons/cate.png",
"selectedIconPath": "static/tab_icons/cate-active.png"
},
{
"pagePath": "pages/cart/cart",
"text": "购物车",
"iconPath": "static/tab_icons/cart.png",
"selectedIconPath": "static/tab_icons/cart-active.png"
},
{
"pagePath": "pages/my/my",
"text": "我的",
"iconPath": "static/tab_icons/my.png",
"selectedIconPath": "static/tab_icons/my-active.png"
}
]
}
}
```
> 修改导航条的样式效果
项目根目录中的 `pages.json` 配置文件,新增 `globalStyle` 的配置
```json
{
"globalStyle": {
"navigationBarTextStyle": "white", // 导航栏字体颜色
"navigationBarTitleText": "黑马优购", // 导航栏文字
"navigationBarBackgroundColor": "#C00000", // 导航栏背景色
"backgroundColor": "#FFFFFF" // 下拉刷新时显示的背景色
}
}
```
## 四、配置网络请求
由于平台的限制,小程序项目中**不支持 axios**,而且原生的 wx.request() API 功能较为简单,**不支持拦截器**等全局定制的功能。因此,建议在 uni-app 项目中使用 @escook/request-miniprogram 第三方包发起网络数据请求。
官方文档:https://www.npmjs.com/package/@escook/request-miniprogram
> 配置、安装
如果项目中没有 packag.json 包管理文件,需安装一个
```bash
npm init -y
```
安装:
```bash
npm install @escook/request-miniprogram
```
在项目的 `main.js` 入口文件中,通过如下的方式进行配置
```js
// 导入
import { $http } from '@escook/request-miniprogram'
uni.$http = $http
// 配置请求根路径
$http.baseUrl = 'https://www.uinav.com'
// 响应拦截器
$http.beforeRequest = function (options) {
uni.showLoading({
title: '数据加载中...',
})
}
// 请求拦截器
$http.afterRequest = function () {
uni.hideLoading()
}
```
118