# 微信 **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/` 点击右上角立即注册![image-20211227103051302](README.assets/image-20211227103051302.png) 点击小程序注册image-20211227103118146 填写信息即可注册完成image-20211227103147293 ## 三、找到小程序ID 登录完跳转到小程序后台管理界面,找到左边的导航栏,开发管理选项,点击开发设置则能看见开发IDimage-20211227103541091 ## 四、安装开发者工具 ### 4.1、了解微信开发者工具 微信开发者工具是官方推荐使用的小程序开发工具,它提供的主要功能如下 - 快速创建小程序项目 - 代码的查看和编辑 - 对小程序功能进行调试 - 小程序的预览和发布 ### 4.2、下载 `https://developers.weixin.qq.com/miniprogram/dev/devtools/stable.html` ### 4.3、创建项目 ![image-20211227110222322](README.assets/image-20211227110222322.png) ## 五、小程序代码构成 ### 5.1、项目结构 > **基本项目结构** ![image-20211227110422913](README.assets/image-20211227110422913.png) 1. page 用来存放所有小程序的页面 2. utils 用来存放工具性质的模块 3. app.js 小程序项目的入口文件 4. app.json 小程序项目的全局配置文件 5. app.wxss 小程序项目的全局样式文件 6. project.config.json 项目的配置文件 7. sitemap.json 用来配置小程序及页面是否允许被微信索引 > **页面组成部分** 小程序官方建议吧所有小程序页面放在page目录下,以单独的文件夹存在 ![image-20211227110838598](README.assets/image-20211227110838598.png) 每个页面由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**等 ![image-20211227112904567](README.assets/image-20211227112904567.png) - 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 中相同的配置项 ![image-20211227140005644](README.assets/image-20211227140005644.png) > 新建小程序页面 只需在 app.json -> page 字段中新增页面存放路径,开发工具会直接生成 ![image-20211227140150963](README.assets/image-20211227140150963.png) > 修改项目首页 将 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 是安卓软件的宿主环境,**脱离了宿主环境的软件是没有任何意义的** > 小程序的宿主环境 手机微信就是小程序的宿主环境 ![image-20211227143156105](README.assets/image-20211227143156105.png) > 小程序宿主环境包括的内容 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 ![image-20211227162119578](README.assets/image-20211227162119578.png) - 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 则是当前时间所绑定的组件 ![image-20211228084611209](README.assets/image-20211228084611209.png) 现在点击事件 bindtap 绑定在最外层的view上,当点击内部按钮时,点击事件以莫冒泡的方式向外扩散,会触发到 view 的 tap 事件处理函数,此时对于 view 来说: - e.target 指向的是触发事件的源头组件,也就是内部的按钮组件 - e.currentTarget 指向的是当前正在触发事件的那个组件,也就是当前的 view 组件 > bandtap 的语法格式 定义一个点击事件![image-20211228085825114](README.assets/image-20211228085825114.png) 在对应的js文件中定义该方法的回调函数,事件函数和data同级 ![image-20211228085931980](README.assets/image-20211228085931980.png) > 重新给页面数据赋值 通过调用 this.setData(dataObject) 方法,可以给页面 data 中的数据重新赋值 ![image-20211228090138200](README.assets/image-20211228090138200.png) ![image-20211228090228146](README.assets/image-20211228090228146.png) > 事件传参 可以为组件提供 **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的组成 ![image-20211228105042232](README.assets/image-20211228105042232.png) 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 模块勾选上 - ![image-20211231090930311](README.assets/image-20211231090930311.png)![image-20211231091003915](README.assets/image-20211231091003915.png) - 在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 更倾向于存储外界传递到组件的数据 ![image-20211230100804335](README.assets/image-20211230100804335.png) ### 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 实例对象 ![image-20211230193932660](README.assets/image-20211230193932660.png) > 使用Behavior 在组件中,使用 require() 方法导入需要的 Behavior,挂在后即可访问 Behavior 中的数据或方法 ![image-20211230194249825](README.assets/image-20211230194249825.png) > 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、目录结构 image-20220101142811176image-20220101144801622 ### 19.2、使用分包 > 打包原则 1. 小程序会按 subpackages 的配置进行分包,subpackages 之外的目录将被打包到主包中 2. 主包也可以有自己的 pages(即最外层的 pages 字段) 3. tabBar 页面必须在主包内 4. 分包之间不能互相嵌套 > 引用原则 1. 主包无法引用分包内的私有资源 2. 分包之间不能互相引用私有资源 3. 分包可以引用主包内的公共资源 ![image-20220102161609333](README.assets/image-20220102161609333.png) ### 19.3、独立分包 **独立分包本质上也是分包**,只不过比较特殊,**可以独立于主包和其他分包而单独运行** > 配置方法 ![image-20220102163412798](README.assets/image-20220102163412798.png) 就是在分包的配置中新增一个属性 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 ![image-20220102174639691](README.assets/image-20220102174639691.png) # 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(响应式)、以及各种小程序 ![img](README.assets/1-7.43264ae4.png) ## 二、将项目运行到微信开发者工具中 填写自己的微信小程序AppID ![image-20220104100051421](README.assets/image-20220104100051421.png) 在 HBuilderX 中,配置“微信开发者工具”的安装路径 ![image-20220104100425388](README.assets/image-20220104100425388.png)在微信开发者工具中,通过 设置 -> 安全设置 面板,开启“微信开发者工具”的**服务端口** ![image-20220104100608178](README.assets/image-20220104100608178.png) 在 HBuilderX 中,点击菜单栏中的 `运行 -> 运行到小程序模拟器 -> 微信开发者工具`,将当前 uni-app 项目编译之后,自动运行到微信开发者工具中 ![image-20220104100727457](README.assets/image-20220104100727457.png) 在项目根目录中新建 `.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