Skip to content

小程序

[TOC]

入门

概念

1、什么是小程序

小程序Mini Program)是一种不需要下载安装即可使用的应用,它实现了“触手可及”的梦想,使用起来方便快捷,用完 即走。

小程序的定位:介于 原生 App手机 H5 页面之间的产品

小程序都是由我们前端来开发,因为小程序使用的技术是WXMLWXSSJavaScript,更接近于我们前端的开发技术栈

image-20240708153932059

2、各平台小程序时间线

  • 2017 年 1 月 微信小程序上线,依附于微信 App
  • 2018 年 7 月 百度小程序上线,依附于百度 App
  • 2018 年 9 月 支付宝程序上线,依附于支付宝 App
  • 2018 年 10 月 抖音小程序上线,依附于抖音 App
  • 2018 年 11 月 头条小程序上线,依附于头条 App
  • 2019 年 5 月 QQ 小程序上线,依附于 QQApp
  • 2019 年 10 月 美团小程序上线,依附于美团 App

3、为什么各个平台都支持小程序

  • 第一:你有,我也要有
  • 第二:小程序作为介于 H5 页面和 App 之间的一项技术,它有自身很大的优势
    • 体验比传统 H5 页面要好很多
    • 相当于传统的 App,使用起来更加方便,不需要在应用商店中下载安装甚至注册登录等麻烦的操作
  • 第三:小程序可以间接的动态为 App 添加新功能
    • 传统的 App 更新需要先打包,上架到应用商店之后需要通过审核(App Store)
    • 小程序可以在 App 不更新的情况下,动态为自己的应用添加新的功能需求

4、目前使用最广泛的小程序平台

微信小程序最多,支付宝抖音小程序也或多或少有人在使用

目前公司开发小程序主要开发的还是微信小程序

5、技术选型

A、原生小程序开发:

B、框架开发

  • mpvue : 是一个使用 Vue 开发小程序的前端框架,支持微信小程序、百度智能小程序,头条小程序和支付宝小程序 目前已经被放弃
  • wepy : 由腾讯开源,让小程序支持组件化开发的框架,目前维护也很少
  • uni-app : 由 DCloud 团队开发维护,跨平台,是一个使用 Vue 开发所有前端应用的框架,目前是很多公司的技术选型
  • taro : 由京东团队开发维护,跨平台,是一个开放式跨端、跨框架解决方案,支持React/Vue/Nerv 等框架。在 Taro3.x 之后,支持 Vue3、React Hook 写法
  • uni-app 和 taro 开发原生 App

7、小程序的核心技术

  • 页面布局:WXML,类似 HTML
  • 页面样式:WXSS,几乎就是 CSS(某些不支持,某些进行了增强,但是基本是一致的)
  • 页面脚本:JavaScript+WXS(WeixinScript)

image-20240702113454219

8、小程序的核心思想

核心思想和 Vue 、React 一致:

  • 组件化开发
  • 数据响应式
  • mustache 语法
  • 事件绑定
  • ...

环境搭建

1、注册账号-申请 AppID

注册 / 登录地址:https://mp.weixin.qq.com/cgi-bin/wx

注册过程(略)

2、下载小程序开发工具

地址:https://developers.weixin.qq.com/miniprogram/dev/devtools/download.html

注意: 要下载 稳定版 Stable Build

3、使用 VSCode 开发

插件:

  • WXML - Language Service : 微信小程序 .wxml 文件代码高亮,标签、属性的智能补全(同时支持原生小程序、mpvue 和 wepy 框架,并提供 code snippets)
  • 小程序开发助手 : 代码提示 + 语法高亮,支持 js,json,wxml 文件的代码提示,支持 wxml 文件语法高亮
  • wechat-snippet : 由微信官方文档照搬下来的代码片段

4、创建小程序项目

image-20230113131808396

5、项目目录结构

image-20240702123437348

基本入门

1、新建页面的方式

image-20230113144746515

示例:基本用法

html
<!-- 显示普通文本 -->
<text class="text">基础语法</text>

示例:数据绑定 (mustache 语法)

html
<!-- base.wxml -->
<view class="line message">{{ message }}</view>
js
// base.js
Page({
  data: {
    message: '你好,微信~'
  }
})

示例:列表渲染

html
<!-- 列表渲染 ( wx:for, wx:key ) -->
<view class="line movies">
+	 <view wx:for="{{ movies }}" wx:key="*this">
+      {{ index }}: {{ item }} 
+    </view>
</view>

<!-- 3、列表渲染 (wx:for在block元素上使用) -->
<view class="line moives">
+  <block wx:for="{{ movies }}" wx:key="*this">
    <view> {{ item }} </view>
+  </block>
</view>
js
// base.js
Page({
  data: {
    movies: ['大话西游', '英雄', '长津湖', '我和我的祖国']
  }
})

注意:

  • <block> 相当于 vue 中的 <template>
  • *this : 表示 item

示例:计数器

html
<view class="line counter">
  <view>
    <text>当前计数:</text>
    {{ counter }}
  </view>
  <view class="opr">
+    <button size="mini" type="primary" bind:tap="increment">+</button>
+    <button size="mini" type="warn" bind:tap="decrement">-</button>
  </view>
</view>
js
Page({
  data: {
    counter: 0
  },
  increment() {
+    this.setData({
+      counter: this.data.counter + 1
+    })
  },
  decrement() {
    this.setData({
      counter: this.data.counter - 1
    })
  }
})

image-20230114110139794

注意:

  • bind: tap="increment" : 绑定事件,也可以写成: bindtap="increment"
  • this.setData({counter}) : 响应式修改 data 中的数据,并被重新渲染到页面中,如果通过 this.data.counter 只能修改 data 中的数据,但是不会被重新渲染到页面中

MVVM 架构

Vue 和小程序的 MVVM 架构对比:

image-20230114110328933

MVVM 架构的好处:

  • DOM Listeners: ViewModel 层可以将 DOM 的监听绑定到 Model 层
  • Data Bindings: ViewModel 层可以将数据的变量, 响应式的反应到 View 层
  • MVVM 架构让我们从 命令式编程 转到了 声明式编程

架构和配置

双线程模型

1、小程序宿主环境

宿主环境微信客户端给小程序所提供的环境为宿主环境

2、双线程模型

小程序基于 WebView 环境下时,WebView 的 JS 逻辑、DOM 树创建、CSS 解析、样式计算、Layout、Paint (Composite) 都发生 在同一线程,在 WebView 上执行过多的 JS 逻辑可能阻塞渲染,导致界面卡顿

小程序同时考虑了性能与安全,采用了目前称为「双线程模型」的架构。

双线程模型:

  • WXML模块和WXSS样式运行于 渲染层,渲染层使用 WebView线程渲染(一个程序有多个页面,会使用多个 WebView 的线程)。
  • JS脚本(app.js/home.js 等)运行于 逻辑层,逻辑层使 用JsCore运行 JS 脚本
  • 这两个线程都会经由微信客户端(Native)进行中转交互
image-20230114110943135

skyline(最新的渲染器):用来取代 WebView,直接渲染到底层 GPU

配置文件

小程序的很多开发需求被规定在了配置文件中,这样可以更有利于我们提升开发效率;保证开发出来的小程序的风格比较一致

项目配置

  • 可以在 project.config.json 文件中配置公共的配置,在 project.private.config.json 配置个人的配置,可以将 project.private.config.json 写到 .gitignore 避免版本管理的冲突。
  • 开发者工具内的设置修改会优先覆盖 project.private.config.json 的内容
  • project.private.config.json 中的相同设置优先级高于 project.config.json

全局配置

小程序根目录下的 app.json 文件用来对微信小程序进行全局配置。文件内容为一个 JSON 对象,有以下属性

常用配置

属性类型必填描述最低版本
pagesstring[]页面路径列表
windowObject全局的默认窗口表现
tabBarObject底部 tab 栏的表现
sitemapLocationstring指明 sitemap.json 的位置
stylestring指定使用升级后的 weui 样式,如'v2'2.8.0

其他配置

entryPagePath 、networkTimeout、debug、functionalPages、subpackages、workers、requiredBackgroundModes、requiredPrivateInfos、plugins、preloadRule、resizable、usingComponents、permission、useExtendedLib、entranceDeclare、darkmode、themeLocation、lazyCodeLoading、singlePage、supportedMaterials、serviceProviderTicket、embeddedAppIdList、halfPage、debugOptions、enablePassiveEvent、resolveAlias、renderer、

页面配置

常用配置

属性类型默认值描述最低版本
navigationBarBackgroundColorHexColor#000000导航栏背景颜色,如 #000000
navigationBarTextStylestringwhite导航栏标题颜色,仅支持 black / white
navigationBarTitleTextstring导航栏标题文字内容
navigationStylestringdefault导航栏样式,仅支持以下值: default 默认样式 custom 自定义导航栏,只保留右上角胶囊按钮。iOS/Android 微信客户端 7.0.0,Windows 微信客户端不支持
backgroundColorHexColor#ffffff窗口的背景色
backgroundTextStylestringdark下拉 loading 的样式,仅支持 dark / light
backgroundColorTopstring#ffffff顶部窗口的背景色,仅 iOS 支持微信客户端 6.5.16
backgroundColorBottomstring#ffffff底部窗口的背景色,仅 iOS 支持微信客户端 6.5.16
enablePullDownRefreshbooleanfalse是否开启当前页面下拉刷新。 详见 Page.onPullDownRefresh
onReachBottomDistancenumber50页面上拉触底事件触发时距页面底部距离,单位为 px。 详见 Page.onReachBottom
usingComponentsObject页面自定义组件配置1.6.3

其他配置

homeButton、pageOrientation、disableScroll、initialRenderingCache、style、singlePage、restartStrategy、handleWebviewPreload、visualEffectInBackground、enablePassiveEvent、renderer

  • 注:并不是所有 app.json 中的配置都可以在页面覆盖或单独指定,仅限于本文档包含的选项。

  • 注:iOS/Android 客户端 7.0.0 以下版本,navigationStyle 只在 app.json 中生效。

示例:tabbar 导航栏

js
// app.json

  "tabBar": {
    "selectedColor": "#ff8198",
    "list": [
      {
        "pagePath": "pages/index/index",
        "iconPath": "assets/tabbar/home.png",
        "selectedIconPath": "assets/tabbar/home_active.png",
        "text": "首页"
      },
      {
        "pagePath": "pages/category/category",
        "iconPath": "assets/tabbar/category.png",
        "selectedIconPath": "assets/tabbar/category_active.png",
        "text": "分类"
      },
      {
        "pagePath": "pages/cart/cart",
        "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",
        "text": "我的"
      }
    ]
  },

示例:下拉刷新缩短等待时间

js
// category.json
{
+  "enablePullDownRefresh": true,
  "backgroundTextStyle": "dark"
}
js
// category.js
Page({
+  onPullDownRefresh() {
    console.log('下拉刷新 - 开始');
    setTimeout(function() {
+      wx.stopPullDownRefresh({
+        success: (res) => { console.log('停止刷新 - 成功'); },
+        fail: (err) => { console.log('停止刷新 - 失败'); }
+      })
    },500)
  }
})

示例:上拉加载更多数据

html
<!-- category.wxml -->
<view class="load-more">
  <block wx:for="{{ dataList }}" wx:key="*this">
    <view> 数据列表:{{ item }} </view>
  </block>
</view>
js
// category.js
Page({
  data: {
+    dataList: 30
  },
  onPullDownRefresh() {
    console.log('下拉刷新 - 开始');
+    // 重置dataList
+    this.setData({
+      dataList: 30
+    })
  },
+  onReachBottom() {
+    console.log('已经触底');
+    this.setData({
+      dataList: this.data.dataList + 30
+    })
  }
})

注册小程序

App()

注册小程序。接受一个 Object 参数,其指定小程序的生命周期回调等。

*注意:*App() 必须在 app.js 中调用,必须调用且只能调用一次。不然会出现无法预期的后果。

  • App()(options),注册小程序。接受一个 Object 参数,其指定小程序的生命周期回调等。
    • 参数:options: { onLaunch, onShow, onHide, onError, onPageNotFound, onUnhandledRejection, onThemeChange }

    • onLaunch(options) => void,生命周期回调——监听小程序初始化。

      • options
      • scenenumber,启动小程序的场景值
    • onShow(options) => void,生命周期回调——监听小程序启动或切前台。

      • options
      • scenenumber,启动小程序的场景值
    • onHide() => void,生命周期回调——监听小程序切后台。

    • onErrorfunction,错误监听函数。

    • onPageNotFoundfunction,页面不存在监听函数。

    • onUnhandledRejectionfunction,未处理的 Promise 拒绝事件监听函数。

    • onThemeChangefunction,监听系统主题变化

    • 其他any,开发者可以添加任意的函数或数据变量到 Object 参数中,用 this 可以访问

4、注册 App 时,内部做了什么

  • 判断小程序的进入场景
  • 监听生命周期函数,在生命周期中执行对应的业务逻辑
  • 定义全局 App 的数据,因为 App()实例只有一个,并是全局共享的单例对象,所以可以保存共享数据

作用一:判断打开场景

1、常见打开场景:

  • 1008: 群聊会话中打开
  • 小程序列表中打开
  • 1011: 微信扫一扫打开
  • 1037: 另一个小程序打开

2、场景值列表:https://developers.weixin.qq.com/miniprogram/dev/reference/scene-list.html

image-20230213131607718

3、在 onLaunch 和 onShow 生命周期回调函数中,会有 options 参数,其中有 scene 值

image-20230114125616925

作用二:定义全局 App 的数据

1、在app.js中定义

image-20230213131755842

2、在page.js中访问

image-20230213131801756

image-20230114130842914

image-20230114130738248

作用三:生命周期函数

image-20230114122850175

用户登录

image-20240703114516346

Page()

注册小程序中的一个页面。接受一个 Object 类型参数,其指定页面的初始数据、生命周期回调、事件处理函数等。

  • Page()(options),注册小程序中的一个页面。接受一个 Object 类型参数,其指定页面的初始数据、生命周期回调、事件处理函数等。

    • 参数:options

    • dataobject,页面的初始数据

    • optionsobject,页面的组件选项,同 Component 构造器 中的 options ,需要基础库版本 2.10.1

    • behaviorsstring | array,类似于 mixins 和 traits 的组件间代码复用机制,参见 behaviors,需要基础库版本 2.9.2

    • 生命周期回调函数

    • onLoadfunction(query),生命周期回调—监听页面加载

      • 参数:query
    • onShowfunction(),生命周期回调—监听页面显示

    • onReadyfunction(),生命周期回调—监听页面初次渲染完成

    • onHidefunction(),生命周期回调—监听页面隐藏

    • onUnloadfunction(),生命周期回调—监听页面卸载

    • 事件处理函数

    • onPullDownRefresh()function,监听用户下拉动作

    • onReachBottom()function,页面上拉触底事件的处理函数

    • onShareAppMessage()function,用户点击右上角转发。

      • 参数:{from, target, webViewUrl}
      • 返回值:{title, path, imageUrl, promise}
    • onShareTimeline()function,用户点击右上角转发到朋友圈

    • onAddToFavorites()function,用户点击右上角收藏。

      • 参数:{webViewUrl, title, imageUrl, query}
    • onPageScroll()function,页面滚动触发事件的处理函数。

      • 参数:{scrollTop}
    • onResize()function,页面尺寸改变时触发,详见 响应显示区域变化

      • 参数:res
    • onTabItemTap()function,当前是 tab 页时,点击 tab 时触发

      • 参数:{index, pagePath, text}
    • onSaveExitState()function,页面销毁前保留状态回调

    • 其他any,开发者可以添加任意的函数或数据到 Object 参数中,在页面的函数中用 this 可以访问。这部分属性会在页面实例创建时进行一次深拷贝。

    • 组件事件处理函数

    • Page.routestring,到当前页面的路径

    • Page.prototype.setData()function,将数据从逻辑层发送到视图层(异步),同时改变对应的 this.data 的值(同步)

      • 参数:{data, callback}

image-20230114122911816

业务 1:发送网络请求,获取服务器数据

image-20230114163527001

image-20230114163211945

业务 2:初始化本地数据

image-20240703142625046

image-20240703142606188

业务 3:监听 WXML 点击,绑定事件函数

image-20230114164036559

image-20230114164009444

示例: 点击不同按钮,打印对应的内容

1、定义按钮内容

image-20240703143141073

2、遍历渲染按钮,并设置不同的颜色

image-20240703143553644

3、监听按钮点击事件,并通过data-xxx携带参数

image-20240703143922296

4、定义事件函数,并通过event.target.dataset.xxx获取参数值

image-20240703143845261

业务 4:监听其他事件:页面滚动,上拉加载,下拉刷新

1、开启下拉刷新功能

image-20230114165112329

2、定义下拉刷新,上拉加载,页面滚动事件函数

页面滚动时可以通过event.scrollTop获取滚动的距离

image-20240703144509482

Page 页的生命周期

image-20240703150053821

image-20230114170952601

onshow(options) 判断进入场景

image-20230114122919691

image-20230114122937329

常见内置组件

text

基本使用

html
<text>Hello World</text>
<text>{{ message }}</text>

属性-常用

  • user-selectboolean,文本是否可选,该属性会使文本节点显示为 inline-block

  • spacestring,显示连续空格

    • ensp:中文字符空格一半大小
    • emsp:中文字符空格大小
    • nbsp:根据字体设置的空格大小
  • decodeboolean,是否解码

user-select

html
<text user-select>{{ message }}</text>
<text user-select="{{ true }}">{{ message }}</text>

decode

html
<text decode>&gt;</text>

注意:

  • decode 可以解析的有 &nbsp; &lt; &gt; &amp; &apos; &ensp; &emsp;
  • text 组件内只支持 text 嵌套
  • 除了文本节点以外的其他节点都无法长按选中

button

基本使用

html
<!-- 块级元素 -->
<button>按钮</button>

属性-常用

  • sizedefault | mini,按钮的大小
  • typeprimary | default | warn,按钮的样式类型
  • plainboolean,按钮是否镂空,背景色透明
  • disabledboolean,是否禁用
  • loadingboolean,名称前是否带 loading 图标
  • form-typesubmit | reset,用于 form 组件,点击分别会触发 form 组件的 submit/reset 事件
  • hover-classstring,指定按钮按下去的样式类。当 hover-class="none" 时,没有点击态效果
  • open-typestring,微信开放能力
    • contact,打开客服会话,如果用户在会话中点击消息卡片后返回小程序,可以从 bindcontact 回调中获得具体信息,具体说明 (小程序插件中不能使用
    • share,触发用户转发,使用前建议先阅读使用指引
    • getPhoneNumber,获取用户手机号,可以从 bindgetphonenumber 回调中获取到用户信息,具体说明 (小程序插件中不能使用
    • getUserInfo,获取用户信息,可以从 bindgetuserinfo 回调中获取到用户信息 (小程序插件中不能使用
    • launchApp,打开 APP,可以通过 app-parameter 属性设定向 APP 传的参数具体说明
    • openSetting,打开授权设置页
    • feedback,打开“意见反馈”页面,用户可提交反馈内容并上传日志,开发者可以登录小程序管理后台后进入左侧菜单“客服反馈”页面获取到反馈内容
    • chooseAvatar,获取用户头像,可以从 bindchooseavatar 回调中获取到头像信息

size: default | mini

html
<button size="mini">按钮size属性</button>

type: primary | warn | default

html
<button type="primary">按钮type属性</button>
<button type="warn">按钮type属性</button>

plain

html
<button plain>按钮plain属性</button>

disabled

html
<button disabled>按钮disabled属性</button>

loading

html
<button loading>按钮loading属性</button>

hover-class

html
<button hover-class="active">按钮hover-class属性</button>

open-type

open-type="contact"

打开客服会话,如果用户在会话中点击消息卡片后返回小程序,可以从 bindcontact 回调中获得具体信息

image-20240703153918137

image-20240703154025887

open-type="getUserInfo"

获取用户信息,可以从wx.getUserProfile()回调中获取到用户信息

1、绑定事件(注意:不用绑定open-type="getUserInfo")

image-20230114180103263

2、事件回调

image-20240703160130112

open-type="getPhoneNumber"

获取用户手机号,可以从 bindgetphonenumber 回调中获取到用户信息

注意:

  • 个人开发者没有获取手机号的权限
  • 企业开发者有获取手机号的权限,会获取到一个 code,然后根据该 code 去服务器请求真实的手机号。收费:0.03 元/次

1、绑定事件

image-20230213174211194

2、事件回调

image-20230114180423357

3、个人开发者没有获取手机号的权限

image-20240703160457511

view

视图容器

基本使用

html
<view>我是view组件</view>

属性-常用

  • hover-classstring,指定按下去的样式类。当 hover-class="none" 时,没有点击态效果
  • hover-stop-propagationboolean默认:false,指定是否阻止本节点的祖先节点出现点击态
  • hover-start-timenumber默认:50,按住后多久出现点击态,单位毫秒
  • hover-stay-timenumber默认:400,手指松开后点击态保留时间,单位毫秒

注意: 如果需要使用滚动视图,请使用 <scroll-view>

示例

html
<view bindtap="onViewClick" hover-class="active">我是view组件</view>
js
onViewClick() {
    console.log('onViewClick')
}

image

基本使用

图片

注意:

  • image 元素默认宽高:320x240
html
<image src="/assets/zznh.png" />
<image
  src="https://www.gannett-cdn.com/-mm-/8d3b98b3882527c4b1777d0b11b082fdfebfb6d9/c=0-0-3400-1918/local/-/media/Salisbury/2014/08/09/bobcatt.jpg"
/>

属性-常用

  • srcstring,图片资源地址

  • modestring,图片裁剪、缩放的模式

    • widthFix:``,(推荐),缩放模式,宽度不变,高度自动变化,保持原图宽高比不变
    • heightFix:``,缩放模式,高度不变,宽度自动变化,保持原图宽高比不变
    • aspectFit:``,缩放模式,保持纵横比缩放图片,使图片的长边能完全显示出来。也就是说,可以完整地将图片显示出来
  • webpboolean,默认不解析 webP 格式,只支持网络资源

  • lazy-loadboolean,图片懒加载,在即将进入一定范围(上下三屏)时才开始加载

  • show-menu-by-longpressboolean,长按图片显示发送给朋友、收藏、保存图片、搜一搜、打开名片/前往群聊/打开小程序(若图片中包含对应二维码或小程序码)的菜单。

  • binderroreventhandle,当错误发生时触发,event.detail =

  • bindloadeventhandle,当图片载入完毕时触发,event.detail =

mode

image-20230114182513922

选择本地图片并展示

1、绑定事件,选择图片

image-20240703164502780

2、事件函数

image-20240703164203494

3、res 返回值

image-20240703164148720

4、保存图片地址

image-20240703164442698

5、展示图片

image-20240703164621290

scroll-view

常用属性

属性类型默认值必填说明最低版本
scroll-xbooleanfalse允许横向滚动1.0.0
scroll-ybooleanfalse允许纵向滚动1.0.0
enable-flexbooleanfalse启用 flexbox 布局。开启后,当前节点声明了 display: flex 就会成为 flex container,并作用于其孩子节点。2.7.3
bindscrolltouppereventhandle滚动到顶部/左边时触发1.0.0
bindscrolltolowereventhandle滚动到底部/右边时触发1.0.0
bindscrolleventhandle滚动时触发,event.detail =1.0.0

注意: 滚动的前提:

  • 固定的宽度或高度
  • 内容需要超出宽度或高度
  • 设置 scroll-x 或 scroll-y

上下滚动

1、遍历生成多个 view,撑起 scroll-view

image-20240703165543173

image-20240703165638524

2、设置 scroll-view 固定的高度

image-20240703165831765

3、开启上下滚动

image-20240703165924525

左右滚动

1、设置 scroll-view 固定的宽度(默认占据整行)

2、水平布局 view 元素

  • 开启 scroll-view 的 enable-flex 属性
  • 使用 wxss 水平布局

image-20240703170640798

image-20240703170551955

3、开启左右滚动

image-20240703170654773

监听 scroll-view 滚动

1、监听事件

image-20240703171319247

2、事件函数

image-20240703171409108

3、event 参数

image-20240703171434045

4、deltaX 表示当前是想左还是向右滚动

  • deltaX > 0:向右滚动
  • deltaX < 0:向左滚动

input

新增 input 支持双向绑定

image-20230117165904503

组件共同属性

属性名类型描述注解
idString组件的唯一标示保持整个页面唯一
classString组件的样式类在对应的 WXSS 中定义的样式类
styleString组件的内联样式可以动态设置的内联样式
hiddenBoolean组件是否显示所有组件默认显示
data-*Any自定义属性组件上触发的事件时,会发送给事件处理函数
bind * / catch*EventHandler组件的事件详见事件

WXSS 语法

基本语法

全局样式、页面样式、行内样式

image-20230117172045768

wxss 支持的选择器:

选择器样例样例描述
.class.intro选择所有拥有 class="intro" 的组件
#id#firstname选择拥有 id="firstname" 的组件
elementview选择所有 view 组件
element, elementview, checkbox选择所有文档的 view 组件和所有的 checkbox 组件
::afterview::after在 view 组件后边插入内容
::beforeview::before在 view 组件前边插入内容

权重

WXSS 的权重和 CSS 类似:

image-20230117172411085

尺寸单位 rpx

rpx(responsive pixel): 可以根据屏幕宽度进行自适应。规定屏幕宽为 750rpx

如在 iPhone6 上,屏幕宽度为 375px,共有 750 个物理像素,则 750rpx = 375px = 750 物理像素,1rpx = 0.5px = 1 物理像素。

设备rpx 换算 px (屏幕宽度/750)px 换算 rpx (750/屏幕宽度)
iPhone51rpx = 0.42px1px = 2.34rpx
iPhone61rpx = 0.5px1px = 2rpx
iPhone6 Plus1rpx = 0.552px1px = 1.81rpx

建议: 开发微信小程序时设计师可以用 iPhone6 作为视觉稿的标准。

注意: 在较小的屏幕上不可避免的会有一些毛刺,请在 2 开发时尽量避免这种情况

以 375px 宽度屏幕的 iPhone6 为标准,如下设置

image-20230117174218185

导入样式

使用@import语句可以导入外联样式表,@import后跟需要导入的外联样式表的相对路径。

css
/** app.wxss **/
+ @import "common.wxss";
.middle-p {
  padding:15px;
}

WXML 语法

基本规则

  • 类似于 HTML 代码,可以写成单标签,也可以写成双标签
  • 必须有严格的闭合,否则会导致编译错误
  • 大小写敏感

数据绑定 Mustache

html
<!-- 1. Munstache语法 -->
<view>{{ message }}</view>
<view>{{ firstname + ' ' + lastname }}</view>

注意: 不允许在 中调用方法

html
<!-- 错误的写法:不允许调用方法 -->
<view>{{ testDemo() }}</view>

条件渲染 wx:if

image-20230117181232858

和 Vue 的区别:

  • v-if === wx:if
  • v-else-if === wx:elif

hidden 属性

image-20230117181640607

image-20230118163018596

image-20230118163008657

image-20230118163621289

列表渲染 wx:for

image-20230118173351672

基本使用

  • 遍历数组

    image-20230118173905444

  • 遍历数字

    image-20230118173954021

  • 遍历字符串

    image-20230118174054143

block 组件

image-20230118174726283

image-20230118174614580

item、index 重命名

image-20230118175040899

wx:key 的作用

image-20230118175310256

WXS 语法

介绍

注意: wxs 中不支持 ES6+语法

image-20230119111141123

基本入门

image-20230119111152257

1、添加价格符号

wxs 写法一:标签<wxs>

image-20230119113537669

image-20230119113641582

wxs 写法二:独立的.wxs 文件,通过 src 引入

image-20230119113859329

image-20230119114027959

2、计算总价格

image-20240708162510446

3、格式化数字单位

image-20230119120029461

4、格式化时间

补零函数

image-20230119121449949

image-20230119121524955

事件处理

事件监听

什么时候会产生事件

  • 小程序需要经常和用户进行某种交互,比如点击界面上的某个按钮或者区域,比如滑动了某个区域;
  • 事件是视图层到逻辑层的通讯方式;
  • 事件可以将用户的行为反馈到逻辑层进行处理;
  • 事件可以绑定在组件上,当触发事件时,就会执行逻辑层中对应的事件处理函数;
  • 事件对象可以携带额外信息,如 id, dataset, touches;

事件如何处理

  • 事件是通过 bind/catch 这个属性绑定在组件上的(和普通的属性写法很相似, 以 key=“value”形式);
  • key 以 bind 或 catch 开头, 从 1.5.0 版本开始, 可以在 bind 和 catch 后加上一个冒号;
  • 同时在当前页面的 Page 构造器中定义对应的事件处理函数, 如果没有对应的函数, 触发事件时会报错;
  • 比如当用户点击该 button 区域时,达到触发条件生成事件 tap,该事件处理函数会被执行,同时还会收到一个事件对象 event。

事件的基本使用

image-20240708174757445

image-20230119122540226

image-20230119122629884

常见事件

公共事件

  • touchstart:``,手指触摸动作开始
  • touchmove:``,手指触摸后移动
  • touchcancel:``,手指触摸动作被打断,如来电提醒,弹窗
  • touchend:``,手指触摸动作结束
  • tap:``,手指触摸后马上离开
  • longpress:``,手指触摸后,超过 350ms 再离开,如果指定了事件回调函数并触发了这个事件,tap 事件将不被触发
  • longtap:``,手指触摸后,超过 350ms 再离开(推荐使用 longpress 事件代替)

input 常见特有事件

  • bindinputeventhandle,键盘输入时或内容改变时触发。event.detail = { value: string, cursor?: number, keyCode?: number },cursor 为光标位置,keyCode 为键值。2.1.0 起支持,处理函数可以直接 return 一个字符串,将替换输入框的内容。
  • bindfocuseventhandle,输入框聚焦时触发,event.detail = { value, height },height 为键盘高度,在基础库 1.9.90 起支持
  • bindblureventhandle,输入框失去焦点时触发,event.detail =

scroll-view 常见特有事件

  • bindscrolltouppereventhandle,滚动到顶部/左边时触发
  • bindscrolltolowereventhandle,滚动到底部/右边时触发

事件对象 event

当某个事件触发时, 会产生一个事件对象, 并且这个对象被传入到回调函数中, 事件对象有哪些常见的属性呢?

BaseEvent 基础事件对象属性列表:

  • typestring,事件类型
  • timeStampinteger,事件生成时的时间戳
  • target{ id, dataset... },当前触发事件的组件的一些属性值集合
  • currentTarget{ id, dataset... },当前处理事件的组件的一些属性值集合
  • markobject,事件标记数据

区分 currentTarget、target

**说明:**事件绑定在 outer 元素上,点击的是 inner 元素

image-20230119125950440

image-20230119125607196

image-20230119125849890

建议使用event.currentTarget 接收参数

区分 touches、changedTouches

image-20230119130222089

事件参数传递

data-*

使用 data-* 来传递参数

建议使用event.currentTarget 接收参数

image-20230119132529877

image-20230119132536661

案例:切换标签

image-20230119153449140

image-20230119152747980

mark

注意:

  • 在 2.7.1 版本后支持该属性
  • mark 会将元素及其子元素上所有用mark:*传递的参数统一放入event.mark

image-20230119160345022

接收参数

image-20230119160350722

结果

image-20230119160359489

冒泡和捕获的区别

image-20230119153841679

1、捕获阶段

image-20230119154635467

image-20230119154621907

2、冒泡阶段

image-20230119154735845

image-20230119154751996

image-20230119154901987

3、catch

和 bind 的区别:catch 捕获到事件后,会阻止事件再继续传递

image-20230119155237364

组件化开发

Component()

创建自定义组件,接受一个 Object 类型的参数。

1、语法

js
Component(Object: options)

2、参数

  • propertiesobject | map,组件的对外属性,是属性名到属性设置的映射表
    • type:``,属性的类型
    • value:``,属性的初始值
    • observerfunction,属性值变化时的回调函数
  • dataobject,组件的内部数据,和 properties 一同用于组件的模板渲染
  • observersobject,组件数据字段监听器,用于监听 properties 和 data 的变化,参见 数据监听器
  • methodsobject,组件的方法,包括事件响应函数和任意的自定义方法,关于事件响应函数的使用,参见 组件间通信与事件
  • behaviorsstring | array,类似于 mixins 和 traits 的组件间代码复用机制,参见 behaviors
  • 组件生命周期函数
  • createdfunction,组件生命周期函数 - 在组件实例刚刚被创建时执行,注意此时不能调用 setData
  • attachedfunction,组件生命周期函数 - 在组件实例进入页面节点树时执行
  • readyfunction,组件生命周期函数 - 在组件布局完成后执行
  • movedfunction,组件生命周期函数 - 在组件实例被移动到节点树另一个位置时执行
  • detachedfunction,组件生命周期函数 - 在组件实例被从页面节点树移除时执行
  • relationsobject,组件间关系定义,参见 组件间关系
  • externalClassesstring | array,组件接受的外部样式类,参见 外部样式类
  • optionsobject | map,一些选项(文档中介绍相关特性时会涉及具体的选项设置,这里暂不列举)
    • styleIsolationstring,样式隔离
      • isolated:启用样式隔离,在自定义组件内外,使用 class 指定的样式将不会相互影响(默认
      • apply-shared:页面 wxss 样式将影响到自定义组件,但自定义组件 wxss 中的样式不会影响页面
      • shared:页面 wxss 样式将影响到自定义组件,自定义组件 wxss 中的样式也会影响页面和其他设置
    • multipleSlotsboolean,是否启用多插槽
  • lifetimesobject,组件生命周期声明对象,参见 组件生命周期
  • pageLifetimesobject,组件所在页面的生命周期声明对象,参见 组件生命周期

3、组件实例方法(常用)

使用示例:this.setData({ name: '张飞' })

  • setDatafunction({}),设置 data 并执行视图层渲染
  • triggerEventfunction({name, detail, options}),触发事件
  • selectComponentfunction(selector),使用选择器选择组件实例节点,返回匹配到的第一个组件实例对象
  • selectAllComponentsfunction(selector),使用选择器选择组件实例节点,返回匹配到的全部组件实例对象组成的数组
  • getTabBar:``,返回当前页面的 custom-tab-bar 的组件实例
  • getPageId:``,返回页面标识符(一个字符串),可以用来判断几个自定义组件实例是不是在同一个页面内
  • animatefunction(selector, keyframes, duration, callback),执行关键帧动画
  • clearAnimationfunction(selector, options, callback),清除关键帧动画

组件化思想

小程序在刚刚推出时是不支持组件化的, 也是为人诟病的一个点。从 v1.6.3 开始, 小程序开始支持自定义组件开发

image-20230214094146916

组件化思想的应用

  • 可以将页面内的功能模块抽象成自定义组件,以便在不同的页面中重复使用;

  • 也可以将复杂的页面拆分成多个低耦合的模块,有助于代码维护

  • 尽可能的将页面拆分成一个个小的、可复用的组件,这样让我们的代码更加方便组织和管理,并且扩展性也更强

自定义组件

1、内置组件

html
<!-- 内置组件 -->
<text>内置组件 text</text>

2、创建组件

  • 1、创建组件文件夹,创建一个自定义组件

    image-20240710094103088

  • 2、在 json 文件中设置:{ "component": true }

    image-20240710094323852

  • 3、在 wxml 中编写组件模板

    image-20240710094500994

  • 4、在 wxss 中编写组件样式

    image-20240710094444563

  • 5、在 js 中定义数据和组件内部的逻辑

    image-20240710094357962

3、使用组件

  • 全局使用组件:

    app.json中设置 usingComponents

    json
    {
      "usingComponents": {
        "section-info": "/components/section-info/section-info"
      }
    }
  • 局部使用组件:

    pages/D03-component/D03-component.json 中设置 usingComponents

    json
    {
      "usingComponents": {
        "section-info": "/components/section-info/section-info"
      }
    }

4、注意事项

  • 自定义组件也可以引用自定义组件,引用方法类似于页面引用自定义组件的方式(使用 usingComponents 字段)
  • 自定义组件和页面所在项目根目录名 不能以“wx-”为前缀,否则会报错。
  • 如果在app.jsonusingComponents声明某个组件,那么所有页面和组件可以直接使用该组件

组件样式-实现细节

1、组件内的样式 对 外部样式 的影响

  • 结论一:组件内的 class 样式,只对组件 wxml 内的节点生效, 对引用组件的 Page 页面不生效
  • 结论二:组件内不能使用 id 选择器、属性选择器、标签选择器
html
<!-- 组件内部 -->
<view class="title">我是组件内部的样式</view>
html
<!-- 组件外部 -->
<test-style></test-style>
<view class="title">我是组件外部的样式</view>

image-20230215110306534

2、外部样式 对 组件内样式 的影响

  • 结论一:外部使用class的样式,只对外部 wxml 的 class 生效,不会影响组件内部样式
  • 结论二:外部使用了id 选择器属性选择器不会影响组件内部样式
  • 结论三:外部使用了标签选择器会影响组件内部

3、如何让 class 可以相互影响

  • 在 Component 对象中,可以传入一个 options 属性,其中 options 属性中有一个 styleIsolation(隔离)属性。
  • styleIsolation 有三个取值:
    • isolated: (默认),表示启用样式隔离,在自定义组件内外,使用 class 指定的样式将不会相互影响;
    • apply-shared: 表示页面 wxss 样式将影响到自定义组件,但自定义组件 wxss 中指定的样式不会影响页面;
    • shared: 表示页面 wxss 样式将影响到自定义组件,自定义组件 wxss 中指定的样式也会影响页面和其他设置
html
<!-- 组件内部 -->
<view class="title">我是组件内部的样式</view>

<script>
  +    Component({
  +      options: {
  +        styleIsolation: 'shared'
        }
      })
</script>

<style>
  .title {
  +  color: red
  }
</style>
html
<!-- 组件外部 -->
<test-style></test-style>
<view class="title">我是页面的样式</view>

<style>
  .title {
  +  background-color: orange;
  }
</style>

image-20230215112033381

组件通信

很多情况下,组件内展示的内容(数据、样式、标签),并不是在组件内写死的,而且可以由使用者来决定

image-20230214101849513

1、向组件传递数据 - properties

给组件传递数据:

  • 大部分情况下,组件只负责布局和样式,内容是由使用组件的对象决定的;
  • 所以,我们经常需要从外部传递数据给我们的组件,让我们的组件来进行展示;

如何传递呢?

  • 使用properties属性;

支持的类型:

  • String、Number、Boolean
  • Object、Array、null(不限制类型)

默认值:

  • 可以通过 value 设置默认值;

示例:

html
<!-- 组件外部 -->
<test-style title="鹅鹅鹅" content="鹅,鹅,鹅,曲项向天歌。白毛浮绿水,红掌拨清波。"></test-style>
<test-style title="静夜思" content="床前明月光,疑是地上霜。举头望明月,低头思故乡。"></test-style>
html
<!-- 组件内部 -->
+ <view class="title">{{ title }}</view> + <view>{{ content }}</view>

<script>
     Component({
  +     properties: {
  +       title: {
  +         type: String,
  +         value: '组件标题'  // Vue中使用的是default
         },
  +       content: {
  +         type: String,
  +         value: '组件内容,展示'
         }
       }
     })
</script>

image-20230215130648149

2、向组件传递样式 - externalClasses

给组件传递样式:

  • 有时候,我们不希望将样式在组件内固定不变,而是外部可以决定样式。

这个时候,我们可以使用 externalClasses 属性:

  • 1、在 Component 对象中,定义 externalClasses 属性
  • 2、在组件内的 wxml 中使用 externalClasses 属性中的 class
  • 3、在页面中传入对应的 class,并且给这个 class 设置样式

示例:

html
<!-- 组件外部 -->
+ <test-external-classess info="info"></test-external-classess>

<style>
  + .info {
    color: blue;
  }
</style>
html
<!-- 组件内部 -->
+ <view class="info">组件:externalClasses</view>

<script>
      Component({
  +      externalClasses: ['info']
      })
</script>

image-20230215121657667

3、组件向外传递事件 – 自定义事件

有时候是自定义组件内部发生了事件,需要告知使用者,这个时候可以使用自定义事件

注意:

  • 自定义组件中的处理函数需要写在methods 中,而 Page 页面中的处理函数,是直接写在Page中的
  • 组件内部传递的参数,在组件外部需要通过 event.detail 来获取
html
<!-- 组件内部 -->
<!-- 1、组件内部发生了点击事件onCpnClick -->
<view bind:tap="onCpnClick">组件:标题</view>

<script>
  Component({
    methods: {
      // 2、实现点击事件
      onCpnClick() {
        console.log('组件title点击!') +
          // 3、向组件外部发送cpnClick事件,并传递参数
          this.triggerEvent('cpnClick', 'message')
      }
    }
  })
</script>
html
<!-- 组件外部 -->
<!-- 4、组件外部通过bind:cpnClick获取内部发送过来的事件cpnCLick,并绑定到处理函数onOuterClick上 -->
+ <test-trigger-event bind:cpnClick="onOuterClick"></test-trigger-event>

<script>
  Page({
    // 5、实现处理函数onOuterClick
  +  onOuterClick(e) {
      console.log('Outer点击', e.detail, e)
    }
  })
</script>

image-20230215141222858

4、自定义组件练习

image-20230215150147955

html
<!-- 组件内部 -->
<view class="tab-control">
  <block wx:for="{{ tabs }}" wx:key="*this">
    <view class="item {{ currIndex === index ? 'active' : '' }}" + data-index="{{ index }}" bind:tap="onTabClick">
      {{ item }}
    </view>
  </block>
</view>

<script>
      Component({
        properties: {
          tabs: {
            type: Array,
            value: []
          }
        },
        data: {
          currIndex: 0
        },
        methods: {
          // 点击item,处理函数
          onTabClick(e) {
  +          const index = e.currentTarget.dataset.index // 获取data-index中的index
  +          this.setData({ // 设置data中的属性
              currIndex: index
            })
            // 向外发送currIndex
  +          this.triggerEvent('emitCurrIndex', this.data.currIndex) // 访问data中的属性currIndex
          }
        }
      })
</script>
html
<!-- 组件外部 -->
+ <case-tab-control tabs="{{ tabs }}" bind:emitCurrIndex="getCurrIndex"></case-tab-control>

<script>
      Page({
        data: {
          tabs: ['手机','电脑','硬盘','鼠标']
        },
        // 实现处理函数getCurrIndex
        getCurrIndex(e) {
  +        const index = e.detail // 获取组件内传递的参数
          console.log('点击了:', this.data.tabs[index]);
        }
      })
</script>

5、页面直接调用组件中的方法

可在父组件里调用 this.selectComponent(selector) ,获取子组件的实例对象。

调用时需要传入一个匹配选择器 selector,如:this.selectComponent(".my-component")。

html
<!-- 组件外部 -->
<button bind:tap="onChangeIndex">修改index</button>
+ <case-tab-control class="tab-control" tabs="{{ tabs }}" bind:emitCurrIndex="getCurrIndex"></case-tab-control>

<script>
  Page({
    // 在页面中调用组件中的方法,修改组件中的index
    onChangeIndex(e) {
  +    const tabControlInstance = this.selectComponent('.tab-control') // 获取组件实例
  +    tabControlInstance.innerTest(2) // 调用组件实例中的方法
    }
  })
</script>
html
<!-- 组件内部 -->
<script>
  Component({
    data: {
      currIndex: 0
    },
    methods: {
      // 内部被调用的方法
  +    innerTest(index) {
        console.log('组件内部被调用的方法:innerTest');
  +      this.setData({
  +        currIndex: index
        })
      }
    }
  })
</script>

image-20230215154229161

组件插槽

1、什么是插槽

slot 翻译为插槽:

  • 在生活中很多地方都有插槽,电脑的 USB 插槽,插板当中的电源插槽。
  • 插槽的目的是让我们原来的设备具备更多的扩展性。
  • 比如电脑的 USB 我们可以插入 U 盘、硬盘、手机、音响、键盘、鼠标等等。

组件的插槽:

  • 组件的插槽也是为了让我们封装的组件更加具有扩展性
  • 让使用者可以决定组件内部的一些内容到底展示什么。

栗子:移动网站中的导航栏。

  • 移动开发中,几乎每个页面都有导航栏。
  • 导航栏我们必然会封装成一个插件,比如 nav-bar 组件。
  • 一旦有了这个组件,我们就可以在多个页面中复用了。

image-20230214102321924

2、单个插槽的使用

除了内容和样式可能由外界决定之外,也可能外界想决定显示的方式

  • 比如我们有一个组件定义了头部和尾部,但是中间的内容可能是一段文字,也可能是一张图片,或者是一个进度条。

  • 在不确定外界想插入什么其他组件的前提下,我们可以在组件内预留插槽:

基本使用

html
<!-- 组件内部 -->
<view class="slot-single">
  <view class="header">Header</view>
  <view class="content">
+   <slot></slot>
  </view>
  <view class="footer">Footer</view>
</view>
html
<!-- 组件外部 -->
<slot-single> + <button>我是按钮</button> </slot-single>
<slot-single> + <text>我是文字</text> </slot-single>

解决小程序不支持插槽默认值

说明:和 Vue 不同,小程序中插槽不支持默认值

html
<!-- 组件内部 -->
<view class="slot-single">
  <view class="header">Header</view>
  + <view class="content"> + <slot></slot> </view> + <view class="default">我是插槽默认值</view>
  <view class="footer">Footer</view>
</view>

<style>
  .default {
    display: none;
  }
  +  /* 当content中为空时,其兄弟元素default显示 */
+  .content:empty + .default {
    display: block;
  }
</style>
html
<!-- 组件外部 -->
<slot-single> + <button>我是按钮</button> </slot-single>
<slot-single> + <text>我是文字</text> </slot-single>

image-20230215161337960

3、多个插槽的使用

有时候为了让组件更加灵活, 我们需要定义多个插槽

说明:

  • 组件内部:
    • slot 的 name 属性,定义了插槽的名称
    • options.multipleSlots: true :启用多插槽模式
  • 组价外部:
    • slot 属性,表示使用的是哪个插槽(此为 Vue 早起语法
html
<!-- 组件内部 -->
<view class="slot-multi">
  <view class="left"> + <slot name="left"></slot> </view>
  <view class="center"> + <slot name="center"></slot> </view>
  <view class="right"> + <slot name="right"></slot> </view>
</view>

<script>
      Component({
  +      options: {
  +        multipleSlots: true
        }
      })
</script>
html
<!-- 组件外部 -->
<slot-multi>
  + <view slot="left">左侧</view> + <view slot="center">内容</view> + <view slot="right">右侧</view>
</slot-multi>

image-20230215163328069

Behavior()

behaviors 是用于组件间代码共享的特性,类似于一些编程语言中的 “mixins”。

  • 每个 behavior 可以包含一组属性、数据、生命周期函数和方法;

  • 组件引用它时,它的属性、数据和方法会被合并到组件中,生命周期函数也会在对应时机被调用;

  • 每个组件可以引用多个 behavior ,behavior 也可以引用其它 behavior ;

语法

js
Behavior(Object: object)

参数

  • propertiesobject | map,组件的对外属性,是属性名到属性设置的映射表
  • dataobject,组件的内部数据,和 properties 一同用于组件的模板渲染
  • observersobject,组件数据字段监听器,用于监听 properties 和 data 的变化
  • methodsobject,组件的方法,包括事件响应函数和任意的自定义方法,关于事件响应函数的使用
  • behaviorsstring | array,类似于 mixins 和 traits 的组件间代码复用机制
  • 生命周期函数
  • createdfunction,组件生命周期函数 - 在组件实例刚刚被创建时执行,注意此时不能调用 setData
  • attachedfunction,组件生命周期函数 - 在组件实例进入页面节点树时执行
  • readyfunction,组件生命周期函数 - 在组件布局完成后执行
  • movedfunction,组件生命周期函数 - 在组件实例被移动到节点树另一个位置时执行
  • detachedfunction,组件生命周期函数 - 在组件实例被从页面节点树移除时执行
  • relationsobject,组件间关系定义
  • lifetimesobject,组件生命周期声明对象
  • pageLifetimesobject,组件所在页面的生命周期声明对象
  • definitionFilterfunction,定义段过滤器,用于自定义组件扩展

返回值

示例

html
<!-- 组件内部 -->

<!-- 组件的混入-定义一个计数器 -->
<view>当前计数:{{ counter }}</view>
<button bind:tap="increment">+1</button>
<button bind:tap="decrement">-1</button>

<script>
  +    import counterBehavior from '../../../../behaviors/counter.js'
      Component({
  +      behaviors: [counterBehavior]
      })
</script>
js
// behaviors/counter.js 页面

+    export default Behavior({
      data: {
        counter: 100
      },
      methods: {
        increment() {
          this.setData({ counter: this.data.counter + 1 })
        },
        decrement() {
          this.setData({ counter: this.data.counter - 1 })
        }
      }
    })

image-20230215171204174

组件的生命周期

组件的生命周期,指的是组件自身的一些函数,这些函数在特殊的时间点或遇到一些特殊的框架事件时被自动触发。

  • 其中,最重要的生命周期是 created attached detached ,包含一个组件实例生命流程的最主要时间点。

自小程序基础库版本 2.2.3 起,组件的的生命周期也可以在 lifetimes 字段内进行声明这是推荐的方式,其优先级最高

还有一些特殊的生命周期,它们并非与组件有很强的关联,但有时组件需要获知,以便组件内部处理。样的生命周期称为“组件所在页面的生命周期”,在 pageLifetimes 定义段中定义。

参数

  • 组件的生命周期(lifetimes)
  • lifetimesobject,组件生命周期声明对象,参见 组件生命周期
    • createdfunction,组件生命周期函数 - 在组件实例刚刚被创建时执行,注意此时不能调用 setData
    • attachedfunction,组件生命周期函数 - 在组件实例进入页面节点树时执行
    • readyfunction,组件生命周期函数 - 在组件布局完成后执行
    • movedfunction,组件生命周期函数 - 在组件实例被移动到节点树另一个位置时执行
    • detachedfunction,组件生命周期函数 - 在组件实例被从页面节点树移除时执行
  • 组件所在页面的生命周期
  • pageLifetimesobject,组件所在页面的生命周期声明对象,参见 组件生命周期
    • showfunction,组件所在的页面被展示时执行
    • hidefunction,组件所在的页面被隐藏时执行
    • resizefunction(size),组件所在的页面尺寸变化时执行

示例

js
Component({
  lifetimes: {
    created() {
      console.log('生命周期: created')
    },
    attached() {
      console.log('生命周期: attached')
    },
    detached() {
      console.log('生命周期: detached')
    }
  },
  pageLifetimes: {
    show() {
      console.log('页面生命周期: show')
    },
    hide() {
      console.log('页面生命周期: hide')
    },
    resize(size) {
      console.log('页面生命周期: resize', size)
    }
  }
})

Component 构造器

image-20230214102755223image-20230214102803800

API

网络请求

wx.request()

  • wx.request()(options),发起 HTTPS 网络请求

    • 参数: options

    • urlstring,(必填),开发者服务器接口地址

    • datastring | object | arrayBuffer,请求的参数

    • headerobject,设置请求的 header,header 中不能设置 Referer。content-type 默认为 application/json

    • timeoutnumber,超时时间,单位为毫秒。默认值为 60_000

    • methodOPTIONS | GET | HEAD | POST | PUT | DELETE | TRACE | CONNECT,(默认 GET),HTTP 请求方法

    • dataTypejson | 其他,(默认 json),返回的数据格式

    • responseTypetext | arraybuffer,(默认 text),响应的数据类型

    • enableHttp2boolean,开启 http2

    • enableQuicboolean,开启 quic

    • enableCacheboolean,开启 cache

    • enableHttpDNSboolean,是否开启 HttpDNS 服务。如开启,需要同时填入 httpDNSServiceId

    • httpDNSServiceldstring,HttpDNS 服务商 Id

    • enableChunkedboolean,开启 transfer-encoding chunked

    • forceCellularNetworkboolean,wifi 下使用移动网络发送请求

    • successfunction(res),接口调用成功的回调函数

      • 参数:res: {data, statusCode, header, cookies, errMsg}
    • failfunction(err),接口调用失败的回调函数

      • 参数:err: {errMsg, errno}
    • completefunction,接口调用结束的回调函数(调用成功、失败都会执行)

基本使用

html
<!-- page页面 -->

+ <learn-request houselist="{{ houselist }}"></learn-request>

<script>
    Page({
      data: {
        allCities: {},
        houselist: []
      },
  +    onLoad() {
  +      /* 网络请求的基本使用 */
  +      wx.request({
          url: 'http://123.207.32.32:1888/api/city/all',
          method: 'get',
          success: (res) => {
            this.setData({ allCities: res.data.data })
          },
          fail: (err) => {
            console.log(err)
          }
        })

  +      /* 网络请求的基本使用-携带参数 */
  +      wx.request({
          url: 'http://123.207.32.32:1888/api/home/houselist',
          data: {
            page: 1
          },
          success: (res) => {
            this.setData({ houselist: res.data.data })
          }
        })
      }
    })
</script>
html
<!-- 组件内部 -->
<view class="houselist">
  +
  <!-- 注意:此处wx:key=""中不能写成 "{{item.data.houseId}}" 或 "data.houseId" 或 "houseId",会报错 -->
  +
  <block wx:for="{{houselist}}" wx:key="index">
    <view class="item">
      <view class="item-inner">
        + <image class="album" src="{{item.data.image.url}}" alt="" mode="widthFix" />
        <view>{{item.data.houseName}}</view>
      </view>
    </view>
  </block>
</view>
<script>
      Component({
  +      properties: {
  +        houselist: {
            type: Array,
            value: []
          }
        }
      })
</script>

API 封装

1、封装成函数

js
function mrRequest(options) {
  return new Promise((resolve, reject) => {
    wx.request({
      ...options,
      success(res) {
        resolve(res.data)
      },
      fail: reject
    })
  })
}
export default mrRequest

使用 mrRequest-then 方法

js
/* 2、网络请求-封装函数 */
mrRequest({
  url: 'http://123.207.32.32:1888/api/city/all'
}).then((res) => {
  this.setData({ allCities: res.data })
})

mrRequest({
  url: 'http://123.207.32.32:1888/api/home/houselist',
  data: { page: this.data.nextPage }
}).then((res) => {
  const totalHouselist = [...this.data.houselist, ...res.data]
  this.setData({ houselist: totalHouselist })
  this.data.nextPage++
})

使用 mrRequest-async/await 方法(推荐

js
  onLoad() {
      /* 3、使用 async/await方式 */
      this.getAllCities()
      this.getHouselist()
  },

  onReachBottom() {
    this.getHouselist()
  },

  /* 发送请求,获取allCities */
  async getAllCities() {
    const res = await mrRequestFn({
      url: 'http://123.207.32.32:1888/api/city/all'
    })
    this.setData({ allCities: res.data })
  },

  /* 发送请求,获取houselist */
  async getHouselist() {
    const res = await mrRequestFn({
      url: 'http://123.207.32.32:1888/api/home/houselist',
      data: { page: this.data.nextPage }
    })
    const totalHouselist = [...this.data.houselist, ...res.data]
    this.setData({ houselist: totalHouselist })
    this.data.nextPage ++
  }

2、封装成类

js
    /* 封装成类 */
    class MrRequest {
+      constructor(baseUrl) {
+        this.baseUrl = baseUrl
      }
      request(options) {
        return new Promise((resolve, reject) => {
          wx.request({
            ...options,
 +           url: this.baseUrl + options.url,
            success: res => {
              resolve(res.data)
            },
            fail: reject
          })
        })
      }
      get(options) {
 +       return this.request({...options, method: 'GET'})
      }
      post(options) {
        return this.request({ ...options, method: 'POST' })
      }
      put(options) {
        return this.request({ ...options, method: 'PUT' })
      }
      delete(options) {
        return this.request({ ...options, method: 'DELETE' })
      }
      patch(options) {
        return this.request({ ...options, method: 'PATCH' })
      }
    }
    export const mrRequest = new MrRequest('http://123.207.32.32:1888/api')

使用 mrRequest

js
    /* 4、使用类封装的mrRequest发送请求 */
+    mrRequest.get({
+      url: '/city/all'
+    }).then(res => {
      console.log(res);
    })

网络请求域名配置

每个微信小程序需要事先设置通讯域名,小程序只可以跟指定的域名进行网络通信

  • 小程序登录后台 – 开发管理 – 开发设置 – 服务器域名;

服务器域名请在 「小程序后台 - 开发 - 开发设置 - 服务器域名」 中进行配置,配置时需要注意:

  • 域名只支持 https (wx.request、wx.uploadFile、wx.downloadFile) 和 wss (wx.connectSocket) 协议;
  • 域名不能使用 IP 地址(小程序的局域网 IP 除外)或 localhost
  • 可以配置端口,如 https://myserver.com:8080,但是配置后只能向 https://myserver.com:8080 发起请求。如果向 https://myserver.comhttps://myserver.com:9091 等 URL 请求则会失败。
  • 如果不配置端口。如 https://myserver.com,那么请求的 URL 中也不能包含端口,甚至是默认的 443 端口也不可以。如果向 https://myserver.com:443 请求则会失败。
  • 域名必须经过 ICP 备案
  • 出于安全考虑,api.weixin.qq.com 不能被配置为服务器域名,相关 API 也不能在小程序内调用。 开发者应将 AppSecret 保存到后台服务器中,通过服务器使用 getAccessToken 接口获取 access_token,并调用相关 API;
  • 不支持配置父域名,使用子域名。

展示弹窗

小程序中展示弹窗有四种方式:

  • wx.showToast()options,显示消息提示框

    • 参数:options
    • titlestring,(必填),提示的内容
    • maskboolean,(默认:false),是否显示透明蒙层,防止触摸穿透
    • iconsuccess | error | loading | none,图标
    • imagestring,自定义图标的本地路径,image 的优先级高于 icon
    • durationnumber,(默认:1500),提示的延迟时间
    • successfunction(res),接口调用成功的回调函数
    • failfunction(err),接口调用失败的回调函数
    • completefunction(res),接口调用结束的回调函数(调用成功、失败都会执行)
  • wx.showModal()options,显示模态对话框

    • 参数:options

    • titlestring,提示的标题

    • contentstring,提示的内容

    • showCancelboolean,(默认:true),是否显示取消按钮

    • cancelTextstring,(默认:取消),取消按钮的文字,最多 4 个字符

    • cancelColorstring,(默认:#000000),取消按钮的文字颜色,必须是 16 进制格式的颜色字符串

    • confirmTextstring,(默认:确定),确认按钮的文字,最多 4 个字符

    • confirmColorstring,(默认:#576B95),确认按钮的文字颜色,必须是 16 进制格式的颜色字符串

    • editableboolean,(默认:false),是否显示输入框

    • placeholderTextstring,显示输入框时的提示文本

    • successfunction(res),接口调用成功的回调函数

      • 参数:res
      • contentstring,editable 为 true 时,用户输入的文本
      • confirmboolean,为 true 时,表示用户点击了确定按钮
      • cancelboolean,为 true 时,表示用户点击了取消(用于 Android 系统区分点击蒙层关闭还是点击取消按钮关闭)
    • failfunction(err),接口调用失败的回调函数

    • completefunction(res),接口调用结束的回调函数(调用成功、失败都会执行)

  • wx.showLoading()options,显示 loading 提示框。需主动调用 wx.hideLoading 才能关闭提示框

    • 参数:opitons
    • titlestring,提示的内容
    • maskboolean,(默认:false),是否显示透明蒙层,防止触摸穿透
    • successfunction(res),接口调用成功的回调函数
    • failfunction(err),接口调用失败的回调函数
    • completefunction(res),接口调用结束的回调函数(调用成功、失败都会执行)
  • wx.showActionSheet()options,显示操作菜单

    • 参数:opitons

    • alertTextstring,警示文案

    • itemListstring[],按钮的文字数组,数组长度最大为 6

    • itemColorstring,(默认:#000000),按钮的文字颜色

    • successfunction(res),接口调用成功的回调函数

      • 参数 res
      • tapIndexnumber,用户点击的按钮序号,从上到下的顺序,从 0 开始
    • failfunction(err),接口调用失败的回调函数

    • completefunction(res),接口调用结束的回调函数(调用成功、失败都会执行)

js
  /* 展示消息提示框 */
  methods: {
    onToast() {
      wx.showToast({
        title: 'showToast',
        icon: 'loading',
        image: '/assets/tabbar/home_active.png',
        duration: 1500,
        mask: true,
        success:res => {
          console.log('success' + res);
        },
        fail: err => {
          console.log('fail' + err);
        }
      })
    },
    onLoading() {
      wx.showLoading({
        title: '加载中...',
        mask: true,
        success: res => {
          console.log('成功:' + res);
          wx.hideLoading()
        }
      })
    },
    onModal() {
      wx.showModal({
        title: '删除文件',
        content: '确定删除文件?',
        editable: true,
        cancelText: '我再想想',
        confirmText: '决定了',
        complete: (res) => {
          if (res.cancel) {
            console.log('取消删除文件~', res.content);
          }

          if (res.confirm) {
            console.log('确定删除文件~', res.content);
          }
        }
      })
    },
    onActionSheet() {
      wx.showActionSheet({
        alertText: '选一个吧~',
        itemList: ['苹果','梨子','香蕉','荔枝','火龙果'],
        success: res => {
          console.log(res, res.tapIndex);
        }
      })
    }
  }

image-20230216160414524

分享功能

分享是小程序扩散的一种重要方式,小程序中有两种分享方式:

  • 方式一:点击右上角的菜单按钮,之后点击转发
  • 方式二:点击某一个按钮,直接转发

当我们转发给好友一个小程序时,通常小程序中会显示一些信息:

  • 如何决定这些信息的展示呢?通过 onShareAppMessage
  • 监听用户点击页面内转发按钮(button 组件 open-type="share")或右上角菜单“转发”按钮的行为,并自定义转发内容。
  • 此事件处理函数需要 return 一个 Object,用于自定义转发内容;

语法

  • onShareAppMessagefunction(object),监听用户点击页面内转发按钮(button 组件 open-type="share")或右上角菜单“转发”按钮的行为,并自定义转发内容
    • 参数:object
    • frombutton | menu,转发事件来源。
    • targetobject,如果 from 值是 button,则 target 是触发这次转发事件的 button,否则为 undefined
    • webViewUrlstring,页面中包含 web-view 组件时,返回当前 web-view 的 url

    • 返回值:object
    • titlestring,转发标题(默认:当前小程序名称)
    • pathstring,转发路径,(默认:当前页面 path ,必须是以 / 开头的完整路径)
    • imageUrlstring,自定义图片路径,可以是本地文件路径、代码包文件路径或者网络图片路径。支持 PNG 及 JPG。显示图片长宽比是 5:4。
    • promise:``,如果该参数存在,则以 resolve 结果为准,如果三秒内不 resolve,分享会使用上面传入的默认参数
js
Page({
  onShareAppMessage() {
    return {
      title: '我的小程序',
      path: '/pages/D05-api/D05-api',
      imageUrl: '/assets/tabbar/cart.png'
    }
  }
})

image-20230215175408904

获取设备信息

在开发中,我们需要经常获取当前设备的信息,用于手机信息或者进行一些适配工作

小程序提供了相关个 API:wx.getSystemInfo(Object object)

语法

  • wx.getSystemInfo()object,获取系统信息。由于历史原因,wx.getSystemInfo 是异步的调用格式,但是是同步返回,需要异步获取系统信息请使用 wx.getSystemInfoAsync
    • 参数:object
    • successfunction(res),接口调用成功的回调函数
      • 参数 res(部分常用):{screenWidth, screenHeight, windowWidth, windowHeight}

    • failfunction(err),接口调用失败的回调函数
    • completefunction(res),接口调用结束的回调函数(调用成功、失败都会执行)
js
  /* 2、获取设备信息 */
  onGetSystemInfo() {
    wx.getSystemInfo({
      success: function(res) {
        console.log(res);
      }
    })
  }

image-20230216175542372

获取位置信息

开发中我们需要经常获取用户的位置信息,以方便给用户提供相关的服务

我们可以通过 API 获取:wx.getLocation(Object object)

语法

  • wx.getLocation()object,获取当前的地理位置、速度
    • 参数;object
    • typewgs84 | gcj02,(默认:wgs84),wgs84 返回 gps 坐标,gcj02 返回可用于 wx.openLocation 的坐标
    • altitudeboolean,(默认:false),传入 true 会返回高度信息,由于获取高度需要较高精确度,会减慢接口返回速度
    • isHighAccuracyboolean,(默认:false),开启高精度定位
    • highAccuracyExpireTimenumber,高精度定位超时时间(ms),指定时间内返回最高精度,该值 3000ms 以上高精度定位才有效果
    • successfunction(res),接口调用成功的回调函数
      • 参数 res
      • latitudenumber,纬度,范围为 -90~90,负数表示南纬
      • longitudenumber,经度,范围为 -180~180,负数表示西经
      • speednumber,速度,单位 m/s
      • accuracynumber,位置的精确度,反应与真实位置之间的接近程度,可以理解成 10 即与真实位置相差 10m,越小越精确
      • altitudenumber,高度,单位 m
      • verticalAccuracynumber,垂直精度,单位 m(Android 无法获取,返回 0)
      • horizontalAccuracynumber,水平精度,单位 m
    • failfunction(err),接口调用失败的回调函数
    • completefunction(res),接口调用结束的回调函数(调用成功、失败都会执行)

示例

js
  /* 获取位置信息 */
  onGetLocation() {
    wx.getLocation({
      success(res) {
        console.log(res);
      }
    })
  }

*注意:*对于用户的关键信息,需要获取用户的授权后才能获得

app.json 中设置如下:

js
"permission" {
    "scope.userLocation": {
        "desc": "获取您的位置信息"
    }
}

image-20230216181450173

Storage 存储

在开发中,某些常见我们需要将一部分数据存储在本地:比如 token、用户信息等。

  • 小程序提供了专门的 Storage 用于进行本地存储。

同步存取数据的方法:

  • wx.setStorageSync(key, data):``,将数据存储在本地缓存中指定的 key 中。会覆盖掉原来该 key 对应的内容

    • 参数:key, data
    • keystring,本地缓存中指定的 key
    • dataany,需要存储的内容。只支持原生类型、Date、及能够通过JSON.stringify序列化的对象
  • wx.getStorageSync(key):``,从本地缓存中同步获取指定 key 的内容

    • 参数:key
    • keystring,本地缓存中指定的 key
    • 返回值:any
    • anyany,key 对应的内容
  • wx.removeStorageSync(key):``,从本地缓存中移除指定 key。

    • 参数:key
    • keystring,本地缓存中指定的 key
  • wx.clearStorageSync():``,清理本地数据缓存。

异步存储数据的方法:

语法

  • wx.setStorage(object):``,将数据存储在本地缓存中指定的 key 中。会覆盖掉原来该 key 对应的内容

    • 参数:object
    • keystring,本地缓存中指定的 key
    • dataany,需要存储的内容。只支持原生类型、Date、及能够通过JSON.stringify序列化的对象
    • encryptboolean,(默认:false),是否开启加密存储。只有异步的 setStorage 接口支持开启加密存储。最低版本 2.21.3
    • successfunction(res),接口调用成功的回调函数
    • failfunction(err),接口调用失败的回调函数
    • completefunction(res),接口调用结束的回调函数(调用成功、失败都会执行)
  • wx.getStorage(object):``,从本地缓存中异步获取指定 key 的内容

    • 参数:object
    • keystring,本地缓存中指定的 key
    • encryptboolean,(默认:false),是否开启加密存储。只有异步的 setStorage 接口支持开启加密存储。最低版本 2.21.3
    • successfunction(res),接口调用成功的回调函数
    • failfunction(err),接口调用失败的回调函数
    • completefunction(res),接口调用结束的回调函数(调用成功、失败都会执行)
  • wx.removeStorage(object):``,从本地缓存中移除指定 key。

    • 参数:object
    • keystring,本地缓存中指定的 key
    • successfunction(res),接口调用成功的回调函数
    • failfunction(err),接口调用失败的回调函数
    • completefunction(res),接口调用结束的回调函数(调用成功、失败都会执行)
  • wx.clearStorage(object):``,清理本地数据缓存。

    • 参数:object
    • successfunction(res),接口调用成功的回调函数
    • failfunction(err),接口调用失败的回调函数
    • completefunction(res),接口调用结束的回调函数(调用成功、失败都会执行)
  • :``,

示例

同步存储

js
  onSetStorage() {
+    wx.setStorageSync('name', '张飞')
    wx.setStorageSync('age', 38)
    wx.setStorageSync('friends', ['刘备', '关羽'])
  },
  onGetStorage() {
+    const name = wx.getStorageSync('name')
    const age = wx.getStorageSync('age')
    const friends = wx.getStorageSync('friends')
    console.log(name, age, friends);
  },
  onRemoveStorage() {
+    wx.removeStorageSync('name')
  },
  onClearStorage() {
+    wx.clearStorageSync()
  }

异步存储

js
onSetStorage() {
+    wx.setStorage({
      key: 'name',
      data: '张飞',
      encrypt: true,
      success(res) { console.log(res); }
    })
    wx.setStorage({
      key: 'age',
      data: 21,
      encrypt: true,
      success(res) { console.log(res); }
    })
  },
  onGetStorage() {
+    wx.getStorage({
      key: 'name',
      encrypt: true,
      success: res => {
        console.log(res);
      }
    })
  },
  onRemoveStorage() {
+    wx.removeStorage({
      key: 'name',
      success: res => {
        console.log(res);
      }
    })
  },
  onClearStorage() {
+    wx.clearStorage({
      success: res => {
        console.log(res);
      }
    })
  }

界面跳转

界面的跳转有两种方式:

  • 通过navigator组件
  • 通过wx的API跳转

这里我们先以 wx 的 API 作为讲解

API

  • wx.navigateTo(object):``,保留当前页面,跳转到应用内的某个页面。但是不能跳到 tabbar 页面。使用 wx.navigateBack 可以返回到原页面。小程序中页面栈最多十层。
    • 参数:object
    • urlstring,(必填),需要跳转的应用内非 tabBar 的页面的路径 (代码包路径), 路径后可以带参数。参数与路径之间使用 ? 分隔,参数键与参数值用 = 相连,不同参数用 & 分隔;如 'path?key=value&key2=value2'
    • eventsobject: {callbackFn,...},页面间通信接口,用于监听被打开页面发送到当前页面的数据。基础库 2.7.3 开始支持。
    • successfunction(res),接口调用成功的回调函数
    • failfunction(err),接口调用失败的回调函数
    • completefunction(res),接口调用结束的回调函数(调用成功、失败都会执行)
  • wx.navigateBack(object):``,关闭当前页面,返回上一页面或多级页面。可通过 getCurrentPages 获取当前的页面栈,决定需要返回几层。
    • 参数:object
    • deltanumber,(默认:1),返回的页面数,如果 delta 大于现有页面数,则返回到首页
    • successfunction(res),接口调用成功的回调函数
    • failfunction(err),接口调用失败的回调函数
    • completefunction(res),接口调用结束的回调函数(调用成功、失败都会执行)
  • wx.redirectTo(object):``,关闭当前页面,跳转到应用内的某个页面。但是不允许跳转到 tabbar 页面
    • 参数:object
    • urlstring,(必填),需要跳转的应用内非 tabBar 的页面的路径 (代码包路径), 路径后可以带参数。参数与路径之间使用 ? 分隔,参数键与参数值用 = 相连,不同参数用 & 分隔;如 'path?key=value&key2=value2'
    • successfunction(res),接口调用成功的回调函数
    • failfunction(err),接口调用失败的回调函数
    • completefunction(res),接口调用结束的回调函数(调用成功、失败都会执行)
  • wx.switchTab(object):``,跳转到 tabBar 页面,并关闭其他所有非 tabBar 页面
    • 参数:object
    • urlstring,(必填),需要跳转的 tabBar 页面的路径 (代码包路径)(需在 app.json 的 tabBar 字段定义的页面),路径后不能带参数。
    • successfunction(res),接口调用成功的回调函数
    • failfunction(err),接口调用失败的回调函数
    • completefunction(res),接口调用结束的回调函数(调用成功、失败都会执行)
  • wx.reLaunch(object):``,关闭所有页面,打开到应用内的某个页面
    • 参数:object
    • url:``,(必填),需要跳转的应用内页面路径 (代码包路径),路径后可以带参数。参数与路径之间使用?分隔,参数键与参数值用=相连,不同参数用&分隔;如 'path?key=value&key2=value2'
    • successfunction(res),接口调用成功的回调函数
    • failfunction(err),接口调用失败的回调函数
    • completefunction(res),接口调用结束的回调函数(调用成功、失败都会执行)
  • :``,

wx.navigateTo(Object object):保留当前页面,跳转到应用内的某个页面,但是不能跳到 tabbar 页面

js
// 起始页
    /* 点击跳转 */
      onJump() {
        const name = this.data.name
        const age = this.data.age
+        wx.navigateTo({
+          url: `/pages/detail/detail?name=${name}&age=${age}`,
        })

      }
js
// 跳转到的页面
+      onLoad(query) {
+        const { name, age } = query
+        this.setData({
          name,
          age
        })
      }

wx.navigateBack(Object object):关闭当前页面,返回上一页面或多级页面

js
  onJumpBack() {
+    wx.navigateBack({
+      delta: 2 // 跳转2层
    })
  }

数据传回

如何在界面跳转过程中我们需要相互传递一些数据,应该如何完成呢?

1、数据传递-早期的方法

  • 首页 -> 详情页:使用 URL 中的 query 字段
  • 详情页 -> 首页:在详情页内部拿到首页的页面对象,直接修改数据

image-20230215180000769

js
// 跳转到的页面
  onJumpBack() {
    wx.navigateBack()

    // 返回的时候,传递数据回去
+    const pages = getCurrentPages()
+    const prevPage = pages[pages.length - 2]
+    prevPage.setData({ message: {title: 'Hello', content: '返回的内容~'} })
  }
html
<!-- 原来的页面 -->
<!-- 注意:在微信中不能在差值语句{{}}中直接写js文件中的函数调用,只能用在wxs中定义的函数 -->
+ <view>{{format.objToStr(message)}}</view>

+
<wxs module="format">
  + function objToStr(obj) { + return JSON.stringify(obj) } + module.exports = { + objToStr: objToStr }
</wxs>

注意: 如果想让不同方式在返回上一页时,都可以传回参数的话,可以在onUnload生命周期函数中传递参数

image-20240711141420489

2、数据传递-events 参数对象

eventsobject: {callbackFn,...},页面间通信接口,用于监听被打开页面发送到当前页面的数据。基础库 2.7.3 开始支持。

如果一个页面由另一个页面通过 wx.navigateTo 打开,这两个页面间将建立一条数据通道:

  • 被打开的页面可以通过 this.getOpenerEventChannel() 方法来获得一个 EventChannel 对象;
  • wx.navigateTosuccess 回调中也包含一个 EventChannel 对象。

这两个 EventChannel 对象间可以使用 emiton 方法相互发送、监听事件。

js
// 原来的页面
  /* 点击跳转 */
  onJump() {
    const name = this.data.name
    const age = this.data.age
    wx.navigateTo({
      url: `/pages/detail/detail?name=${name}&age=${age}`,
+      events: {
+        backData: data => {
+          this.setData({ message: data })
        }
      }
    })
  }
js
// 跳转到的页面
    // 2、方法二:使用events,传递数据回去
+    const ec = this.getOpenerEventChannel()
+    ec.emit('backData', { title: 'events', content: '通过events返回的数据~' })

界面跳转的方式

<navigator> 组件主要就是用于界面的跳转的,也可以跳转到其他小程序中:

API

  • <navigator>组件,页面链接
    • 属性(部分):
    • targetself | miniProgram,在哪个目标上发生跳转,默认当前小程序
    • urlstring,当前小程序内的跳转链接,可以携带 query 格式参数
    • open-typenavigate | navigateBack | redirect | switchTab | reLaunch | exit ,跳转方式
    • deltanumber,(默认:1),当 open-type 为 'navigateBack' 时有效,表示回退的层数
    • app-idstring,要打开的小程序 appId,当target="miniProgram"open-type="navigate"时有效
    • pathstring,打开的页面路径,如果为空则打开首页,当target="miniProgram"open-type="navigate"时有效

示例

html
// 原来的页面
<!-- 方式二:navigator组件 -->
<navigator url="/pages/detail/detail?name=ZhangSan&age=15" open-type="navigate">navigator跳转</navigator>
html
// 跳转到的页面 <navigator open-type="navigateBack">navigate返回</navigator>

音频

InnerAudioContext

InnerAudioContext 实例,可通过 wx.createInnerAudioContext 接口获取实例。

语法

js
wx.createInnerAudioContext()

API

  • 属性
  • src:``,音频资源的地址,用于直接播放
  • startTime:``,开始播放的位置(单位:s),默认为 0
  • autoplay:``,是否自动开始播放,默认为 false
  • loop:``,是否循环播放,默认为 false
  • obeyMuteSwitch:``,是否遵循系统静音开关,默认为 true。从 2.3.0 版本开始此参数不生效
  • volume:``,音量。范围 0~1。默认为 1
  • playbackRate:``,播放速度。范围 0.5-2.0,默认为 1
  • duration:``,当前音频的长度(单位 s)。只有在当前有合法的 src 时返回(只读)
  • currentTime:``,当前音频的播放位置(单位 s)。只有在当前有合法的 src 时返回,时间保留小数点后 6 位(currentTime 属性在基础库 2.26.2 之前只读,基础库 2.26.2 开始可读可写,改变 currentTime 值等同于调用 seek)
  • paused:``,当前是是否暂停或停止状态(只读)
  • buffered:``,音频缓冲的时间点,仅保证当前播放时间点到此时间点内容已缓冲(只读)
  • referrerPolicyorigin | no-referrer,origin: 发送完整的 referrer ; no-referrer: 不发送。

  • 方法
  • InnerAudioContext.play():``,播放
  • InnerAudioContext.pause():``,暂停。暂停后的音频再播放会从暂停处开始播放
  • InnerAudioContext.stop():``,停止。停止后的音频再播放会从头开始播放。
  • InnerAudioContext.seek(positionNum):``,跳转到指定位置,单位 s
  • InnerAudioContext.destroy():``,销毁当前实例

  • 事件监听
  • InnerAudioContext.onCanplay(listenerFn):``,监听音频进入可以播放状态的事件。但不保证后面可以流畅播放
  • InnerAudioContext.offCanplay(listenerFn):``,移除音频进入可以播放状态的事件的监听函数
  • InnerAudioContext.onPlay(listenerFn):``,监听音频播放事件
  • InnerAudioContext.offPlay(listenerFn):``,移除音频播放事件的监听函数
  • InnerAudioContext.onPause(listenerFn):``,监听音频暂停事件
  • InnerAudioContext.offPause(listenerFn):``,移除音频暂停事件的监听函数
  • InnerAudioContext.onStop(listenerFn):``,监听音频停止事件
  • InnerAudioContext.offStop(listenerFn):``,移除音频停止事件的监听函数
  • InnerAudioContext.onEnded(listenerFn):``,监听音频自然播放至结束的事件
  • InnerAudioContext.offEnded(listenerFn):``,移除音频自然播放至结束的事件的监听函数
  • InnerAudioContext.onTimeUpdate(listenerFn):``,监听音频播放进度更新事件
  • InnerAudioContext.offTimeUpdate(listenerFn):``,移除音频播放进度更新事件的监听函数
  • InnerAudioContext.onError(listenerFn):``,监听音频播放错误事件
  • InnerAudioContext.offError(listenerFn):``,移除音频播放错误事件的监听函数
  • InnerAudioContext.onWaiting(listenerFn):``,监听音频加载中事件。当音频因为数据不足,需要停下来加载时会触发
  • InnerAudioContext.offWaiting(listenerFn):``,移除音频加载中事件的监听函数
  • InnerAudioContext.onSeeking(listenerFn):``,监听音频进行跳转操作的事件
  • InnerAudioContext.offSeeking(listenerFn):``,移除音频进行跳转操作的事件的监听函数
  • InnerAudioContext.onSeeked(listenerFn):``,监听音频完成跳转操作的事件
  • InnerAudioContext.offSeeked(listenerFn):``,移除音频完成跳转操作的事件的监听函数

小程序登录

小程序登录解析

为什么需要用户登录?

  • 增加用户的粘性和产品的停留时间;

如何识别同一个小程序用户身份?

  • 认识小程序登录流程
  • openidunionid
  • 获取 code
  • 换取 authToken

用户身份多平台共享

  • 账号绑定
  • 手机号绑定

小程序用户登录的流程

image-20230215180147664

image-20230215180204108

对比 WXML、HTML

WXMLHTML相同不同
viewdiv
cover-view
grid-view
list-view
movable-view
scroll-view
swiper
swiper-item
page-container
textspan
buttonbutton
blocktemplate

错误日志

1、从任务栏固定图标启动微信开发者工具会导致调试器显示空白

image-20230113220304993

解决: 从其他地方(桌面、开始)启动编辑器