微信小程序(二):基础知识

324 阅读33分钟

前言

该文章记录一些工作中常用的微信小程序基础知识,慢慢将会添加更多的基础知识,所有内容均从网上整理而来,加上自己的理解做一个整合,方便工作中使用。

一、配置文件

1.【配置文件介绍】

JSON是一种轻量级的数据格式,常用于前后端数据的交互,但是在小程序中,JSON 扮演的静态配置的角色,用于配置当前页面或组件的属性和行为,每个页面或组件也都可以拥有一个对应的 json 文件。

小程序中常见的配置文件有以下几种:

  1. 全局配置文件:app.json ➡ 小程序全局配置文件,用于配置小程序的一些全局属性和页面路由。
  2. 局部配置文件:页面.json ➡ 小程序页面配置文件,用于配置当前页面的窗口样式、页面标题等
  3. 项目配置文件:project.config.json ➡ 小程序项目的配置文件,用于保存项目的一些配置信息和开发者的个人设置
  4. 搜索配置文件:sitemap.json ➡ 配置小程序及其页面是否允许被微信索引,提高小程序在搜索引擎搜索到的概率

2.【全局配置】

详细文档: pages 配置项

小程序 app.json 文件是小程序的全局配置文件,用于配置小程序的一些全局属性和页面路由。

当小程序启动时,会自动读取 app.json 文件中的配置,根据配置生成对应的页面和组件、界面表现、网络超时时间、底部 tab,在小程序运行过程中起着关键的作用。

2-1. pages字段

用于指定小程序由哪些页面组成,用于为了让小程序知道由哪些页面组成以及页面定义在哪个目录,每一项都对应一个页面的 路径(含文件名) 信息。

  "pages": [
    "pages/index/index",
    "pages/login/login"
  ],
  //设置login页为启动页面,如果不设置此项,以pages数组中第一项为启动页面
  "entryPagePath": "pages/login/login", 

2-2. window字段

window字段: 用于设置小程序的状态栏、导航条、标题、窗口背景色。

image.png

属性描述类型默认值
navigationBarBackgroundColor导航栏背景颜色HexColor#000000
navigationBarTextStyle导航栏标题颜色,仅支持 black / whitestringwhite
navigationBarTitleText导航栏标题文字内容string
backgroundColor下拉 loading 的样式,仅支持 dark / lightstringdark
enablePullDownRefresh是否开启全局的下拉刷新booleanfalse
onReachBottomDistance页面上拉触底事件触发时距页面底部距离单位为 pxnumber50

2-3. tabBar字段

tabBar 字段:定义小程序顶部、底部 tab 栏,如果小程序是一个多 tab 应用,例如:可以在客户端窗口的底部或顶部通过 tab 栏可以切换页面,可以通过 tabBar 配置项指定 tab 栏的表现,以及 tab 切换时显示的对应页面。

image.png

属性描述类型默认值
colortab 上的文字默认颜色,仅支持十六进制颜色HexColor
selectedColortab 上的文字选中时的颜色,仅支持十六进制颜色HexColor
backgroundColortab 的背景色,仅支持十六进制颜色HexColor
borderStyletabbar 上边框的颜色, 仅支持 black / whitestringblack
listtab 的列表,详见 list 属性说明,最少 2 个、最多 5 个 tab
positiontabBar 的位置,仅支持 bottom / topstringbottom

List 配置项:list 是一个数组,只能配置最少 2 个、最多 5 个 tab,tab 按数组的顺序排序,每个项都是一个对象

属性描述类型是否必填
pagePath页面路径,必须在 pages 中先定义string
texttab 上按钮文字string
iconPath图片路径,icon 大小限制为 40kb,
建议尺寸为 81px * 81px,
string
selectedIconPath选中时的图片路径,icon 大小限制为 40kb,
建议尺寸为 81px * 81px,不支持网络图片。
string

📌 注意事项:

  • list 是一个数组,只能配置最少 2 个、最多 5 个 tab
  • positiontop 时,不显示 icon

3.【页面配置】

详细文档: 页面配置文档

小程序的页面配置,也称局部配置,每一个小程序页面也可以使用自己的 .json 文件来对本页面的窗口表现进行配置。

需要注意的是:页面配置文件的属性和 全局配置文件中的 window 属性几乎一致

只不过这里不需要额外指定 window 字段,因此如果出现相同的配置项,页面中配置项会覆盖全局配置文件中相同的配置项。

属性描述类型默认值
navigationBarBackgroundColor导航栏背景颜色HexColor#000000
navigationBarTextStyle导航栏标题颜色,仅支持 black / whitestringwhite
navigationBarTitleText导航栏标题文字内容string
backgroundColor下拉 loading 的样式,仅支持 dark / lightstringdark
enablePullDownRefresh是否开启全局的下拉刷新booleanfalse
onReachBottomDistance页面上拉触底事件触发时距页面底部距离单位为 pxnumber50
{
  "usingComponents": {}, //注册自定义组件
  "navigationBarTitleText": "商品分类",
  "navigationBarTextStyle": "white",
  "navigationBarBackgroundColor": "#00AF92",
  "enablePullDownRefresh": true,
  "backgroundColor": "#eee",
  "backgroundTextStyle": "light",
  ···
}

4.【项目配置文件】

详细文档: 项目配置文件

通常大家在使用一个工具的时候,都会针对各自喜好做一些个性化配置,例如 编译配置等等,当你换了另外一台电脑重新安装工具的时候,你还要重新配置。

考虑到这点,小程序开发者工具在每个项目的根目录都会生成一个 project.config.json,你在工具上做的任何配置都会写入到这个文件,当你重新安装工具或者换电脑工作时,你只要载入同一个项目的代码包,开发者工具就自动会帮你恢复到当时你开发项目时的个性化配置,其中会包括编辑器的颜色、代码上传时自动压缩等等一系列选项

image.png

  • project.config.json 文件中配置公共的配置,
  • project.private.config.json 配置个人配置,文件同样可以对项目进行配置
  • project.private.config.json中的相同设置优先级高于project.config.json

📌 注意事项

  • project.private.config.json 写到 .gitignore 避免版本管理的冲突。
  • 与最终编译结果有关的设置 必须 设置到 project.config.json 中

可以在微信开发者工具,点击以下两个配置选项进行相关的设置,然后观察两个文件的变化即可。

image.png

5.【支持使用 sass/less】

project.config.json 文件中,修改 setting 下的 useCompilerPlugins 字段为 ["sass"],即可开启工具内置的 sass 编译插件。 如需同时开启 typescript 编译插件,可将该字段修改为 ["typescript ", "sass"]。 目前支持三个编译插件:typescript、less、sass

{
  "setting": {
    "useCompilerPlugins": [
      "sass"
    ]
  }
}

配置好以后,需要将 .wxss 改成 .scss

📌 注意:

我们在配置的时候,编译插件的名称是 sass,但是文件的后缀名是 .scss; 这是因为 Sass 是 Css 预处理语言,scss 是 Sass 的一个语法版本

6.【sitemap.json】

微信现已开放小程序内搜索,当开发者允许微信索引时,微信会通过爬虫的形式,为小程序的页面内容建立索引。当用户的搜索词条触发该索引时,小程序的页面将可能展示在搜索结果中。

可以通过 sitemap.json 配置,或者管理后台页面收录开关来配置其小程序页面是否允许微信索引。语法如下:

{
  "rules": [
    {
      "action": "allow",
      "page": "*"
    }
  ]
}

常用配置项:

属性属性说明属性值
action是否允许被搜索可选项有:allow 、disallow
page允许/不允许被搜索的页面页面路径或者通配符

📌 注意事项

  • 没有 sitemap.json 则默认所有页面都能被索引
  • sitemap.json 文件中默认的设置,是优先级最低的默认规则,所有页面都会被微信索引

二、常用样式和组件

1.【组件和样式介绍】

在小程序中不能使用 HTML 标签,也就没有 DOMBOM,同时仅仅支持部分 CSS选择器

  • 组件

小程序给提供的组件文档:WXML

其中 WXML 充当的就是类似 HTML 的角色,只不过在 WXML 中没有divpspanimga 等标签,在 WXML 中需要使用 小程序提供的 viewtextimagenavigator 等标签来构建页面结构,小程序提供的这些标签,我们称为 "组件",开发者可以通过组合这些基础组件进行快速开发。

  • 样式

小程序样式官方文档:WXSS

WXSS 则充当的就是类似 CSS 的角色,WXSS 具有 CSS 大部分的特性,小程序在 WXSS 也做了一些扩充和修改,新增了尺寸单位 rpx、提供了全局的样式和局部样式,另外需要注意的是WXSS 仅支持部分 CSS 选择器。

rpx : 小程序新增的拓展单位,可以根据屏幕宽度进行自适应

📌 注意事项: : 小程序规定任何型号手机:屏幕宽度都为750rpx

🔔 开发建议

  • 开发微信小程序时设计师可以用 iPhone6 作为视觉稿的标准。
  • iPhone6 的设计稿一般是 750px,小程序的宽是 750rpx
  • 在我们开发小程序页面时,量取多少 px ,直接写多少 rpx,开发起来更方便,也能够适配屏幕的适配

原因: 设计稿宽度是 750px,而 iPhone6 的手机设备宽度是 375px, 设计稿想完整展示到手机中,就需要缩小一倍 在 iPhone6 下,px 和 rpx 的换算关系是:1rpx = 0.5px, 750rpx = 375px,刚好能够填充满整个屏幕的宽度

2.【全局样式和局部样式】

在进行网页开发时,我们经常创建 reset.css 作为全局样式文件进行重置样式或者样式统一,然后在每个页面或组件中写当前页面或组件的局部样式,小程序中也存在全局样式和局部样式。

  • 知识点:

全局样式:指在 app.wxss中定义的样式规则,作用于每一个页面

局部样式:指在page.wxss中定义的样式规则,只作用在对应的页面,并会覆盖 app.wxss 中相同的选择器。

  • 案例:

app.wxss 中定义全局样式,设置 text 组件的颜色以及字号大小,这段样式将会作用于任意页面的 text 组件

/* app.wxss */

text {
  color: lightseagreen;
  font-size: 50rpx;
}

然后在 cate.wxss 中定义局部样式,设置 text 组件的颜色以及字号大小,会发现局部样式将全局样式进行了覆盖

/* pages/index/index.wxss */

text {
  color: red;
  font-size: 30rpx;
}

3.【常用组件】

  • view组件:容器组件,类似于 div,也是一个块级元素,占据一行

    <!-- 公司相关信息 -->
    <view class="info">2</view>
    
    <!-- 商品导航区域 -->
    <view class="goods-nav">3</view>
    
    <!-- 商品推荐区域 -->
    <view class="hot">4</view>
    
  • swiper组件:官方文档

    在小程序中,提供了 swiperswiper-item 组件实现轮播图:

    1. swiper:滑块视图容器,常用来实现轮播图,其中只可放置swiper-item组件,否则会导致未定义的行为

    2. swiper-item:仅可放置在swiper组件中,宽高自动设置为100%,代表 swiper 中的每一项

    我们可以使用 swiper 组件提供的属性,实现轮播图的订制,常见属性如下:

    属性说明类型
    indicator-dots是否显示面板指示点boolean (默认 false)
    indicator-color指示点颜色color (默认:rgba(0, 0, 0, .3))
    indicator-active-color当前选中的指示点颜色color (默认:#000000)
    autoplay是否自动切换boolean (默认 false)
    interval自动切换时间间隔number (默认 5000)
    circular是否采用衔接滑动boolean (默认 false)
    其他属性...

    落地代码:

    ➡️ pages/index/index.wxml

    <!-- 轮播图区域 -->
    <view class="swiper">
      <!-- swiper 组件实现轮播图区域的绘制 -->
      <!-- swiper 组件,滑块视图容器 -->
      <swiper
        circular
        autoplay
        indicator-dots
        interval="2000"
        indicator-color="#efefef"
        indicator-active-color="#ccc"
      >
        <!-- swiper 组件内部不能写其他组件或内容 -->
        <!-- 在 swiper 组件内部只能写 swiper-item 组件 -->
        <!-- swiper-item 组件只能放到 swiper 组件中,宽高自动设置为 100% -->
        <swiper-item>
          第一张轮播图
        </swiper-item>
    
        <swiper-item>
          第二张轮播图
        </swiper-item>
    
        <swiper-item>
          第三张轮播图
        </swiper-item>
      </swiper>
    </view>
    

    ➡️ pages/index/index.scss

    page {
      height: 100vh;
      background-color: #efefef !important;
    }
    
    swiper {
      swiper-item {
    
        // 在 Sass 拓展语言中,& 符号表示父选择器的引用。它用于在嵌套的选择器中引用父选择器
        // 下面这段代码在编译以后,生成的代码是 swiper-item:first-child
        &:first-child {
          background-color: skyblue;
        }
    
        &:nth-child(2) {
          background-color: lightcoral;
        }
    
        &:last-child {
          background-color: lightseagreen;
        }
      }
    }
    
  • image组件:类似img标签

    <!-- src:图片资源地址 -->
    <!-- mode:图片裁剪、缩放的模式 -->
    <!-- lazy-load:图片懒加载,在即将进入一定范围(上下三屏)时才开始加载 -->
    <image src="/assets/tom.png" mode="heightFix" lazy-load="{{ true }}" />
    
  • text组件:文本组件,相当于 span,是一个行内元素

    <view class="navs">
      <view>
        <image src="/assets/cate-1.png" alt=""/>
        <text>爱礼精选</text>
      </view>
    </view>
    
  • navigator组件: 跳转组件,类似a标签

    <!-- url:当前小程序内的跳转链接 --> 
    <navigator url="/pages/list/list">
    

    在小程序中,如果需要进行跳转,需要使用 navigation 组件,常用的属性有 2 个:

    1. url :当前小程序内的跳转链接

    2. open-type :跳转方式

      • navigate:保留当前页面,跳转到应用内的某个页面。但是不能跳到 tabbar 页面
      • redirect: 关闭当前页面,跳转到应用内的某个页面。但不能跳转到 tabbar 页面
      • switchTab:跳转到 tabBar 页面,并关闭其他所有非 tabBar 页面
      • reLaunch:关闭所有页面,打开到应用内的某个页面
      • navigateBack:关闭当前页面,返回上一页面或多级页面

    📌 注意事项:

    • 路径后可以带参数。参数与路径之间使用 ? 分隔,参数键与参数值用 = 相连,不同参数用 & 分隔;例如:/list?id=10&name=hua,在 onLoad(options) 生命周期函数 中获取传递的参数

    • 属性 open-type="switchTab" 时不支持传参

  • scroll-view组件: 可滚动视图区域,适用于需要滚动展示内的场景

    可滚动视图区域,适用于需要滚动展示内的场景,它可以在小程序中实现类似于网页中的滚动条效果,用户可以通过手指滑动或者点击滚动条来滚动内容,scroll-view 组件可以设置滚动方向、滚动条样式、滚动到顶部或底部时的回调函数等属性,可以根据实际需求进行灵活配置

    设置横向滚动时,需要添加 scroll-x 属性,然后通过 css 进行结构绘制,实现页面横向滚动

    设置竖向滚动时,需要给scroll-view一个固定高度,同时添加 scroll-y 属性,实现页面纵向滚动

    落地代码:

    ➡️ pages/index/index.wxml:

    <view class="hot">
      <scroll-view class="scroll-x" scroll-x>
        <view>1</view>
        <view>2</view>
        <view>3</view>
      </scroll-view>
    
      <scroll-view class="scroll-y" scroll-y>
        <view>1</view>
        <view>2</view>
        <view>3</view>
      </scroll-view>
    </view>
    

    ➡️ pages/index/index.wxss

    .hot {
      margin-top: 16rpx;
    
      .scroll-x {
        width: 100%;
        white-space: nowrap;
        background-color: lightblue;
    
        view{
          display: inline-block;
          width: 50%;
          height: 80rpx;
    
          &:last-child{
            background-color: lightseagreen;
          }
    
          &:first-child{
            background-color: lightcoral;
          }
        } 
      }
    
     .scroll-y {
       height: 400rpx;
       background-color: lightsalmon;
       margin-top: 60rpx;
    
       view {
         height: 400rpx;
    
          &:nth-child(odd) {
            background-color: lightseagreen;
          }
    
          &:nth-child(even) {
            background-color: lightcoral;
          }
        }  
      }
    }
    

三、小程序事件系统

1.【事件绑定和事件对象】

小程序中绑定事件使用 bind 方法,点击事件click 也需要使用 tap 事件来进行代替,绑定事件的方式有两种:

第一种方式:bind:事件名,bind 后面需要跟上冒号,冒号后面跟上事件名

<button bind:tap="handler">按钮</button>

第二种方式:bind事件名,bind 后面直接跟上事件名

<button bindtap="handler">按钮</button>

事件处理函数需要写到 .js 文件中,在 .js 文件中需要调用小程序提供的 Page 方法来注册小程序的页面,我们可以直接在 Page 方法中创建事件处理函数。

当组件触发事件时,绑定的事件的处理函数会收到一个事件对象,用来记录事件发生时的相关信息。在触发事件时,事件处理程序会主动的给我们传入一个参数 —— event(事件对象)

// pages/home/home.js
Page({
  // 页面的初始数据
  data: {},

  // 事件处理程序
  handler (event) {
    // console.log('我被触发了~~~')
    console.log(event)
  }
    
  // 其他 coding...
})

2.【绑定并阻止事件冒泡】

事件分为冒泡事件和非冒泡事件:

  1. 冒泡事件:当一个组件上的事件被触发后,该事件会向父节点传递。
  2. 非冒泡事件:当一个组件上的事件被触发后,该事件不会向父节点传递。

使用 bind 绑定的事件,会触发事件冒泡,如果想阻止事件冒泡,可以使用 catch 来绑定事件。

落地代码:

<view bindtap="parentHandler">
  <!-- 使用 bind 绑定的事件,会产生事件冒泡 -->
  <!-- <button bindtap="handler">按钮</button> -->

  <!-- 使用 catcht 绑定的事件,会阻止事件冒泡 -->
  <button catchtap="handler">按钮</button>
</view>

Page({
  // 页面的初始数据
  data: {},

  // 事件处理程序
  handler (event) {
    console.log('我是子绑定的事件 ~~~')
  },
  
  parentHandler () {
    console.log('我是父绑定的事件 ~~~')
  }
    
  // 其他 coding...
})

WXML 中冒泡事件列表如下表:

类型触发条件
touchstart手指触摸动作开始
touchmove手指触摸后移动
touchcancel手指触摸动作被打断,如来电提醒,弹窗
touchend手指触摸动作结束
tap手指触摸后马上离开
longpress手指触摸后,超过350ms再离开,如果指定了事件回调函数并触发了这个事件,tap事件将不被触发
longtap手指触摸后,超过350ms再离开(推荐使用 longpress 事件代替)
transitionend会在 WXSS transition 或 wx.createAnimation 动画结束后触发
animationstart会在一个 WXSS animation 动画开始时触发
animationiteration会在一个 WXSS animation 一次迭代结束时触发
animationend会在一个 WXSS animation 动画完成时触发
touchforcechange在支持 3D Touch 的 iPhone 设备,重按时会触发

📌 注意事项

除上表之外的其他组件自定义事件,如无特殊声明都是非冒泡事件 例如 formsubmit事件,inputinput事件

3.【事件传参-data-*自定义数据】

在小程序中,可以通过事件传参的方式,将数据传递给事件处理函数。常见的事件包括点击事件、输入事件等。

在组件节点中可以通过 data- 的方式传递一些自定义数据,传递的数据可以通过事件对象的方式进行获取

在 wxml 文件中,使用 data-* 属性将数据传递给事件处理函数。例如:

<button bindtap="btnHandler" data-id="1" data-name="tom">按钮</button>

在 js 文件中,可以通过 event.currentTarget.dataset 获取传递的数据

Page({
  btnHandler (event) {
    // currentTarget 事件绑定者,也就是指:哪个组件绑定了当前事件处理函数
    // target 事件触发者,也就是指:哪个组件触发了当前事件处理函数
    // currentTarget 和 target 都是指按钮,因为是按钮绑定的事件处理函数,同时点击按钮触发事件处理函数
    // 这时候通过谁来获取数据都可以
    console.log(event.currentTarget.dataset.id)
    console.log(event.target.dataset.name)
  }
})

复杂情况: 事件绑定在父组件上,自定义数据父子组件都有设置,点击触发事件的组件不同,获取数据方式不同。

<view data-address="背景" class="box" bindtap="handler">
  <button data-name="tom">按钮</button>
</view>
Page({
  handler(event) {
    //两种触发情况
    //一、点击view组件,非button组件部分
    // currentTarget 事件绑定者:view组件
    // target 事件触发者:view组件

    //可以通过currentTarget/target获取到address,无法获取到button组件上的name
    console.log(event.currentTarget.dataset.address)
    console.log(event.target.dataset.address)

    //二、直接点击button组件
    // currentTarget 事件绑定者:view组件
    // target 事件触发者:button组件

    // 如果想获取 view 身上的数据,就必须使用 currentTarget 才可以
    // 如果想获取的是事件触发者本身的数据,就需要使用 target
    console.log(event.currentTarget.dataset.address)
    console.log(event.target.dataset.name)
  }
})

📌 注意事项

  • 使用 data- 方法传递参数的时候,多个单词由连字符 - 连接
  • 连字符写法会转换成驼峰写法,而大写字符会自动转成小写字符
    • data-element-type ,最终会呈现为 event.currentTarget.dataset.elementType
    • data-elementType ,最终会呈现为 event.currentTarget.dataset.elementtype

4.【事件传参-mark 自定义数据】

mark是一种自定义属性,可以在组件上添加,用于来识别具体触发事件的 target 节点。同时 mark 还可以用于承载一些自定义数据(类似于 dataset

markdataset 很相似,主要区别在于:

  • mark 会包含从触发事件的节点到根节点上所有的 mark: 属性值 (事件委托的)

  • dataset 仅包含触发事件那一个节点的 data- 属性值。

落地代码:

<view mark:address="背景" class="box" bindtap="handler">
  <button mark:name="tom">按钮</button>
</view>
Page({
  handler(event) {
    //两种触发情况
    //一、点击view组件,非button组件部分
    //可以通过mark获取到address,无法获取到button组件上的name
    console.log(event.mark.address)

    //二、直接点击button组件
    //可以通过mark获取到view组件的address,和button组件上的name
    console.log(event.mark.address)
    console.log(event.mark.name)
  }
})

四、模板语法

1.【声明和绑定数据】

小程序页面中使用的数据均需要在 Page() 方法的 data 对象中进行声明定义

在将数据声明好以后,需要在 WXML 中绑定数据,数据绑定最简单的方式是使用 Mustache 语法(双大括号)将变量包起来。在 {{ }} 内部可以做一些简单的运算,支持如下几种方式:

  • 算数运算
  • 三元运算
  • 逻辑判断
  • 其他…

📌 注意事项:

  • {{ }} 语法中,只能写表达式,不能写语句,也不能调用 js 相关的方法

使用数据:

➡️ pages/index/index.wxml


<!-- 直接使用 -->
<view>{{ school }}</view>
<view>{{ obj.name }}</view>

<!-- 绑定属性值,如果需要动态绑定一个变量,属性值也需要使用双大括号进行包裹 -->
<view id="{{ id }}">绑定属性值</view>

<!-- 如果属性值是布尔值,也需要使用双大括号进行包裹 -->
<checkbox checked="{{ isChecked }}" />

<!-- 算术运算 -->
<view>{{ id + 1 }}</view>
<view>{{ id - 1 }}</view>

<!-- 三元运算 -->
<view>{{ id === 1 ? '等于' : '不等于' }}</view>

<!-- 逻辑判断 -->
<view>{{ id === 1 }}</view>

➡️ pages/index/index.js

Page({
  // 在小程序页面中所需要使用的数据均来自于 data 对象
  data: {
    id: 1,
    isChecked: false,
    school: '尚硅谷',
    obj: {
      name: 'tom'
    }
  }
})

2.【声明和修改数据】

小程序中修改数据并不能直接进行赋值,而是要通过调用 this.setData 方法才能实现

this.setData 方法有两个作用:

  1. 更新数据
  2. 驱动视图更新
Page({
  // 页面的初始数据
  data: {
    num: 1
  },

  updateNum() {
    this.setData({
      // key 是需要修改的数据
      // value 是最新值
      num: this.data.num + 1
    })
  }
 
  // coding...
}

2-1. setData-修改对象类型数据

  • 定义一个对象

    Page({
      // 定义页面中使用的数据
      data: {
        userInfo: {
          name: 'Tom',
          age: 10,
          gender: '男'
        }
      }
    }
    
  • 修改对象中的单个属性:

    this.setData({
      'userInfo.name': 'Jerry'
    })
    
  • 修改对象中的多个属性

    // 修改对象中的多个属性
    this.setData({
      'userInfo.name': 'Jerry',
      'userInfo.age': 100
    })
    
  • 使用 ES6 的展开运算符

    在修改对象类型的数据时,可以使用 ES6 的展开运算符先复制对象,然后利用新值对旧值覆盖的方式修改

    // 修改对象中的多个属性
    this.setData({
       ...this.data.userInfo,
      name: 'Jerry',
      age: 100
    })
    
  • 使用 Object.assign 方法合并对象

    // 使用 Object.assign 方法将多个对象合并为一个对象
    // 修改对象中的多个属性
    this.setData({
      userInfo:Object.assign(this.data.userInfo, { name: 'Jerry' },{ age: 100 })
    })
    
  • 删除对象中的属性

    📌 注意事项:在删除对象中的属性时,不能使用 delete 操作符,因为小程序的数据绑定机制不支持监听 delete 操作

    // 使用展开运算符拷贝一份数据,产生一个新对象
    const newUser = { ...this.data.userInfo }
    // 使用 delete 删除新对象中的属性
    delete newUser.age
    
    this.setData({
      // 将新的对象进行赋值
      userInfo: newUser
    })
    

2-2. setData-修改数组类型数据

  • 定义一个数组

    Page({
      // 定义页面中使用的数据
      data: {
        animalList: ['Tom', 'Jerry', 'Spyke']
      }
    })
    
  • 使用数组的 concat 方法合并数组

    在修改数组类型的数据时,可以使用数组的 concat 方法来合并数组

    // 使用 concat 方法来合并数组
    this.setData({
      animalList: this.data.animalList.concat('Tyke')
      animalList: this.data.animalList.concat(['Donald','HUge'])
    })
    
  • 使用数组的 push 方法新增属性

    在修改数组类型的数据时,可以使用数组的 push 方法来添加元素

    this.setData({
      animalList: this.data.animalList.push('Tyke')
    })
    
  • 使用 ES6 的展开运算符

    在数组类型的数据时,可以使用 ES6 的展开运算符先复制数组,然后进行合并

    this.setData({
      animalList: [...this.data.animalList, 'Tyke']
    })
    
  • 修改数组中某个元素的值:

    利用索引的方式进行修改,但必须使用 wx:for 来进行渲染数组,否则会出现错误

    this.setData({
      'animalList[2]': 'Tyke' 
    })
    
  • 使用数组的 filter 方法删除元素

    在修改数组类型的数据时,可以使用数组的 filter 方法来删除元素

    this.setData({
      animalList: this.data.animalList.filter(item => item !== 'Tom')
    })
    

3.【数据绑定-简易双向绑定】

  • 【单项绑定】 在 WXML 中,普通属性的绑定是单向的,例如:

    <input value="{{ num }}" />
    

    如果使用 this.setData 来更新 numnum 和输入框的中显示的值都会被更新为值。但如果用户修改了输入框里的值,却不会同时改变 data 中的 num

  • 【双向绑定】

    如果需要在用户输入的同时也将 data 中的数据修改 ,需要借助简易双向绑定机制。此时可以在对应项目之前加入 model: 前缀即可,例如:

    <input model:value="{{ value }}" />
    

    如果使用 this.setData 来更新 numnum 和输入框的中显示的值都会被更新为值。如果输入框的值被改变了, data 的数据也会随着改变。同时, WXML 中所有绑定了数据的位置也会被一同更新

📌 注意事项 --简易双向绑定的属性值如下限制:

  1. 只能是一个单一字段的绑定,例如:错误用法:<input model:value="值为 {{value}}" />

  2. 尚不能写 data 路径,也就是不支持数组和对象,错误用法:<input model:value="{{ a.b }}" />

落地代码:

<!-- 单向绑定:数据能够影响页面,但是页面更新不会影响到数据 -->
<input type="text" value="{{ value }}" />

<!-- 双向绑定:数据能够影响页面,页面更新也能够影响数据 -->
<!-- 如果想实现简易双向绑定,需要再对应的属性之前添加 model: -->
<input type="text" model:value="{{ value }}" />

<!-- 如果需要获取复选框的选中效果,需要给 checked 添加 model: -->
<checkbox model:checked="{{ isChecked }}" /> 是否同意该协议

<!-- 错误写法1:属性值只能是一个单一字段的绑定  -->
<input type="text" model:value="值为 {{ value }}" />

<!-- 错误写法2:属性值不能写数据路径,也就是不支持对象和数组 -->
<input type="text" model:value="{{ obj.value }}" />

4.【列表渲染-基本使用】

  • 基本使用

    表渲染:就是指通过循环遍历一个数组或对象,将其中的每个元素渲染到页面上;只需要在组件上使用 wx:for 属性绑定一个数组,即可使用数组中各项的数据重复渲染该组件

    • 默认数组当前项的变量名默认为 item
    • 默认数组的当前项的下标变量名默认为 index
    • 在使用 wx:for 对数组进行遍历的时候,建议加上 wx:key 属性,如不提供 wx:key,会报一个 warning, 如果明确知道该列表是静态,即以后数据不会改变,或者不必关注其顺序,可以选择忽略。

    落地代码:

    
    <!-- 如果渲染的是数组,item:数组的每一项,index:下标 -->
    <view wx:for="{{ numList }}"> {{ item }} - {{ index }} </view>
    
    <!-- 如果渲染的是对象,item:对象属性的值,index:对象属性 -->
    <view wx:for="{{ obj }}"> {{ item }} - {{ index }} </view>
    
    <!-- ------------------------ 关于 Key --------------------------------- -->
    
    <!-- wx:key 提升性能 -->
    <!-- wx:key 的属性值不需要使用双大括号进行包裹,直接写遍历的数组 中 item 的某个属性 -->
    
    <!-- wx:key 属性值有两种添加形式 -->
    <!-- 字符串,需要是遍历的数组 中 item 的某个属性,要求该属性是列表中唯一的字符串或者数字,不能进行动态改变 -->
    <view wx:for="{{ fruitList }}" wx:key="id">{{ item.name }}</view>
    <view wx:for="{{ fruitList }}" wx:key="index">{{ item.name }}</view>
    
    <!-- 保留关键字 *this,*this 代表的是 item 本身,item 本身是唯一的字符串或者数字 -->
    <view wx:for="{{ numList }}" wx:key="*this">{{ item.price }}</view>
    
    
    // profile.js
    Page({
    
      data: {
        numList: [1, 2, 3],
        fruitList: [
          { id: 1, name: '🍎', price: 66 },
          { id: 2, name: '🍋', price: 77 },
          { id: 3, name: '🍅', price: 88 }
        ],
        obj: {
          name: 'tom',
          age: 10
        }
      }
    })
    
    
  • 使用进阶

    修改默认下标和变量名:

    如果需要对默认的下标和变量名进行修改,可以使用 wx:for-itemwx:for-index

    1. 使用 wx:for-item 可以指定数组当前元素的变量名

    2. 使用 wx:for-index 可以指定数组当前下标的变量名

    <view wx:for="{{ animal }}" wx:for-item="itemName" wx:for-index="i">
      {{ itemName.name }} - {{ itemName.avatar }} - {{ i }}
    </view>
    

    渲染多节点结构块:

    如果需要渲染一个包含多节点的结构块,可以使用一个 <block/> 标签将多个组件包装起来

    <block wx:for="{{ animal }}">
      <view>
        <span>{{ item.name }}</span>
        <span>{{ item.avatar }}</span>
      </view>
    </block>
    

    📌 注意事项: <block/> 并不是一个组件,它仅仅是一个包装元素,不会在页面中做任何渲染,只接受控制属性。

5.【条件渲染】

知识点:

条件渲染主要用来控制页面结构的展示和隐藏,在微信小程序中实现条件渲染有两种方式:

  • 使用 wx:ifwx:elifwx:else 属性组
  • 使用 hidden 属性
<view wx:if="{{show}}"> True </view>
<view wx:if="{{length > 5}}"> 类型一 </view>
<view wx:elif="{{length > 2}}"> 类型二 </view>
<view wx:else> 类型三 </view
<view hidden="{{show}}"> True </view>

wx:ifhidden 二者的区别:

  • wx:if :当条件为 true 时将内容渲染出来,否则元素不会进行渲染,通过移除/新增节点的方式来实现
  • hidden :当条件为 true 时会将内容隐藏,否则元素会显示内容,通过 display 样式属性来实现的

五、生命周期

1.【小程序运行机制】

image.png

  • 冷启动与热启动:

    小程序启动可以分为两种情况,一种是冷启动,一种是热启动

    冷启动:如果用户首次打开,或小程序销毁后被用户再次打开,此时小程序需要重新加载启动

    热启动:如果用户已经打开过某小程序,然后在一定时间内再次打开该小程序,此时小程序并未被销毁,只是从后台状态进入前台状态

  • 前台 以及 后台状态:

    小程序启动后,界面被展示给用户,此时小程序处于「前台」状态。

    当用户「关闭」小程序时,小程序并没有真正被关闭,而是进入了「后台」状态,当用户再次进入微信并打开小程序,小程序又会重新进入「前台」状态

    切后台的方式包括但不限于以下几种:

    1. 点击右上角胶囊按钮离开小程序
    2. 安卓点击返回键离开小程序
    3. 屏幕左侧右滑离开小程序
  • 挂起:

    小程序进入「后台」状态一段时间后(5 秒),微信停止小程序 JS 线程执行,小程序进入「挂起」状态,当开发者使用了后台播放音乐、后台地理位置等能力时,小程序可以在后台持续运行,不会进入到挂起状态

  • 销毁:

    如果用户很久没有使用小程序,或者系统资源紧张,小程序会被销毁,即完全终止运行。

    当小程序进入后台并被「挂起」后,如果很长时间(目前是 30 分钟)都未再次进入前台,小程序会被销毁

    当小程序占用系统资源过高,可能会被系统销毁或被微信客户端主动回收。

2.【小程序更新机制】

在访问小程序时,微信会将小程序代码包缓存到本地。

开发者在发布了新的小程序版本以后,微信客户端会检查本地缓存的小程序有没有新版本,并进行小程序代码包的更新。

小程序的更新机制有两种:启动时同步更新启动时异步更新

  • 启动时异步更新

    启动时同步更新:微信运行时,会定期检查最近使用的小程序是否有更新。如果有更新,下次小程序启动时会同步进行更新,更新到最新版本后再打开小程序。如果 用户长时间未使用小程序时,会强制同步检查版本更新

  • 启动时异步更新

    启动时异步更新:在启动前没有发现更新,小程序每次 冷启动 时,都会异步检查是否有更新版本。如果发现有新版本,将会异步下载新版本的代码包,将新版本的小程序在下一次冷启动进行使用,当前访问使用的依然是本地的旧版本代码

    在启动时异步更新的情况下,如果开发者希望立刻进行版本更新,可以使用 wx.getUpdateManager API 进行处理。在有新版本时提示用户重启小程序更新新版本。

    App({
    
      /**
       * 当小程序初始化完成时,会触发 onLaunch(全局只触发一次)
       */
    
      onLaunch: function () {
        const updateManager = wx.getUpdateManager()
    
        updateManager.onCheckForUpdate(function (res) {
          // 请求完新版本信息的回调
          console.log(res.hasUpdate)
        })
    
        updateManager.onUpdateReady(function () {
          wx.showModal({
            title: '更新提示',
            content: '新版本已经准备好,是否重启应用?',
            success(res) {
              if (res.confirm) {
                // 新的版本已经下载好,调用 applyUpdate 应用新版本并重启
                updateManager.applyUpdate()
              }
            }
          })
        })
    
        updateManager.onUpdateFailed(function () {
          // 新版本下载失败
        })
      }
    
    })
    

    落地代码:

    // app.js
    App({
    
      // onLaunch 是小程序的钩子函数,这个钩子函数在冷启动时肯定会执行到
      // 当小程序冷启动时,会自动微信后台请求新版本的信息,如果有新版本,会立即进行下载
      onLaunch () {
        // 使用 wx.getUpdateManager 方法监听下载的状态
        const updateManager = wx.getUpdateManager()
    
        // 当下载完成新版本以后,会触发 onUpdateReady 回调函数
        updateManager.onUpdateReady(function () {
          // 在回调函数中给用户提示,
          wx.showModal({
            title: '更新提示',
            content: '新版本已经准备好,是否重启应用?',
            success(res) {
              if (res.confirm) {
                // 强制当前小程序使用新版本并且会重启当前小程序
                updateManager.applyUpdate()
              }
            }
          })
        })
      }
    
    })
    
    

3.【生命周期介绍】

  • 应用生命周期是指应用程序进程从创建到消亡的整个过程

  • 小程序的生命周期指的是小程序从启动到销毁的整个过程

    小程序的生命周期分为三类:应用级别、页面级别和组件级别 3 种类型,我们先学习应用级别和页面级别的生命周期

4.【应用级别生命周期】

知识点:

应用生命周期通常是指一个小程序从 启动 → 运行 → 销毁的整个过程

应用生命周期伴随着一些函数,我们称为 应用生命周期函数,应用生命周期函数需要 在 app.js 文件的 App() 方法中定义

当整个小程序应用运行到某个时机的时候,我们需要做一些事情。例如:当小程序启动成功之后,我们要获取小程序的一些信息,就可以在小程序启动成功时的钩子函数中写代码获取我们想要的信息。

生命周期必填说明
onLaunch监听小程序初始化,全局只会执行 1 次
onShow监听小程序启动或切前台
onHide监听小程序切后台

image.png

📌 注意事项:

  1. 从小程序生命周期的角度来看,我们一般讲的「启动」专指冷启动,热启动一般被称为后台切前台。

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

小程序启动后,后台会首先完成小程序的初始化,该过程只会触发一次;之后会完成显示的工作,用户可以操作小程序从前台进入后台以及从后台回复到前台显示;小程序在后台运行一段时间,当系统资源不足时会被注销。

落地代码:

➡️ app.js

App({
  /**
   * 当小程序初始化完成时,会触发 onLaunch(全局只触发一次)
   */
  onLaunch: function () {
    // 监听小程序初始化
    console.log('onLaunch: 当小程序初始化完成时,会触发 onLaunch')
  },

  /**
   * 当小程序启动,或从后台进入前台显示,会触发 onShow
   */
  onShow: function (options) {
    // 监听小程序的显示
    console.log('onShow: 当小程序启动,或从后台进入前台显示')
  },

  /**
   * 当小程序从前台进入后台,会触发 onHide
   */
  onHide: function () {
    // 监听小程序的隐藏
    console.log('onHide: 小程序从前台进入后台')
  }
})

5.【页面级别生命周期】

知识点:

页面生命周期就是指小程序页面从 加载 → 运行 → 销毁的整个过程

当某个页面运行到某个时机的时候,我们需要做一些事情,例如: 当某个页面加载完毕之后,需要发请求获取当前页面所需的数据,就可以在对应的页面加载完成后的钩子函数中执行发送请求的代码。

小程序中的一个页面都需要在对应页面的 .js 文件中调用 Page() 方法来注册。Page() 接受一个 Object 类型参数,其指定页面的初始数据、生命周期回调、事件处理函数等。

生命周期必填说明
onLoad页面加载时触发 (一个页面只会调用一次)
onShow页面显示时触发,页面显示/切入前台时触发
onReady页面初次渲染完成时触发(一个页面只会调用一次)
代表页面已经准备妥当,可以和视图层进行交互
onHide页面隐藏/切入后台时触发
onUnload页面卸载时触发

image.png

落地代码:

// pages/home/home.js
Page({
   
  // coding...
    
  // 生命周期函数--监听页面加载
  onLoad: function (options) {
    console.log('页面加载完毕')
  },

  // 生命周期函数--监听页面显示
  onShow: function () {
    console.log('监听页面显示,此时页面处于显示状态')
  },

  // 生命周期函数--监听页面初次渲染完成
  onReady: function () {
    console.log('页面初次渲染已经完成')
  },

  // 生命周期函数--监听页面隐藏
  onHide: function () {
    console.log('当前页面处于隐藏状态')
  },

  // 生命周期函数--监听页面卸载
  onUnload: function () {
    console.log('页面卸载时触发')
  }
})

5.【生命周期两个细节补充说明】

  1. tabBar 页面之间相互切换,页面不会被销毁

    image.png

  2. 点击左上角,返回上一个页面,会销毁当前页面(被打开页面)

    image.png

六、微信原生 API

小程序 API 介绍

微信小程序 API 文档

1.【API 基础】

小程序开发框架提供丰富的微信原生 API,可以方便的调起微信提供的能力,如获取用户信息,本地存储,支付功能等,几乎所有小程序的 API 都挂载在 wx 对象底下,例如:wx.chooseMedia()wx.request(), wx 对象实际上就是小程序的宿主环境微信所提供的全局对象

通常,在小程序 API 有以下几种类型:

image.png

  1. 事件监听 API:约定以 on 开头 API 用来监听某个事件是否触发,例如:wx.onThemeChange()

  2. 同步 API:约定以 Sync 结尾的 API 都是同步 API,例如:wx.setStorageSync()

  3. 异步 API:大多数 API 都是异步 API,例如:wx.setStorage()

    异步 API 支持 callback & Promise 两种调用方式:

    • 当接口参数 Object 对象中不包含 success/fail/complete 时将默认返回 Promise

    • 部分接口如 request, uploadFile 本身就有返回值,因此不支持 Promise 风格的调用方式,它们的 promisify 需要开发者自行封装。

1.【生命周期两个细节补充说明】

1.【生命周期两个细节补充说明】

1.【生命周期两个细节补充说明】