小程序学习笔记

辰漪
2022-09-28 / 0 评论 / 14 阅读 / 正在检测是否收录...

小程序基本了解

小程序与普通网页的区别

  • 运行环境不同

    • 网页运行在浏览器环境中
    • 小程序运行在微信环境中
  • API不同

    • 运行环境不同,这也就导致小程序无法调用DOM和BOM的API。
    • 但是可以调用微信环境中提供的各种API
  • 开发模式不同

    • 网页的开发模式:浏览器 + 代码编辑器
    • 小程序: 申请小程序开发者账号,安装小程序开发者工具,创建和配置小程序项目

小程序项目结构

|-- project_02   // 根目录
    |-- .eslintrc.js // eslint配置
    |-- app.js // 小程序入口文件
    |-- app.json // 全局配置文件
    |-- app.wxss // 全局样式文件
    |-- project.config.json // 项目配置文件
    |-- project.private.config.json // 项目私有配置文件 会覆盖 project.config.json相同字段
    |-- sitemap.json // 配置页面能否被微信索引
    |-- pages // 存放页面的文件夹
    |   |-- index 
    |   |   |-- index.js // 页面js文件(存放页面数据,事件处理函数等)
    |   |   |-- index.json // 页面配置文件(配置页面窗口外观,表现)
    |   |   |-- index.wxml // 页面模板文件
    |   |   |-- index.wxss // 页面样式文件
    |   |-- logs
    |       |-- logs.js
    |       |-- logs.json
    |       |-- logs.wxml
    |       |-- logs.wxss
    |-- utils // 存放工具函数的文件夹
        |-- util.js

小程序配置文件

  • app.json

全局页面配置文件,配置页面的窗口,页面的路径等

{
  "pages":[ 
    "pages/index/index",
    "pages/logs/logs"
  ],
  "window":{
    "backgroundTextStyle":"light",
    "navigationBarBackgroundColor": "#fff",
    "navigationBarTitleText": "Weixin",
    "navigationBarTextStyle":"black"
  },
  "style": "v2",
  "sitemapLocation": "sitemap.json"
}

pages节点 ---> 小程序的页面路径,在此配置会默认生成页面的目录结构

window节点 ---> 配置页面的背景色,文字颜色等,全局生效

style节点 ---> 定义小程序组件使用的样式版本

sitemapLocation节点 --> 指定sitemap.json的位置

  • project.config.json

项目的配置文件,用来配置跟项目相关的配置

setting节点 ---> 定义编译相关的配置

projectname ---> 配置项目的名称

appid ---> 配置小程序的appid

  • sitemap.json

配置页面是否被微信搜索到。

{
  "desc": "关于本文件的更多信息,请参考文档 https://developers.weixin.qq.com/miniprogram/dev/framework/sitemap.html",
  "rules": [{
  "action": "allow", // 允许索引  disallow 不允许索引
  "page": "*" // * 表示所有的页面
  }]
}

在项目配置文件peoject.config.json中的setting节点添加 "checkSiteMap": false, 可以隐藏掉索引情况提示信息

  • 页面的 .json文件

可以对当前页面的窗口外观样式进行配置

覆盖全局的app.json中window节点下的配置

小程序代码构成

如何创建一个页面

  • 直接在app.json里边的pages节点下新增页面的路径,项目会自动创建对应的页面目录
  • 在pages文件夹右键,新建文件夹,右键新建的文件夹,新建page,输入页面名后会自动生成页面需要的文件,此时app.json的pages节点也会自动添加这个页面路径

修改首页对应的页面

只需要将pages节点中的路径位置调整一下顺序,第一个就表示首页的页面

wxml和html的区别

  • 标签名称不同

    • html(div, span, a, img)
    • wxml(view, text, navigator, image)
  • 属性不同

    • <a href="#">
    • <navigator url="/pages/home/home"></navigator>
  • 支持类似于vue的模板语法

    • 数据绑定
    • 列表渲染
    • 条件渲染

wxss和css的区别

  • 新增rpx单位

    • css中需要手动对像素px进行换算,例如:rpx单位
    • rpx则可以在不同尺寸的屏幕上自动进行换算
  • 提供了全局样式和局部样式

    • app.wxss全局样式会作用于所有的页面
    • 局部页面的 .wxss 样式只针对于当前页面的样式

小程序中的js文件

  • app.js

    • 是整个小程序的入口文件,通过调用App()函数启动小程序
  • 页面的 .js文件

    • 是页面的入口文件,通过调用Page()函数创建并运行页面
  • 普通的 .js文件

    • 普通的功能函数模块,封装一些公用的函数或者属性,供其他页面使用

小程序中的组件

小程序组件分类

  • 视图容器
  • 基础内容
  • 表单组件
  • 导航组件
  • 媒体组件
  • map地图组件
  • canvas画布组件
  • 开放能力
  • 无障碍访问

常用的视图容器组件

  • view组件

    • 类似于div,用来布局
  • scroll-view组件

    • 可以滚动的div,用来实现列表滚动
  • swiper和swiper-item组件

    • 轮播图容器(swiper)和里边的每一项轮播图(swiper-item),用来实现轮播图

常用的基础内容组件

  • text组件

    • 普通的文本组件,类似于span
  • rich-text

    • 富文本组件,支持html字符串转换成wxml结构
<text>13213212</text>
<rich-text nodes="<h1>12313</h1>"></rich-text>

其他常用的组件

  • button组件

    • 按钮组件,更丰富的功能,可通过open-type属性调用微信的功能(客服,转发,用户授权等)
  • image组件

    • 图片组件,存放图片的容器
  • navigator组件

    • 页面导航组件,类似于a

小程序中的api

  • 事件监听api

    • 以on开头,监听某个事件
    • 例如:wx.onWindowResize(() => {}) 监听窗口尺寸的变化
  • 同步api

    • 以Sync结尾,可以直接接受函数返回值
    • 例如:wx.setStorageSync('key', 'value') 本地存储
  • 异步的api

    • 不带Sync的api,需要通过success fail compalete接收
    • 例如:wx.request()发送一个网络请求 需要通过success回调函数接收数据

小程序语法

数据绑定,mustache语法

// js
Page({
    data: {
        // 在这里进行数据绑定
        num: 1,
        src: 'http://wwjjds.com/1.png'
    }
})

// wxml
在wxml模板中 使用mustache语法进行渲染  双大括号的形式
// 绑定内容
<view>{{ num }}</view>
// 绑定属性
<image src="{{ src }}"></image>
// 表达式
<view>{{ num > 1 ? '大于1' : '小于等于1' }}</view>
// 算术运算
<view>{{ num * 100 }}</view>

事件绑定

tap点击事件 bindtap 或者bind:tap

input文本框输入事件 bindinput 或者bind:input

change状态改变时触发 bindchange 或者bind:change

事件对象的属性(event)

属性类型说明
typeString事件类型
timeStampInteger页面打开到触发这个事件经过的时间,毫秒数
targerObject触发事件的组件的一些属性值集合
currentTargerObject当前组件的一些属性值集合
detailObject额外的一些信息
touchesArray触摸事件,当前停留在屏幕上的触摸点信息数组
changedTouchesArray触摸事件,当前变化的触摸点信息数组
  • target

    • target指的是事件触发的源头
  • currentTarget

    • currentTarget指的是正在触发的那个元素
// js
Page({
  tapHandler(e) {
    console.log(e, 'event');
  }
})
<!-- wxml -->
<view class="mine-container" data-count="{{ 2 }}" bindtap="tapHandler">
  <button type="primary" data-num="{{ 1 }}">按钮</button>
</view>

点击按钮,此时事件向上冒泡,e.target指的就是这个button按钮,即事件触发的源头,可以从e. target . dataset. num 拿到num值。

e.currentTarget是正在触发事件的那个元素 view,可以e. currentTarget. dataset. count拿到count值

为data进行赋值

调用this.setData()函数为data中的属性进行赋值操作

  btnClick (e) {
    console.log(e);
    // 修改data中的数据
    this.setData({
        // 要修改的属性  :  修改的值  通过this.data拿到data中的数据
      num: this.data.num + 1
    })
  },

事件传参

通过在wxml模板上绑定属性,绑定方式为 data-*,在事件对象中通过e. target. dataset对象拿到对应的属性

// js
Page({
  tapHandler(e) {
    console.log(e, 'event');
    console.log(e.target.dataset.num) // button绑定的属性data-num
  }
})
<!-- wxml -->
<view class="mine-container" data-count="{{ 2 }}" bindtap="tapHandler">
  <button type="primary" data-num="{{ 1 }}">按钮</button>
</view>

input事件

bindinput进行绑定 通过e.detail.value拿到最新的值

// js
Page({
  data: {
    inputValue: ''
  },
  inputChange(e) {
    console.log(e.detail.value); // 文本框中的值
    this.setData({
      inputValue: e.detail.value // 实现双向绑定 修改文本框数据 data中的数据也一并修改
    })
  },
})
<!-- wxml -->
<input value="{{ inputValue }}" bindinput="inputChange"/>

条件渲染

  • wx:if
  • wx:elif
  • wx:else
// js
Page({
  data: {
    sex: 1
  }
})
<!-- wxml -->
<view wx:if="{{ sex === 1 }}">男</view>
<view wx:elif="{{ sex === 0 }}">女</view>
<view wx:else> 未知 </view>

结合block标签进行条件渲染,block标签不会渲染到页面中,只是起到了包裹的作用

<!-- wxml -->
<block wx:if="{{ true }}">
  <view>view1</view>
  <view>view2</view>
</block>
<view wx:if="{{ true }}">
  <view>view1</view>
  <view>view2</view>
</view>
  • hidden
<view hidden="{{ true }}">hidden隐藏</view>

wx:if和hidden的区别

hidden 通过display: none进行隐藏,wx:if会创建或者移除该元素

列表渲染

wx:for

默认索引是index,数据项是item

通过属性 wx:for-index="" 修改对应的索引变量

通过属性 wx:for-item="" 修改对应的数据项变量

通过wx:key提高渲染效率,不需要mustache语法,索引index,如果每一项有id的话直接写id属性

// js
Page({
  data: {
    list: [
      {id: 1, name: '苹果'},
      {id: 2, name: '草莓'},
      {id: 3, name: '鸭梨'}
    ]
  }
})
<!-- wxml -->
<text>------------列表渲染------------</text>
<view wx:for="{{ list }}" wx:key="id">
  <text>名称:{{ item.name }}</text>
  <view>索引:{{ index }}</view>
</view>

<text>------------列表渲染 自定义index和item------------</text>
<view wx:for="{{ list }}" wx:key="id" wx:for-index="ind" wx:for-item="ite">
  <text>名称:{{ ite.name }}</text>
  <view>索引:{{ ind }}</view>
</view>

rpx单位

适配不同屏幕尺寸

rpx实现原理:

  • rpx把所有设备屏幕划分为750份,即宽度为750rpx,在小屏幕上,1rpx宽度较小,在大屏幕上,宽度较大。
  • 小程序在运行时,会把rpx单位的样式换成对应的px单位,实现屏幕的适配。
设备rpx换算px(屏幕宽度 / 750)px换选rpx(750 / 屏幕宽度)
iPhone51rpx = 0.42px1px = 2.34rpx
iPhone61rpx = 0.5px1px = 2rpx
iPhone6 Plus1rpx = 0.552px1px = 1.81rpx

iPhone6 屏幕宽度 375px 物理像素750,rpx等分750物理像素

即 1rpx = 1物理像素 = 0.5px

一般会采用iPhone6设计稿, rpx是整数

小程序全局配置

app.json全局配置文件

常用配置项节点

  • pages

    • 配置小程序的页面
  • window

    • 配置页面窗口外观
  • tabBar

    • 设置小程序的tabBar
  • style

    • 小程序组件使用的样式版本号(v2)最新版

window节点

小程序窗口可以分为三类:

  • navigationBar

    • 导航栏区域
  • background

    • 背景区域,下拉刷新时可见
  • wxml

    • 页面的主体布局区域

l8leblhf.png

常用的window属性

属性名类型默认值说明
navigationBarTitleTextString字符串导航栏标题文本内容
navigationBarBackgroundColorHexColor#000000导航栏背景色,16进制颜色
navigationBarTextStyleStringwhite导航栏标题颜色,仅支持white/black
backgroundColorHexColor#ffffff窗口背景色,下拉才会显示
backgroundTextStyleStringdark下拉loding的样式,仅支持dark/light
enablePullDownRefreshBooleanfalse是否开启全局下拉刷新
onReachBottomDistanceNumber50上拉触底事件距离页面底部的距离,单位px

tabBar节点

tabBar两种:底部tabBar,顶部tabBar

tabBar至少要配置两项,最多五个

顶部的yabBar不会显示icon图标,只显示文本

tabBar属性

属性类型必填默认值说明
positionStringbottomtabBar位置 仅支持bottom/top
borderStyleStringblacktabBar上边框的颜色 仅支持black/white
colorHexColor tabBar文本,未选中时的颜色
selectedColorHexColor tabBar文本,选中时的颜色
backgroundColorHexColor tabBar的背景色
listArray tabBar的列表,最少两个,最多五个

list数组对象

  • pagePath

    • tab对应的页面路径
  • text

    • tab对应的文本
  • iconPath

    • tab对应的图标
  • selectedIconPath

    • tab选中时的图标

// // app.json
{
  "pages": [
    "pages/mine/mine",
    "pages/index/index",
    "pages/logs/logs",
    "pages/home/home"
  ],
  "window": {
    "backgroundColor": "#f0f0f0", // 下拉窗口背景色 16进制颜色
    "backgroundTextStyle": "dark", // 下拉小圆点的样式  dark / light
    "navigationBarBackgroundColor": "#ff00ff", // 导航栏背景色 16进制颜色
    "navigationBarTitleText": "我的小程序", // 导航栏标题文本
    "navigationBarTextStyle": "white", // 导航栏标题文本样式 仅支持white/black
    "enablePullDownRefresh": true, // 是否开启下拉刷新 全局生效
    "onReachBottomDistance": 100 // 上拉触底事件,距离底部的距离   100px
  },
  "tabBar": { 
    "position": "bottom", // tab位置 bottom/top
    "color": "#000", // tab未选中的文本颜色
    "selectedColor": "#f12f00", // tab选中的文本颜色
    "backgroundColor": "#f0f0f0", // tab背景色
    "list": [ // tab页签选项列表
      {
        "pagePath": "pages/mine/mine", // tab对应的页面路径
        "text": "mine", // tab对应的文本
        "iconPath": "", // tab对应的图标
        "selectedIconPath": "" // tab选中时的图标
      },      
      {
        "pagePath": "pages/index/index",
        "text": "index",
        "iconPath": "",
        "selectedIconPath": ""
      },      
      {
        "pagePath": "pages/logs/logs",
        "text": "logs",
        "iconPath": "",
        "selectedIconPath": ""
      }
    ]
  },
  "style": "v2",
  "sitemapLocation": "sitemap.json"
}

小程序网络请求

小程序网络请求的限制

  • 只能请求https类型的接口
  • 接口域名必须要添加到信任列表中(微信公众平台)

如何去配置合法接口域名

打开微信公众平台 --- 开发 --- 开发管理 --- 开发设置 --- 服务器域名

使用wx.request()发起网络请求

Page({
  onLoad(options) { 
    this.getLoop() // 页面加载之后就会调用
    this.onLogin()
  },
  // 发送get请求
  getLoop() {
    wx.request({
      url: 'https://www.wrz521.top:8080/api/getLoopArt', // 请求地址
      method: 'GET', // 请求方法
      data: {}, // 传递的数据
      success(res) { // 成功后的回调
        console.log(res.data, '请求结果');
      },
    })
  },
  // 发送post请求
  onLogin() {
    wx.request({
      url: 'https://www.wrz521.top:8080/api/login',
      method: 'POST',
      data: {
        username: 'admin',
        password: '123456789'
      },
      success(res) {
        console.log(res.data, '请求结果');
      }
    })
  },
})

跨域和ajax

小程序不存在跨域,不是运行在浏览器上的。

ajax依赖于浏览器xhr对象,小程序是依赖微信客户端,不能说是ajax请求,只能说网络数据请求

小程序页面导航

页面导航的两种方式

  • 声明式导航

    • 使用navigator组件, 点击navigator组件实现页面跳转
    • 跳转tabBar页面 需要指定open-type属性为 switchTab
    • 跳转到非tabBar页面 需要指定open-type为navigate
  • 编程式导航

    • 调用小程序的导航api进行跳转
    • 跳转tabBar页面 使用wx.switchTab()
    • 跳转到非tabBar页面 使用wx.navigatorTo()

跳转到tabBar页面

声明式导航:

<!-- wxml -->
<navigator url="/pages/index/index" open-type="switchTab">
    点击 跳转到tab index页面
</navigator>

编程式导航:

wx.switchTab()

Page({
  goTabIndex() {
    wx.switchTab({
      url: '/pages/index/index',
      success(res) { // 成功回调
        console.log(res, 'success');
      },
      fail(err) { // 失败回调
        console.log(err, 'fail');
      },
      complete(res) { // 成功或失败都会调用
        console.log(res, 'complete');
      }
    })
  }
})

跳转到非tabBar页面

声明式导航:

<!-- wxml -->
<navigator url="/pages/home/home" open-type="navigate">点击 跳转到非tab home页面</navigator>

编程式导航:

wx.navigateTo()

Page({
  goPageHome() {
    wx.navigateTo({
      url: '/pages/home/home',
      success(res) { // 成功回调
        console.log(res, 'success');
      },
      fail(err) { // 失败回调
        console.log(err, 'fail');
      },
      complete(res) { // 成功或失败都会调用
        console.log(res, 'complete');
      }
    })
  },
})

后退导航

  • 声明式导航

    • 使用组件时 指定 open-type属性为navigateBack delta属性为 后退的层级,是一个数字
  • 编程时导航

    • 使用wx.navigateBack()

声明式导航

<!-- wxml -->
<navigator open-type="navigateBack" delta="1">后退</navigator>

编程式导航

wx.navigateBack()

Page({
  goPageHome() {
    wx.navigateBack({
      delta: 1, // 返回的层级
      success(res) { // 成功回调
        console.log(res, 'success');
      },
      fail(err) { // 失败回调
        console.log(err, 'fail');
      },
      complete(res) { // 成功或失败都会调用
        console.log(res, 'complete');
      }
    })
  },
})

导航传参

  • 声明式导航

    • 在url的链接中以查询字符串的形式携带
    • url链接和参数之间 ? 隔开
    • 多个参数之间 & 隔开
  • 编程式导航

    • 在url的链接中以查询字符串的形式携带
    • url链接和参数之间 ? 隔开
    • 多个参数之间 & 隔开
  • 获取携带的参数

    • 在onLoad(options)生命周期函数中,options就是携带的参数对象
// wxml
<navigator url="/pages/home/home?age=18&name=zs" open-type="navigate">
    点击 跳转到非tab home页面
</navigator>
// mine.js
Page({
  goPageHome() {
    wx.navigateTo({
      url: '/pages/home/home?name=zs&age=18',
      success(res) {
        console.log(res, 'success');
      },
      fail(err) {
        console.log(err, 'fail');
      },
      complete(res) {
        console.log(res, 'complete');
      }
    })
  },
})
// home.js
Page({
    onLoad(options) {
        console.log(options) // 页面参数 {name: zs, age: 18}
    }
})

小程序页面事件

下拉刷新事件

onPullDownRefresh()

  • 开启下拉刷新

    • app.json 设置 window节点 设置enablePullDownRefresh: true,全局生效
    • 页面的json 设置enablePullDownRefresh: true,只有当前这个页面生效(建议)
  • 监听页面的onPullDownRefresh事件

    • 下拉刷新会触发
    • 需要手动调用wx.stopPullDownRefresh()停止下拉刷新
  /**
   * 页面相关事件处理函数--监听用户下拉动作
   */
  onPullDownRefresh() {
      console.log('页面刷新了');
      wx.stopPullDownRefresh({
          success(res){
              console.log(res, '停止下拉刷新了');
          }  
      })

  },

上拉触底事件

onReachBottom()

  • 设置上拉触底距离

    • app.json window节点配置 onReachBottomDistance: 100 距离底部100px的位置触发上拉触底事件
  • 监听页面的onReachBottom事件

    • 上拉到指定位置会触发该事件
  /**
   * 页面上拉触底事件的处理函数
   */
  onReachBottom() {
    console.log('上拉触底了');
  },

滑动页面事件

onPageScroll(Object object)

参数Object object

  • scrollTop

    • 页面在垂直方向已滚动的距离(单位px)

点击右上角菜单‘收藏’按钮

onAddToFavorites(Object object)

参数Object object

  • webViewUrl

    • 页面如果包含web-view组件时,会返回web-view的url

该事件需要 return一个Object,用来自定义收藏内容

Object

  • title

    • 自定义标题,默认页面标题或者账号名称
  • imageUrl

    • 自定义图片,默认页面截图
  • query

    • 自定义query字段,默认当前页面的query

更多

官方文档:https://developers.weixin.qq.com/miniprogram/dev/reference/api/Page.html

小程序生命周期

什么是生命周期

一个对象从创建到销毁的过程就是他的生命周期

小程序生命周期

小程序生命周期可以分为两类:

  • 应用生命周期

    • 小程序从启动 --> 运行 --> 销毁的过程
  • 页面的生命周期

    • 小程序每个页面从加载 --> 渲染 --> 销毁的过程

其中页面的生命周期范围小,应用生命周期范围大,两者包含关系

小程序启动 --> 页面A生命周期 --> 页面B生命周期 --> ... --> 小程序结束

生命周期函数

生命周期函数会伴随着生命周期,自动依次调用执行。

允许我们在某个特定的时间段,做一些操作,例如在页面加载的时候,初始化页面的数据,此时就需要onLoad生命周期函数。

应用生命周期函数

需要在app.js中调用App(Object object)函数,指定小程序应用的生命周期回调

  • onLaunch

    • 当小程序初始化完成时,会触发 onLaunch(全局只触发一次)
  • onShow

    • 当小程序启动,或从后台进入前台显示,会触发 onShow
  • onHide

    • 当小程序从前台进入后台,会触发 onHide
  • onError

    • 当小程序发生脚本错误,或者 api 调用失败时,会触发 onError 并带上错误信息
  • onPageNotFound

    • 当页面不存在时触发
  • onUnhandledRejection

    • 有未处理的promise,reject事件时触发
  • onThemeChange

    • 系统主题变化时触发
  • 其他

    • 可以添加任意的函数或者数据变量,全局使用,通过this进行调用
// app.js
App({
  onLaunch: function () {},
  onShow: function (options) {},
  onHide: function () {},
  onError: function (msg) {},
  globalData: { // 可以定义全局的数据或者函数,通过this进行调用
    userInfo: null
  }
})

页面生命周期函数

需要在页面的 .js中调用Page(Object object)函数,指定页面的生命周期回调

  • onLoad

    • 页面加载时触发。一个页面只会调用一次,可以在 onLoad 的参数中获取打开当前页面路径中的参数
  • onShow

    • 页面显示/切入前台时触发
  • onReady

    • 页面初次渲染完成时触发。一个页面只会调用一次,代表页面已经准备妥当,可以和视图层进行交互
  • onHide

    • 页面隐藏/切入后台时触发。如 wx.navigateTo 或底部tab切换到其他页面,小程序切入后台等
  • onUnload

    • 页面卸载时触发。如wx.redirectTo或wx.navigateBack到其他页面时
// pages/home/home.js
Page({
  onLoad(options) {
    console.log(options, '页面参数');
  },
  onShow() {},
  onReady() {},
  onHide() {},
  onUnload() {},
})

更多

官方文档:https://developers.weixin.qq.com/miniprogram/dev/reference/api/App.html

小程序wxs脚本

wxs和js

区别:

  • wxs通常用作过滤器
  • wxs有自己的数据类型
  • wxs不支持es6及以上的语法形式

    • let const 解构赋值 箭头函数等
  • wxs遵循CommonJs规范

    • module对象
    • require()函数
    • module.exports对象

wxs用法

内嵌在wxml中

定义wxs暴露出一个函数,在{}语法中调用 wxs脚本必须要有一个属性module指定模块名

<view>{{ m1.toUpper(username) }}</view> 
<wxs module="m1">
  module.exports.toUpper = function (str) {
    return str.toUpperCase()
  }
</wxs>

外联wxs脚本

定义wxs后缀的脚本文件 如 tools.wxs

在wxs中定义函数,并暴露

在wxml中引入wxs脚本文件,

调用m2里边的函数就行

<wxs src="../../utils/tools.wxs" module="m2"></wxs>

注意点

  • 只能搭配{}语法使用,不能作为事件回调来使用
  • wxs不能调用js中的函数
  • wxs不能调用小程序提供的api

小程序自定义组件

如何自定义

  • 在项目根目录components文件夹中创建文件夹
  • 右键文件夹,新建Component,会自动生成组件需要的文件

局部注册组件

  • 在页面的.json文件的usingComponents 节点中注册
  • 注册方式 组件名称:组件路径
{
  "usingComponents": {
    "my-test": "/componnets/test/test"
  }
}

全局注册组件

  • 在app.json文件的usingComponents 节点中注册
  • 注册方式同上

如何使用

在wxml中以标签的形式使用

<my-test></my-test>

组件特点

  • 组件样式隔离不会影响其他组件或者页面
  • 只有class类选择器才会受到样式隔离

如何修改样式隔离

在组件的js文件中添加options节点,添加属性styleIsolation为isolated

Component({
    options: {
          styleIsolation: "isolated"
    },
})

styleIsolation属性值

可选值默认值描述
isolated启用样式隔离,组件内外的class类声明的样式不会相互影响
apply-shared页面的wxss样式会影响到组件内部的样式,组件样式不会影响外部
shared组件内外的样式,相互影响

组件和页面的区别

  • 组件

    • 组件的js调用Component(Object object)函数
    • 组件的方法函数定义在Component(Object object)函数的methods节点中
    • 其他Component函数的节点
  • 页面

    • 页面的js调用Page(Object object)函数
    • 页面的方法函数直接写在里边就好了
    • 其他Page函数的节点
// 页面js
Page({
  data: {},
  goBack() { // 页面的方法函数,直接写就完事了
    wx.navigateBack({
      delta: 1,
    })
  },
  onLoad(options) {
    console.log(options, '页面参数');
    console.log('onLoad');
  }
})
// 组件js
Component({
  options: {
    styleIsolation: "isolated"
  },
  /* 组件的属性列表 用来接收组件上的属性*/
  properties: {
      num: {
          type: Number, // 属性类型
          value: 10   // 默认值
      },
      num1: Number, // 简化版
  },
  /* 组件的初始数据 */
  data: {},
  /* 组件的方法列表 */
  methods: {
    goBack() { // 组件的方法函数,定义在methods节点
      wx.navigateBack({
        delta: 1,
      })
    },
  }
})

Component(Object object)函数

参数Object object

  • options

    • 类型:Object
    • 描述:组件配置选项
  • data

    • 类型:Object
    • 描述:存放组件私有数据
  • properties

    • 类型:Object | Map
    • 描述:组件外传递过来的属性映射,接收
  • methods

    • 类型:Object
    • 描述:组件的方法函数

更多参数节点参考:https://developers.weixin.qq.com/miniprogram/dev/reference/api/Component.html

组件数据监听

  • Components函数添加observers节点
  • 监听多个字段 num1, num2
  • 监听对象的属性 obj.prop1,obj.prop2
  • 监听对象所有属性,使用通配符*,obj.* 代表所有的属性
Component({
  observers: { // 数据监听器
    'num, num2': function (newNum, newNum2) { // 监听多个字段
      // 做一些事情
    },
    'obj.prop1, obj.prop2': function (newProp1, newProp2) { // 监听对象属性
      // 做一些事情
    },
    'obj.**': function (newObj) { // 监听对象所有的属性
      // 做一些事情
    }
  },
})

纯数据字段

特点:

  • 不会再页面中展示渲染
  • 不会传递给其他组件使用
  • 有利于提升页面更新的性能

设置纯数据字段:

  • options节点新增pureDataPattern属性
  • pureDataPattern值是一个正则表达式
  • 符合表达式的数据就是纯数据字段
Component({
  options: {
    styleIsolation: "isolated",
    pureDataPattern: /^_/ // 以下划线开头的数据,就是纯数据字段
  },
  
  data: {
      _a: true  
  }
})

组件生命周期函数

生命周期函数

  • created

    • 组件示例刚刚创建完执行
    • 不能调用setData函数,只能在this上挂载一些自定义属性字段
  • attached

    • 组件初始化完毕,进入到页面节点树执行
    • 可以发送网络请求,初始化一些数据
  • ready

    • 组件在视图布局完成后执行
  • moved

    • 组件实例被移动到节点树的另一个位置时执行
  • detached

    • 组件实例被从页面节点树移除时执行

使用的两种方法:

  • 直接和data平级,写就完事了
  • 使用 lifetimes节点,生命周期函数写在这里边(推荐)
Component({
  lifetimes: {
    created() {
      console.log('test1组件 created');
    },
    attached() {
      console.log('test1组件 attached');
    }
  }
})

组件所在页面的生命周期函数

生命周期函数

  • show

    • 组件所在页面显示的时候触发
  • hide

    • 组件坐在页面隐藏的时候触发
  • resize

    • 组件所在页面的尺寸发生变化的时候触发

使用方法

  • 新增pageLifetimes节点,将函数写在里边
Component({
  lifetimes: {
    created() {
      console.log('test1组件 created');
    },
    attached() {
      console.log('test1组件 attached');
    }
  },
  pageLifetimes: {
    show() {
      console.log('组件所在页面显示了 show');
    },
    hide() {
      console.log('组件所在页面隐藏了 hide');
    },
    resize() {
      console.log('组件所在页面窗口尺寸变化了 resize');
    }
  }
})

组件插槽

  • 匿名插槽

    • 使用slot标签占位时,不设置name属性
  • 具名插槽

    • 使用slot标签占位时,设置name属性
  • 开启组件多插槽

    • 组件默认只能使用一个插槽
    • 在options节点,新增multipleSlots: true,开启多插槽支持
<!-- 组件wxml -->
<view>
  <slot name="before"></slot>
  <slot></slot>
  <slot name="after"></slot>
</view>

<!-- 引用组件的wxml -->
<cy-test1>

  <view slot="after"> 渲染到name为 after的插槽 </view>
  <view slot="before"> 渲染到name为 before的插槽 </view>
  <view>渲染到默认插槽</view>
  
</cy-test1>

小程序组件传值

父子间组件通讯

通讯方法:

  • 属性绑定

    • 绑定属性在子组件上,子组件内通过properties进行接收
  • 事件绑定

    • 通过bind绑定自定义事件,子组件内通过this. triggerEvent(自定义事件名称, 传递的数据)进行调用
  • 获取组件实例

    • 直接通过this.selectComponent()获取组件实例

父向子传值

通过属性绑定

<!-- 父组件 使用组件,并添加属性arrList="父组件的某个数据" -->
<my-test arrList="{{ arr }}">
  <text slot="before">before对应的插槽内容</text>
  1231456
  <text slot="after">after对应的插槽内容</text>
</my-test>

<!-- 在子组件的js的properties节点中添加对应的属性,并声明类型或者默认值 -->
  properties: {
    arrList: {
      type: Array
    }
  }

<!-- 子组件封装 -->
<view style="background: pink;">
  <slot name="before"></slot>
  <slot></slot>
  <slot name="after"></slot>
  <view>----------</view>
  <text wx:for="{{ arrList }}" wx:key=" id ">
    接受到了父组件传递的数组: {{ item.name }}, {{ item.id }}  // 拿到接收到的数据渲染
  </text>
</view>

子向父传值

通过事件绑定

// 调用组件 并绑定自定义事件
<my-test arrList="{{ arr }}" fatherNum="{{ num }}" bind:getValue="getValue">
  <text slot="before">before对应的插槽内容</text>
  1231456
  <text slot="after">after对应的插槽内容</text>
</my-test>


// js
  getValue (e) {
    console.log(e, '子组件调用父组件的getValue函数');
  },
// 子组件触发这个自定义函数 并传值
this.triggerEvent('getValue', {value: 5})

获取组件实例

使用this.selectComponent() 传入id或者class选择器

this.selectComponent('.my-text1') // 组件标签添加class类

behaviors

类似于vue mixins混入

使用方法:

  • 创建behaviors,新建一个js文件, 调用Behavior()函数创建一个behavior实例对象,通过module.exports向外暴露,组件调用时,会被合并到组件中
// js
module.exports = Behavior({
  data: {},
  properties: {},
  methods: {}
})
  • 通过require导入该js文件,并且在组件的behaviors节点中注册使用
const myBehavior = require('../../behaviors/my-behaviors')
// 在组件中添加behaviors节点,对应一个数组
behaviors: [myBehavior],
  • behaviors中可用的节点 同组件属性

小程序npm包

npm包支持和限制

  • 不支持依赖nodejs内置库的npm包
  • 不支持依赖浏览器对象的npm包
  • 不支持依赖c++插件的npm包

下载和使用

新版:

​ 下载npm包 --> 工具 --> 构建npm包

旧版:

​ 下载npm包 --> 右侧详情模块勾选npm包 --> 工具 --> 构建npm包

小程序全局共享容器

mobx全局共享

小程序可以使用mobx-miniprogram和mobx-miniprogram-bindings实现全局数据共享。

  • mobx-miniprogram用来创建store对象
  • mobx-program-bindings用来挂载store容器到页面 或者 组件中

如何使用mobx

下载npm包

npm install mobx-miniprogram --save
npm i mobx-miniprogram-bindings --save

# or

npm install --save mobx-miniprogram mobx-miniprogram-bindings

创建store容器

新建store.js文件

import { observable, action } from 'mobx-miniprogram'

// 创建store容器
export const store = observable({
  // 数据字段
  numA: 1,
  numB: 2,
  // 计算属性
  get sum() {
    return this.numA + this.numB
  },
  // action方法 修改数据
  update: action(function(a = 0, b = 0) {
    this.numA += a
    this.numB += b
  })
})

在页面中使用

// js
import { createStoreBindings } from 'mobx-miniprogram-bindings'
import { store } from '../../store/store'
Page({
  data: {},
  editNum(e) {
    const a = e.target.dataset.a || 0
    const b = e.target.dataset.b || 0
    this.update(a, b)
  },
  onLoad(options) {
    // 挂载store容器
    this.storeBindings = createStoreBindings(this, {
      store, // store容器
      fields: ['numA', 'numB', 'sum'], // 映射数据字段和计算属性
      actions: ['update'] // 映射action方法
    })
  },
})
<!-- wxml -->
<view>{{numA }} + {{ numB }} = {{ sum }}</view>
<van-button type="primary" bindtap="editNum" data-a="{{ 1 }}">A + 1</van-button>
<van-button type="info" bindtap="editNum" data-b="{{ 1 }}">B + 1</van-button>

在组件中使用

// js
import { storeBindingsBehavior } from 'mobx-miniprogram-bindings'
import { store }  from '../../store/store'
Component({
  behaviors: [storeBindingsBehavior], // 挂载behavior
    
  storeBindings: { // storeBindings配置选项
    store,
    // fields: ['numA', 'numB', 'sum'],
    fields: { // 可以自定义变量名称  numABC: 'numA'
      numA: 'numA', // 直接映射numA
      numB: () => store.numB, // 函数返回numB
      sum: (store) => store.sum // 函数返回sum
    },
    // actions: ['update']
    actions: {
      update: 'update'
    }
  }
  properties: {},
  data: {},
  methods: {
    editNum(e) {
      const a = e.target.dataset.a || 0
      const b = e.target.dataset.b || 0
      this.update(a, b)
    }
  }
})

小程序分包

什么是分包

分包指的是将一个完整的小程序项目根据需求划分为不同的子包,在构建时打包成不同的分包,用户在使用的时候按需进行加载

分包特点

  • 加载规则

    • 小程序启动时,默认会下载主包并且启动主包内的页面(tabbar页面需要放到主包)
    • 当用户进入分包内的某个页面,客户端会把对应的分包下载下来,进行展示(非tabbar页面按照功能的不同,划分不同的分包,进行按需下载)
  • 体积限制

    • 整个小程序的所有分包大小不能超过16M(主包 + 所有分包)
    • 单个分包或者主包不能超过2M
  • 引用原则

    • 普通分包

      • 可以引用主包内的公共资源
      • 不能引用其他分包的私有资源
      • 主包不能引用分包的私有资源
    • 独立分包

      • 资源独立
  • 打包原则

    • 小程序会按照subPackages的配置进行分包
    • subPackages之外的目录将被打包到主包中
    • tabbar页面必须要在主包中
    • 分包之间不能互相嵌套
  • 分包好处

    • 可以优化小程序首次启动的下载时间,在多团队协作开发时能够更好的解耦协作

项目构成

  • 分包前

    • 小程序所有的页面和资源都被打包在一起
    • 整个项目体积过大,影响小程序的首次启动的下载时间
  • 分包后

    • 小程序项目由一个主包和多个分包组成
    • 主包一般只包含项目的启动页面或者tabbar页面,以及所有分包都需要使用的一些公共资源
    • 分包只包含和当前分包有关的页面和私有资源

如何配置分包

在app.json中添加节点 subPackages 是一个数组,多个分包,就写多个对象

  "subPackages": [
    {
      "root": "pkgA", // 分包的根目录
      "name": "p1", // 分包的别名
      "pages": [ // 分包下面的页面 会自动创建
        "pages/cat/cat",
        "pages/logs/logs"
      ]
    }
  ],

独立分包

独立分包和普通分包区别

  • 独立分包

    • 本质上还是分包
    • 功能独立
    • 不能引用主包公共资源,不能引用分包的私有资源,独立分包之间也不可相互引用,资源完全独立
    • 不依赖主包,可以单独运行,提升分包页面的启动速度
  • 普通分包

    • 普通分包依赖于主包,需要先下载主包
    • 可以引用主包公共资源

配置独立分包

只需要在分包中添加independent为true,则当前分包就是一个独立分包

{
      "root": "pkgB",
      "name": "p2",
      "pages": [
        "pages/cat/cat",
        "pages/logs/logs"
      ],
      "independent": true
}

分包预下载

分包预下载指的是,在进入小程序的某个页面时,由框架自动预下载可能需要的分包,从而提升后续进入分包时页面的启动速度

配置分包预下载

  • 预下载分包的行为,会在进入到指定的页面时触发。
  • 在app.json中配置preloadRule节点,定义预下载规则。
  • 分包预下载所有页面共享2M,预下载的大小不能超过2M
  "preloadRule": {
    "pages/logs/logs": { // 页面路径,哪一个页面,进入这个页面,预加载哪些packges分包
      "packages": ["p1", "p2"], // 分包的name别名或者 root根目录
      "network": "all" // 下载环境 all 所有 wifi 仅限wifi环境
    }
  },
0
选择打赏方式:
微信

评论 (0)

取消