4

微信小程序从零入门的文章实暂时就到这里了,还有一个生命周期的内容,感觉当初整理的不是很好就不写了,主要最近时间有点紧张,没时间改....

学完了 WXML、WXSS、一些常用组件,还有事件绑定,其实一个较为不错的页面已经能自己搭建出来了,如果你还想继续往后面研究,就可以开始看 与后台交互的内容了,发送异步请求,对数据进行回显等,回显内容时,你就又可以开始考虑用什么别的组件,可以让页面的数据加载或者观看更加顺滑,美观,当然有很多小伙伴都是后端,所以,可以自己搭个后台,试着弄用户登录授权这块,这块算是小程序一个重要的点,要好好研究一下,以后要做的事情,就和传统的后端基本一样了。我的文章都是根据官网写的原生写法,当然你也可以看一下一些小程序框架,或者看一看 ES6 的内容,毕竟我也是个后端,也没细细研究前端的内容

再接着就可以自己动手写点东西了,不会的组件或者内容就去查官方文档,查别人的博客,写着写着,就发现又认识了 N 个 东西,或许你就会用到 模板、swiper,然后自然而然的对小程序的生命周期有了一定的认识等等

可能在一定意义上,能自己手写一个不算太简陋的项目,才算真的入门了是不,啊哈哈哈

【微信小程序出发】

(一) 准备工作

(1) 登录注册

  • 注册账号:这就不谈了,只需要注意使用一个全新的邮箱,别之前注册过公众号小程序等就可以了

    • https://mp.weixin.qq.com/wxopen/waregister?action=step1
  • 登录账号:通过邮箱密码登录,亦或者绑定微信后使用扫码也是可以的

    • https://mp.weixin.qq.com/

(2) 获取 APPID

登录后,在开发入门的阶段有一个比较重要的内容需要了解,那就是 APPID,很好理解,就是这个小程序的唯一标识,就类似我们的身份证,登录后首页左侧栏选择【开发】,跳转后,选择【开发设置】就可以看到我们的 APPID

这个 APPID 要记好哈,在刚开始学习的时候,就会使用到

(3) 下载工具

在官网选择一个合适的版本进行下载,这就是我们小程序的编译器,这里我选择的是开发版,不过选择稳定版也是可以的,针对入门并没有太大的区别,不过稳定版可能出现的小毛病会少一些

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

安装好后,直接提示扫码登录,接着就是点击左侧【小程序】,然后点击右侧【新建】(一个大加号)填写一些基本的信息

  • 项目名称和目录:自己看着弄就可以了
  • APPID:之前页面中找到的 APPID 在这个时候就可以用的上了,虽然你使用测试号也是可以进入的,到底后面还是要用自己的 ID 的。
  • 开发模式:小程序
  • 后端服务:不使用云服务,前面还是以学习小程序本身为主,不使用此选项
  • 语言:JavaScript 和 Typescript,根据自身的熟悉程序选择即可

新建后,第一个小程序就完事了哈~

(二) 初识小程序

(1) 界面总览

下面的区域就是一个初始化新建好的项目界面了,图片中标的很清楚,每一块的具体内容,第一次创建项目时,也可以在设置的通用设置中将默认的的工作区以及主题(浅色还是深色)根据自己的需要修改

说明:直接在小程序官方的工具中编写代码也可以,不过我个人选择配合 vscode 或 sublime 进行代码的编辑,在微信官方开发工具或者那个查看结果以及控制台的一些信息

(2) 文件类型

与传统的网页开发有一丝小不同,微信小程序重新定义了它的描述语言,例如 wxml、wxss 等,同时还额外提供了一层 JSON 的配置文件

wxml(页面结构文件)

  • 用来书写、构建页面,类似传统网页开发的 HTML

wxss(样式表文件)

  • 用于制定页面样式,从而美化页面,类似传统网页开发的 CSS

js(脚本文件)

  • 用于指定一定页面交互逻辑,就是 Javascript

json(静态数据配置文件)

  • JSON 格式的配置文件,设置程序的一些配置效果

(3) 结构目录

A:总体介绍

通过官方开发工具或者vscode等其他编辑器,你可以看到,新建一个项目后,会默认生成一个初始化的项目结构,里面含有很多文件,其后缀格式都是我们上面介绍过的

下面我们针对一些主要的内容进行一个基本的介绍

├── pages                             // 页面文件夹
|    ├── index                            // 首页
│   |    ├── index.js                  // 首页逻辑脚本文件
│   |    ├── index.json                  // 首页配置文件
│   |    ├── index.wxml                    // 首页页面结构文件
│   |    ├── index.wxss                  // 首页样式文件

|    ├── logs                            // 日志页面
│   |    ├── logs.js                        // 日志页面逻辑脚本文件
│   |    ├── logs.json                  // 日志页面配置文件
│   |    ├── logs.wxml                    // 日志页面页面结构文件
│   |    ├── logs.wxss                  // 日志页面样式文件

|    ├── utils                            // 工具js文件(第三方,可删除)
│   |    ├── util.js                        // 日志页面逻辑脚本文件

│   ├── app.js                          // 项目的全局脚本文件
│   ├── app.json                      // 项目的全局配置文件
│   ├── app.wxss                      // 项目的全局配置文件
│   ├── project.config.json              // 项目的开发者工具的配置
│   ├── sitemap.json                  // 索引配置文件

具体的一些例如 wxml wxss 等的用法,会在后面提到,这里我们还要提一下两个内容:

A:针对说明

app.js:项目的入口文件,用来创建应用程序的对象,处理程序的生命周期

app.json:项目全局的配置文件,涉及到了页面的路径,界面/窗口 的表现时间,网格超时的时间,还有小程序底部的 tab 等等,还是非常重要的,初始化新建项目后,可以看到如下pages 字段和 windows 字段

{
  "pages":[
    "pages/index/index",
    "pages/logs/logs"
  ],
  "window":{
    "backgroundTextStyle":"light",
    "navigationBarBackgroundColor": "#fff",
    "navigationBarTitleText": "WeChat",
    "navigationBarTextStyle":"black"
  }
}
  • pages 字段,是关于页面路径的,也就是给客户端说明出你小程序页面到底在哪里
  • window 字段,对应 页面的颜色、标题等等
  • tabbar 字段,底部 tab 栏(切换页面)

贴一段官网关于tabbar的说明(官网的说明确实很可!):

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

属性类型必填默认值描述
colorHexColor tab 上的文字默认颜色,仅支持十六进制颜色
selectedColorHexColor tab 上的文字选中时的颜色,仅支持十六进制颜色
backgroundColorHexColor tab 的背景色,仅支持十六进制颜色
borderStylestringblacktabbar 上边框的颜色, 仅支持 black / white
listArray tab 的列表,详见 list 属性说明,最少 2 个、最多 5 个 tab
positionstringbottomtabBar 的位置,仅支持 bottom / top
custombooleanfalse自定义 tabBar,最低需要 2.5 版本

而一般我们想要设置出常见的效果就会选择使用 list 进行配置

属性类型必填说明
pagePathstring页面路径,必须在 pages 中先定义
textstringtab 上按钮文字
iconPathstring图片路径,icon 大小限制为 40kb,建议尺寸为 81px * 81px,不支持网络图片。 positiontop 时,不显示 icon。
selectedIconPathstring选中时的图片路径,icon 大小限制为 40kb,建议尺寸为 81px 81px,不支持网络图片。 positiontop 时,不显示 icon。*

给大家举个例子,书写的格式就是这样的,别忘了制定了 tabbar 一定要有在pages中设置对应的页面哦

"tabBar": {
    "color": "#999",
    "selectedColor": "#ff2d4a",
    "backgroundColor": "#fafafa",
    "position": "bottom",
    "borderStyle": "black",
    "list": [
      {
        "pagePath": "pages/index/index",
        "text": "首页",
        "iconPath": "icons/home.png",
        "selectedIconPath": "icons/home.png"
      },
      {
        "pagePath": "pages/user/index",
        "text": "我的",
        "iconPath": "icons/my.png",
        "selectedIconPath": "icons/my.png"
      }
    ]
  },

每一个小程序页面也可以使用 .json 文件来对本页面的窗口表现进行配置。页面中配置项在当前页面会覆盖 app.jsonwindow 中相同的配置项。同样的,也有很多配置内容,看一下官网就可以了

https://developers.weixin.qq.com/miniprogram/dev/reference/configuration/page.html

—————分割线—————

【WXML 常用语法】

(一) WXML 是什么

官方说明:WXML(WeiXin Markup Language)是框架设计的一套标签语言,结合基础组件、事件系统,可以构建出页面的结构

在前面我们就已经提过,WXML,就可以理解为我们传统页面中的HTML,它是微信为我们提供的一套标签语言,可以说它就是我们小程序的脸面(虽然没经过CSS装饰前不一定光鲜亮丽),开发中 WXML 页面就作为我们一些逻辑行为的入口,以及效果展示的承载者。

再大白话一点:你所看到的小程序页面长什么样(不涉及背后做了什么行为,只说表面),就是 WXML(主要) + WXSS (美化) 实现的

这一篇,我们主要涉及到的是 WXML 中例如数据绑定、或者运算等等,但是学习之前,很显然,我们需要认识几个常见的标签,后面我们会总结一些常用的标签,下面会用到的有:

<text></text><view></view> <image></image> 还有一些标签,大家去看官网文档就可以了,写的非常清楚,我们这里重点还是说一下关于其中的一些标签语法问题

官网——WXML语法文档

https://developers.weixin.qq.com/miniprogram/dev/reference/wxml/

官网——组件文档

https://developers.weixin.qq.com/miniprogram/dev/component/

<!--pages/demo01/demo01.wxml-->

<!-- text 不会换行,可以理解为传统页面中的 span 行内元素-->
<text>这是text标签1</text>
<text>这是text标签2</text>

<!-- view 会换行,可以理解为传统页面中的 div 块级元素 -->
<view>这是div标签1</view>
<view>这是div标签2</view>

<view>
  <!-- 我博客的图,显示如果出现什么问题,自己替换一下哈 -->
  <image  mode='widthFix' style='width:60%' src='https://www.ideal-20.cn/medias/avatar.jpg'></image>
</view>

看一下效果

(二) 数据绑定

虽然还不涉及到什么页面的美化,以及复杂的标签,不过一个极为简单的静态页面现在已经可以构造出来了,归根结底,我们最后都是要进行前后台数据的交互的,而微信小程序就为我们提供了很多很好用的用法,能很快的进行数据的绑定操作

有一个前提条件,我们先模拟一些数据,我们只需要在页面的 js 文件中的 data对象中定义小程序初始化的数据,例如下面代码,我们随便拿一些常见的数据类型来模拟一下

Page({
  /**
   * 页面的初始数据
   */
  data: {
    msg: "你好,微信小程序",
    status: 100,
    isLogin: true,
    person:{
      name: "张三",
      age: 22,
      profession: "student"
    },
    isChecked: true
  },
})

(1) 常见类型普通写法

如何在 WXML 标签组件中进行数据的绑定其实是非常简单的,微信小程序中通过 {{}} 来解析刚才在 JS 中模拟的变量

要注意:直接通过 {{}} 解析的变量都是 页面 js 文件中 Page --> data 下的

A:字符串

字符串内容直接用两个大括号括住接收就可以了,在上面我们有这样的定义:

msg: "你好,微信小程序", 所以直接括住 msg 就可以获取到后面的值了

<view>{{msg}}</view>

B:数值

数值也是一样直接可以获取

<view>{{status}}</view>

C:布尔类型

布尔类型第一个代码是直接打印出其布尔类型 true 或者 false

<view>{{isLogin}}</view>

而下面配合 checkbox 就可以实现是否选中的效果

<view>
    <checkbox checked="{{isChecked}}"></checkbox>
</view>

D:对象

对象这块如果你直接打印 person 就会输出一个 Object 类型,所以如果想要拿到对象的属性值,一定要指定到具体的属性

<view>{{person.name}}</view>
<view>{{person.age}}</view>
<view>{{person.profession}}</view>

看一下上述所有的绑定效果

(2) 组件属性中

例如我们 view 组件的 id 值前缀是固定的 user- 后面就是用户的序号,这时候就可以通过变量来进行巧妙的解析到属性中了

注:不要轻易的乱加空格,否则可能会读取失败例如: <view id=" user-{{uid}}"></view>

<view id="user-{{uid}}"></view>

看一下 Wxml 的源码 id 这个属性中已经进行了拼接,这种方式同样还会常用在 class 或者 style 中,配合三元运行能不错的实现一些需求,下面我们会提到

(三) 运算

首先我们依旧定义一些数据,三个整数,和两个字符串

Page({
  data: {
    a: 11,
    b: 22,
    c: 33,
    msg: "姓名",
    name: "张三"
  },
})

(1) 算数运算

直接在 {{}} 中进行 加减乘除等的运算,直接就可以得到结算的结果,例如:

<view>{{a + b + c}}</view>
<view>{{a + b}} + {{c}}</view>

(2) 字符串运算

如果是字符串类型的数据,利用 + 进行运算,结果是一个拼接的效果

<view>{{'a' + 'b' + 'c'}}</view>
<view>{{'11' + '22' + '33'}}</view>
<view>{{msg + ':' +name}}</view>

(3) 逻辑判断

这个就是常见的 if 判断,例如使用 wx:if 这个属性,那么就只有在后面的表达式为 true 的情况下才会显示文本 a 大于 0

<view wx:if="{{a > 0}}">a 大于 0</view>

(4) 三元运算

三元运算的应用场景还是很多的(等式 ? : true情况,false的情况)

<view>{{11 + 22 === 33 ? true : false}}</view>
<view>{{11 + 22 === 33 ? '正确' : '错误'}}</view>
<view>{{a + b === c ? '等式成立' : '等式不成立'}}</view>

三元补充:

通过在属性中解析变量的方式,可以达到根据变量的值,来指定不同的 class名,以显示不同的样式

例如我们的 css 样式是这样的,iconfont 是我们共用的,所以直接写在属性中就可以了,而究竟是用 icon-back 还是 icon-remove 就可以通过一个变量来操纵,例如我们下面的 isClick 就是在 js 里 data 中定义的一个 布尔类型的变量

.iconfont {......}
.icon-back:before {......}
.icon-remove:before {......}

当 isClick 为 true 就执行 class 就是这样的 class="iconfont icon-remove" 为 false 就是用另一个,我们就可以通过 控制变量值来进行不同的显示

<icon class="iconfont {{isClick ? 'icon-remove':'icon-back'}}"

看一下上述所有运算的执行结果(不含补充的结果)

(四) 列表循环(列表渲染)

(1) 模拟数据

依旧我们给一些模拟数据,一个是 person 这样的对象内部有一些属性,还有一个就是 studentList 学生集合,其中有三个学生的数据

Page({
  data: {
    person:{
      pid: 1,
      name: "张三",
      age: 22,
      profession: "student"
    },
    studentList:[{
        sid:1,
        name:"汤姆",
        gender:"男"
      },{
        sid:2,
        name:"杰克",
        gender:"男"
      },{
        sid:3,
        name:"玛丽",
        gender:"女"
      }
    ]
  },
})

如果我们接受到了后台的一些集合或者数组等内容,循环遍历是一个非常常用的操作

(2) 正式使用

组件(标签)上使用 wx:for 就可以绑定一个数组或集合内容,就可用数组中各项的数据重复渲染该组件

先举个例子

<view>
    <view 
    wx:for="{{studentList}}" wx:for-item="item" wx:for-index="index" wx:key="sid">
        {{index}} --- {{item.name}} 
    </view>
</view>

我们分别来解释一下:

  • wx:for:数组或者对象
  • wx:for-item:循环项(数组或集合)的变量名称,同时一般默认为 item
  • wx:for-index:循环项(数组或集合)的索引(下标),同时一般默认为 index
  • wx:key:绑定一个唯一的值,可以提高列表渲染的性能,可以简单理解为主键的概念,例如这里我传入了 studentList 中不可能重复的值 sid

    • 如果你的数组只是一个普通的数组,例如 [11,22,65,23,3,6] 没有所谓唯一的值,就可以使用 wx:key="*this" 即表示你的数组是一个普通的数组,*this 表示的是 item 本身

如果传这个 key 值,会有一个警告弹出

(3) 嵌套用法的补充说明

  • 如果你的循环只有一层,那么 wx:for-item="item" wx:for-index="index" 这两个内容实际上是可以省略的,小程序会自动把这两个内容设置为 item 和 index
  • 如果你的循环是一个嵌套的效果,那么切记一定 item 和 index 的值一定不要重复...

嵌套的正确写法

<view wx:for="{{[1, 2, 3, 4, 5, 6, 7, 8, 9]}}" wx:for-item="i" wx:key="*this">
  <view wx:for="{{[1, 2, 3, 4, 5, 6, 7, 8, 9]}}" wx:for-item="j" wx:key="*this">
    <view wx:if="{{i <= j}}" wx:key="*this">
      {{i}} * {{j}} = {{i * j}}
    </view>
  </view>
</view>

再举一个例子(遍历对象的所有属性):

<view>
    <view wx:for="{{person}}" wx:for-item="value" wx:for-index="key" wx:key="pid">
    {{key}} --- {{value}} 
    </view>
</view>

看一下执行效果

(4) 循环(渲染)block标签

如果我们使用两种不同的组件(标签)看看最终渲染出来的结果有什么区别呢?

方法一(view 标签)

<view wx:for="{{person}}" wx:for-item="value" wx:for-index="key" wx:key="pid">
    {{key}} --- {{value}} 
</view>
  • 结果一
<view> pid --- 1 </view>
<view> name --- 张三 </view>
<view> age --- 22 </view>
<view> profession --- student </view>

方法二(block 标签)

<block wx:for="{{person}}" wx:for-item="value" wx:for-index="key" wx:key="pid">
    {{key}} --- {{value}} 
</block>
  • 结果二
pid --- 1 name --- 张三 age --- 22 profession --- studen

通过控制台中 Wxml 界面,可以看到,只有在 view 组件下遍历内容时才真正的生成了 dom 结构,而直接使用 block 则只是将内容重复写了几次,不会变成真正的dom元素

(五) 逻辑判断(条件渲染)

(1) 用法

这块理解没什么难点,无非就是关于逻辑的几种判断,看一个例子就清楚了

说明:isLogin 是在 js 中模拟的一个数据,分别赋予 true false 或者其他的 例如 null,会根据逻辑值显示不同的内容

<view wx:if="{{isLogin == true}}">已经登录,逻辑为 true</view>
<view wx:elif="{{isLogin == false}}">未登录,逻辑为 false</view>
<view wx:else>不确定逻辑</view>

(2) 补充 hidden

补充用法(hidden):

通过上面的 if else 等可以控制组件例如 view 的显示,而有一个属性 hidden 同样可以实现根据逻辑值控制组件的显示

例如给 hidden 传入一个 false 就会显示出来

<view hidden="{{false}}">不隐藏</view>

(3) wx:if 和 hidden 选择哪个

那么既然一定程度上都可以达到这种效果,我们选择那个呢?

先来看一下

<view>---- 分界线 -----</view>
<view wx:if="{{false}}">if 隐藏</view>
<view hidden="{{true}}">隐藏</view>

看一下渲染出来的结构,关于 wx:if 的那块直接就没有渲染出来了,只有 hidden 的那个,由此可以得出:

  • wx:if 是直接把标签从页面结构中移除掉了
  • hidden 是通过添加样式的方式的隐藏,标签结构还在

所以,当标签不总是切换显示的时候,可以考虑先用 wx:if ,标签切换频繁的时候用 hidden

(六) 模板

(1) 创建模板

模板的字面意思就是,一个可以应用在多处,通用的一个版块,如何去用呢?

使用 name 属性,作为模板的名字。然后在 <template/> 内定义代码片段

<template name="test1">
  <view>
    <text> 这是一个 template 模块 </text>
    <text> {{id}}: {{name}} </text>
  </view>
</template>

(2) 引入模板

我们需要在想引用模板的页面中引入模板,WXML 提供两种文件引用方式 importinclude

如果没有效果,可以看一下是不是路径写错了,要根据自己定义的来写哦

<import src="../../template/test1/test1" />

<include src="../../template/test1/test1" />

这两者的区别就是 import 有作用域的问题,官网这里写的挺清楚,我直接贴一下:

import 有作用域的概念,即只会 import 目标文件中定义的 template,而不会 import 目标文件 import 的 template。

如:C import B,B import A,在C中可以使用B定义的template,在B中可以使用A定义的template,但是C不能使用A定义的template

(3) 调用模板

使用 is 属性,声明需要的使用的模板,也就是与上面的 name 一致就可以了,然后将模板所需要的 data 传入,如(直接传入):

<template is="test1" data="{{id:'0', name:'张三'}}"</template>

赋值方式还有一种常用的

它的意思就是将调用这个模板页面中的 student 对象变量赋值给这个模板,三个点就是一个扩展运算符,作用就是将这个student 对象展开

<template is="test1" data="{{...student}}"></template>

例如

Page({
  data: {
    student: {
      id: 0,
      name: '张三',
    }
  }
})

—————分割线—————

【事件绑定】

一 通过实例来认识

(一) 给出代码

我们直接通过一个实例来引入我们想要讲解的内容:

<input type="text" bindinput="handleInput" />
<button bindtap="handletap" data-operation="{{1}}">+</button>
<button bindtap="handletap" data-operation="{{-1}}">-</button>

<view>你输入的是:{{number}}</view>

上述代码就四行,首先是一个 input 输入框,目的是用来输入一些值,同时下面标签就会显示,接着是两个 button 用来分别执行 +1 或者 -1 的操作,最后一个 view 标签就是为了 进行数据输入或变化的回显

Page({
  data: {
    number:0
  },
  handleInput(e){
    this.setData({
      number:e.detail.value
    })
  },
  handletap(e){
    const operation = e.currentTarget.dataset.operation
    this.setData({
      number:this.data.number + operation
      // number:this.data.number * 1 + e.currentTarget.dataset.operation
    })
  }
})

这里给出的就是对应的 js 代码,涉及到了对于输入以及 +1 或者 -1 操作的一个具体逻辑处理,核心就是围绕 data 中定义的 number 变量进行处理(具体逻辑接着会提到),结合前面的 wxml 代码分析一下:

(二) 分析代码

分析标签中属性中的部分:

bindinput="handleInput"

bindtap="handletap" data-operation="{{-1}}"

  • 绑定事件的关键字是 bind 例如上面用到的 bindinputbindtap 就是分别对于输入和点击事件的一个绑定
  • 而后面的一个名称例如 handleInput 就是自定义的事件名称,我们在 js 中书写方法也是与这个后面的名称相对应
  • 注:绑定关键字为 bind 仅针对此例,并非只是 bind

补充几个 input 中相对常用的事件绑定属性

属性类型必填说明最低版本
bindinputeventhandle键盘输入时触发,event.detail = {value, cursor, keyCode},keyCode 为键值,2.1.0 起支持,处理函数可以直接 return 一个字符串,将替换输入框的内容。1.0.0
bindfocuseventhandle输入框聚焦时触发,event.detail = { value, height },height 为键盘高度,在基础库 1.9.90 起支持1.0.0
bindblureventhandle输入框失去焦点时触发,event.detail = {value: value}

如果想要获取到输入框的值,通过时间源对象来获取 e.detail.value

(1) JS 中赋值问题

输入框中输入的值赋值给 data 中的 number,如果按惯性思维直接赋值是有问题的

  • 不能使用 this.data.numer = e.detail.value
  • 不能使用 this.number = e.detail.value
  • 需要使用:
this.setData({
    number:e.detail.value
})

(2) JS 中按钮传参问题

添加按钮点击事件:关键字是 bindtap

我们按钮想要达到的目的是,点击按钮进行 number 的 +1 或者 -1 ,通过根据我们上面的 js 代码可以看出,这里所采用实现的方式是根据页面属性中传来的参数,进行相加,例如 number + 1 或者 number + (-1) 达到加减效果

但是,直接传参是有问题的!!!只能通过属性赋值

正解:bindtap="handletap" data-operation="{{-1}}"

(3) 忘记想要的值对应在哪里

说明:如果记不住例如:e.detail.value、e.currentTarget.dataset.operation 则可以使用如下的方式,先把事件打印出来

handleInput(e){
    console.log(e);
},

在找到对应的层级

二 事件绑定类别

(一) 分类

我们上面的例子使用了 bind 这个事件绑定关键字,但是它会发生冒泡事件

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

我们还有一些别的选择,我们下面在 (3) (4) 中会一个一个进行分析

  • bind:普通绑定(会发生冒泡事件)
  • catch:可以阻止事件冒泡
  • capture-bind: 捕获阶段绑定(后面的捕获流程和冒泡流程还会继续执行)
  • capture-catch:中断捕获阶段和取消冒泡阶段,在捕获阶段阻止事件的传递

(二) 冒泡事件列表

在分析前,我们还要补充一个点,那就是 WXML 的冒泡事件列表:

我们起码现在知道了 bind 和 catch 的作用,但是正例如我们上面用到的 bindinput 或者 bindtap ,bind 后面的内容又是什么呢?是固定的还是自定义的呢?这一段我直接贴一段官网的文档说明

类型触发条件最低版本
touchstart手指触摸动作开始
touchmove手指触摸后移动
touchcancel手指触摸动作被打断,如来电提醒,弹窗
touchend手指触摸动作结束
tap手指触摸后马上离开
longpress手指触摸后,超过350ms再离开,如果指定了事件回调函数并触发了这个事件,tap事件将不被触发1.5.0
longtap手指触摸后,超过350ms再离开(推荐使用longpress事件代替)
transitionend会在 WXSS transition 或 wx.createAnimation 动画结束后触发
animationstart会在一个 WXSS animation 动画开始时触发
animationiteration会在一个 WXSS animation 一次迭代结束时触发
animationend会在一个 WXSS animation 动画完成时触发
touchforcechange在支持 3D Touch 的 iPhone 设备,重按时会触发1.9.90
注:除上表之外的其他组件自定义事件如无特殊声明都是非冒泡事件,如 form 的submit事件,input 的input事件,scroll-view 的scroll事件,(详见各个组件)

看完上面的表格,应该就比较清楚了,正因为我们很多事件都是通过手机点一下某个组件等进行,所以 tap 是比较常用的

(三) bind 和 catch

说明:代码在下面自取

(1) bind

前面我们提到了,使用 bind 会发生冒泡事件,我们来模拟一下

首先我们写了三个嵌套的 view 标签,然后接着使用 bindtap 进行事件绑定,进行一个基本的打印逻辑,看看会有什么情况发生

当点击中间层后,首先执行了中间层的事件效果,但是最外层的事件效果也被执行了,这也就是冒泡事件发生了

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

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

(3) catch

这一次我们仍然点击中间这一层,如果在上面的基础上,我们将中间层的事件绑定使用 catch,而不是 bind ,结果会是怎样呢?

结果就是冒泡事件被阻止了,点击后只显示中间层的事件

(四) capture-bind 和 capture-catch

前面提及到这两个内容的时候,我们提到了一个概念也就是事件的捕获阶段,简单说一下:

自基础库版本 1.5.0 起,触摸类事件支持捕获阶段。捕获阶段位于冒泡阶段之前,且在捕获阶段中,事件到达节点的顺序与冒泡阶段恰好相反。需要在捕获阶段监听事件时,可以采用capture-bind、capture-catch关键字,后者将中断捕获阶段和取消冒泡阶段。

(1) capture-bind:tap

依旧是刚才的例子,将三层的属性都修改为 capture-bind:tap="handleTap1" 这种形式的

当我们点击最里层的内容时,执行结果如下:

即它与包裹它的两层都执行了,且是从外至内

(2) capture-catch:tap

将三层属性修改为 capture-catch:tap="handleTap1" 这种形式,点击任意一层:

结果都是只执行最外层的

(五) 简单总结

  • bind:点击会触发它和包裹它的所有事件,且从内向外执行(冒泡事件)
  • catch:点击哪个就触发哪个,独立的(阻止冒泡事件)
  • capture-bind: 点击会触发它和包裹它的所有事件,且从外向内执行
  • capture-catch:如何点击都只会触发最外层的事件

(六) 代码提取

代码给出的是 capture-bind:tap 的情况, bindtap 或者 catchtap 以及 capture-catch 只需要将 capture-bind:tap 替换就行了

wxml

<view class="outer" capture-bind:tap="handleTap1">
  这是最外层
  <view class="middle" capture-bind:tap="handleTap2">
    这是中间层
    <view class="inner" capture-bind:tap="handleTap3">
      这是最里层
    </view>
  </view>
</view>

wxss

.outer {
    text-align: center;
    background-color: red;
    height: 300rpx;
}
.middle {
    background-color: orange;
    width: 60%;
    height: 200rpx;
}
.inner {
    background-color: yellow;
    width: 60%;
    height: 100rpx;
}

—————分割线—————

【WXSS 浅谈】

(一) 尺寸问题

WXSS (WeiXin Style Sheets)是一套样式语言,用于描述 WXML 的组件样式。

其实和原来的 CSS 没差特别多,不过先说一个挺重要的点,就是微信小程序官方提供的一种,解决尺寸问题的方案 rpx

例如设计师给你的设计稿是px为单位的,但是如果你直接使用这样固定的写法,就会导致在不同的机型上,出现内容尺寸比例不一的现象,当然我们也可以使用百分比来解决这个问题,而今天我们简单说一说 rpx

(1) 存在的问题

首先我们,随便写一个 200px * 200px 的方框

view{
    width: 200px;
    height: 200px;
    background-color: deeppink;
}

在不同的机型下,实际上大小可以说写死了,在其他机型下,很清晰就可以看到,右边的留白,发生了很大的变化

(下图为 750 * 550 自定义的)

(2) 尺寸单位

  • 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 作为视觉稿的标准。

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

知道了这些,接着看上面的问题,首先,1px=rpx*(750/设备屏幕宽度),因为原型图我们以iphone6为标准,所以公式就是1px=rpx*(750/375),所以1px=2rpx,这也对应了上面的表格,所以我们只需要将原来固定的 200px 修改一下,成为 400rpx,这样就会发现方框就会根据不同屏幕的尺寸来变化了

(3) 总结

使⽤步骤:

  1. 确定设计稿宽度 pageWidth
  2. 计算⽐例 750rpx = pageWidth px ,因此 1px=750rpx/pageWidth
  3. 在less⽂件中,只要把设计稿中的 px => 750/pageWidth rpx 即可

(二) 引入样式

刚才,我们简单说了一下比例尺寸的问题,在同一个页面下的 样式文件,是不需要引入的,也就是说 例如 test 文件夹下的 test.wxml 中就可以自动匹配上 test.wxss 中的样式

但是,如果想自定义一些样式供多个页面使用,怎么做呢,例如我们在根目录下创建一个文件夹,在其中创建一个名为 commom.wxss 的样式文件,为了效果显著一些,把字体改一下样式

view{
    color: red;
    font-size: 30px;
}

我们在需要页面的 WXSS 中引入一下

注:路径只能写相对路径哈

@import"../../styles/common.wxss";

效果一下就显出来了

(三) 选择器

(1) 支持的选择器:

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

注意:通配符 * 是不支持的,即下列代码是无效的

*{
    margin:0;
    padding:0;
    box-sizing:border-box; 
}

(2) 全局样式与局部样式

定义在 app.wxss 中的样式为全局样式,作用于每一个页面。在 page 的 wxss 文件中定义的样式为局部样式,只作用在对应的页面,并会覆盖 app.wxss 中相同的选择器。

(四) 原生小程序使用 less 的方法

原生的小程序是不支持使用 less 的,当然了,你可以选择直接写样式,如果想要使用 less 的话,可以在 vscode 中安装例如 Easy LESS 插件(此插件需要在 vscode 配置中加入)

"less.compile": {
    "outExt": ".wxss"
},

在编写样式的地方,直接新建 less 文件,例如 test.less 编辑保存后,会生成对应的WXSS文件

—————分割线—————

【常用组件及自定义组件】

(一) 常用标签

组件你可以理解为传统页面开发时候的各种标签,例如 div span 等等,我这里只说一些常用的,这样就能能搭建出一个基本的页面了,但是如果想要更加美观以及拥有更好的体验,就需要 XSS 和 别的一些强大的组件了,如果有额外的需求,可以去官方文档查阅一下 (同时不常用的属性,也就不提了)

https://developers.weixin.qq.com/miniprogram/dev/component/

(1) view

view 可以理解为传统页面开发中的 div 块级元素,使用 view 会换行

关于 view 标签,还有一些额外的属性,说的也很清楚,但是前期的话,其实不考虑这个也是可以的,就单纯的当做一个布局的 div 来用

属性类型默认值必填说明最低版本
hover-classstringnone指定按下去的样式类。当 hover-class="none" 时,没有点击态效果1.0.0
hover-stop-propagationbooleanfalse指定是否阻止本节点的祖先节点出现点击态1.5.0
hover-start-timenumber50按住后多久出现点击态,单位毫秒1.0.0
hover-stay-timenumber400手指松开后点击态保留时间,单位毫秒1.0.0

(2) text

text 可以理解为传统页面中的 span 行内元素,text 不会换行

text 涉及的一些标签

属性类型默认值必填说明最低版本
selectablebooleanfalse文本是否可选1.1.0
spacestring 显示连续空格1.4.0
decodebooleanfalse是否解码1.4.0

space 的合法值

说明
ensp中文字符空格一半大小
emsp中文字符空格大小
nbsp根据字体设置的空格大小

decode可以解析的有

&nbsp; &lt; &gt; &amp; &apos; &ensp; &emsp;

简单测试一下其中两个,可以看到,后者长按可以选择文字,同时编码被解析成空格,前者反之

<text selectable="{{false}}" decode="{{false}}">测&nbsp;试</text>
<text selectable="{{true}}" decode="{{true}}">测&nbsp;试</text>

(3) image

image 就是图片相关的一个组件,这个组件默认宽度320px、⾼度240px,同时支持懒加载

我摘了三个比较常用的属性出来

属性类型默认值必填说明最低版本
srcstring 图片资源地址1.0.0
modestringscaleToFill图片裁剪、缩放的模式1.0.0
lazy-loadbooleanfalse图片懒加载,在即将进入一定范围(上下三屏)时才开始加载1.5.0

他作为图片的一个承载物,我们重点多说一下关于 mode 的问题,也就是图片的显示形式

所以先来看一下,mode 的取值范围(节选了相对常用的,其余的取值都属于裁剪类型)

说明最低版本
scaleToFill缩放模式,不保持纵横比缩放图片,使图片的宽高完全拉伸至填满 image 元素
aspectFit缩放模式,保持纵横比缩放图片,使图片的长边能完全显示出来。也就是说,可以完整地将图片显示出来。
aspectFill缩放模式,保持纵横比缩放图片,只保证图片的短边能完全显示出来。也就是说,图片通常只在水平或垂直方向是完整的,另一个方向将会发生截取。
widthFix缩放模式,宽度不变,高度自动变化,保持原图宽高比不变
heightFix缩放模式,高度不变,宽度自动变化,保持原图宽高比不变2.10.3

比较常用是 widthFix,在这几个其中,aspectFill 相对还是用的比较少的

(4) swiper

这个组件,是小程序页面中的一个轮播图的效果

swiper 是轮播图的一个总的容器,swiper-item 代表其中的每一个内容,配合其属性,能很方便的达到需要的样式

同样摘了几个常见的属性

属性类型默认值必填说明最低版本
indicator-dotsbooleanfalse是否显示面板指示点1.0.0
indicator-colorcolorrgba(0, 0, 0, .3)指示点颜色1.1.0
indicator-active-colorcolor#000000当前选中的指示点颜色1.1.0
autoplaybooleanfalse是否自动切换1.0.0
intervalnumber5000自动切换时间间隔1.0.0
durationnumber500滑动动画时长1.0.0
circularbooleanfalse是否采用衔接滑动1.0.0
verticalbooleanfalse滑动方向是否为纵向1.0.0

显示比例问题

首先说明一下,swiper存在一些默认的样式

  • width: 100%
  • height 150px

image 默认宽高

  • width: 320px
  • height: 240px

如果,swiper 的高度出现了问题,给出一个解决方式

先根据素材图片的宽高比例,等比计算 swiper 的宽高,这样高度就换算出来了

swiper 高度 = swiper 宽度 * 素材高度 / 素材宽度

即:height: 750rpx * 素材高度 / 素材宽度

来看个综合一些的例子

WXML

图片随便自己做了两张

<swiper autoplay="{{true}}" interval="5000" circular="{{true}}" indicator-dots="{{true}}"
    indicator-color="#D3D3D3" indicator-active-color="#FFFF00">
    <swiper-item><image mode="widthFix" src="../../image/swiperC.jpg"></image></swiper-item>
    <swiper-item><image mode="widthFix" src="../../image/swiperB.jpg"></image></swiper-item>
    <swiper-item><image mode="widthFix" src="../../image/swiperA.jpg"></image></swiper-item>
</swiper>

WXSS

swiper{
    width: 100%;
    height: calc(750rpx * 275 / 1000);
}

image{
    width: 100%;
}

看一下效果,现在就实现了轮播图的效果,同时会5秒自动循环轮播,自己可以对照属文档进行定制修改

(5) navigator

导航组件,这块可以理解为传统页面开发的超链接标签

属性类型默认值必填说明最低版本
targetstringself在哪个目标上发生跳转,默认当前小程序2.0.7
urlstring 当前小程序内的跳转链接1.0.0
open-typestringnavigate跳转方式1.0.0

open-type 的合法值

说明最低版本
navigate保留当前页面,跳转到应用内的某个页面,但是不能跳到tabbar 页面
redirect关闭当前页面,跳转到应用内的某个页面,但是不允许跳转到tabbar 页面
switchTab跳转到 tabBar 页面,并关闭其他所有非 tabBar 页面
reLaunch关闭所有页面,打开到应用内的某个页面1.1.0
navigateBack关闭当前页面,返回上⼀页面或多级页面。可通过 getCurrentPages() 获取当1.1.0
exit退出小程序,target=miniProgram时⽣效2.1.0

下面给出一个测试的代码,默认不添加 open-type 的写法会有一个返回上一层的

<navigator url="/pages/test06/test06">默认跳转到test06</navigator>

<navigator open-type="redirect" url="/pages/test06/test06">redirect跳转到test06</navigator>

<navigator open-type="switchTab" url="/pages/index/index">switchTab跳转到主页</navigator>

<navigator open-type="reLaunch" url="/pages/index/index">reLaunch跳转到主页</navigator>

(6) rich-text

这是一个富文本标签,作用就是把字符串中的对应标签解析出来,其主要的一个属性就是 nodes ,我们先简单看一下 nodes的属性有哪些

现支持两种节点,通过type来区分,分别是元素节点和文本节点,默认是元素节点,在富文本区域里显示的HTML节点 元素节点:type = node

属性说明类型必填备注
name标签名string支持部分受信任的 HTML 节点
attrs属性object支持部分受信任的属性,遵循 Pascal 命名法
children子节点列表array结构和 nodes 一致

来看一个例子,这个nodes 的值,我们去 js 中定义一个

<rich-text nodes="{{receive}}"></rich-text>

有两种方式赋值,一种就是我注释掉的那一行,直接使用一个含有标签的字符串,直接赋值就会解析,另一种就是通过后面这样 JSON 的一种格式赋值,效果是一样的

Page({
  data: {
    // receive:'<div class="div_class"><h3>理想二旬不止</h3></div>'
    receive:[{
      name:'div',
      attrs:{
        class:'div_class'
      },
      children:[{
        name:'h3',
        attrs:{},
        children:[{
          type:'text',
          text:'理想二旬不止'
        }]
      }]
    }] 
  },
})

(7) button

按钮标签,也算是非常常用的内容了,同时相比较传统页面开发中的按钮,微信小程序中又有很多开放式的功能,首先看一些涉及的一些属性(更多内容可以看官网文档):

https://developers.weixin.qq.com/miniprogram/dev/component/button.html

属性类型默认值必填说明最低版本
sizestringdefault按钮的大小1.0.0
typestringdefault按钮的样式类型1.0.0
plainbooleanfalse按钮是否镂空,背景色透明1.0.0
disabledbooleanfalse是否禁用1.0.0
loadingbooleanfalse名称前是否带 loading 图标1.0.0
form-typestring 用于 form 组件,点击分别会触发 form 组件的 submit/reset 事件1.0.0
open-typestring 微信开放能力1.10

size 的合法值

说明
default默认大小
mini小尺寸

type 的合法值

说明
primary绿色
default白色
warn红色

form-type 的合法值

说明最低版本
submit提交表单
reset重置表单

open-type 的合法值

说明最低版本
contact打开客服会话,如果用户在会话中点击消息卡片后返回小程序,可以从 bindcontact 回调中获得具体信息1.1.0
share触发用户转发,使用前建议先阅读1.2.0
getPhoneNumber获取用户手机号,可以从bindgetphonenumber回调中获取到用户信息1.2.0
getUserInfo获取用户信息,可以从bindgetuserinfo回调中获取到用户信息1.3.0
launchApp打开APP,可以通过app-parameter属性设定向APP传的参数1.9.5
openSetting打开授权设置页2.0.7
feedback打开“意见反馈”页面,用户可提交反馈内容并上传日志,开发者可以登录小程序管理后台后进入左侧菜单“客服反馈”页面获取到反馈内容2.1.0

这几个代码就是通过 sizetype 进行基本的大小或者说类型实现一个样式

<button style="width:100%">默认按钮</button>
<button style="width:100%" size="mini">mini 默认按钮</button>
<button style="width:100%" type="primary">primary 按钮</button>
<button style="width:100%" type="warn">warn 按钮</button>
<button style="width:100%" type="warn" plain>plain 按钮</button>

下面就是一些开放的功能

<button style="width:100%" open-type="contact">联系客服</button>
<button style="width:100%" open-type="share">分享小程序</button>
<button style="width:100%" open-type="getPhoneNumber" bindgetphonenumber="getPhoneNumber">
    获取电话号码
</button>
<button style="width:100%" open-type="getUserInfo" bindgetuserinfo="getUserInfo">
    获取用户信息
</button>
<button style="width:100%" open-type="launchApp">打开App</button>
<button style="width:100%" open-type="openSetting">打开授权设置页</button>
<button style="width:100%" open-type="feedback">意见反馈</button>

需要说明的几个点:

  • 联系客服这个功能只能在真机调试,需要先在后台绑定一个客服的微信号码,接着在开发工具中选择真机调试,然后扫描二维码就可以了

  • 获取电话号码,以及用户信息,需要结合事件来做,例如:
Page({
  // 获取用户的手机号码信息
  getPhoneNumber(e){
    console.log(e);
  },
  // 获取用户个人信息
  getUserInfo(e){
    console.log(e);
  }
})

例如获取用户信息

但是电话号码,不是企业的小程序账号 没有权限来获取用户的手机号码

  • 打开App,是在 app 中 通过 app 的某个链接打开小程序,然后在小程序 再通过这个功 重新打开 app
  • 当前版本的微信小程序,在.wxss文件里设置Button宽度无效,网络上的一种解决方案就是把 app.json里的 style: v2语句删掉,还有一种就是像我代码中一样,直接加 style,暂时推荐后者吧,此处未深究

(8) icon

微信小程序默认封装了一些图标,也很简单,只有三个属性

属性类型默认值必填说明最低版本
typestring icon的类型,有效值:success, success_no_circle, info, warn, waiting, cancel, download, search, clear1.0.0
sizenumber/string23icon的大小1.0.0
colorstring icon的颜色,同css的color1.0.0

简单用一下

<icon  type="success" size="50"> </icon>
<icon  type="success" size="50" color="#3390ff"> </icon>

如果不指定颜色,其默认都是有一定颜色样式的,如果指定了 color 就会覆盖掉原来的颜色

(9) radio

单选框组件,需要配合 radio-group 使用,下面看代码就明白了

属性类型默认值必填说明最低版本
valuestring radio标识。当该radio选中时,radio-group 的 change 事件会携带 radio 的 value1.0.0
checkedbooleanfalse当前是否选中1.0.0
disabledbooleanfalse是否禁用1.0.0
colorstring#09BB07radio的颜色,同css的color1.0.0

简单用一下,

<radio-group bindchange="handleChange">
  <radio color="blue" value="male">男</radio>
  <radio color="blue" value="female" >女</radio>
</radio-group>

<view>你选择的性别是:{{gender}}</view>

js 内容,至于 e.detail.value 如何来的,可以通过 console.log(e) 打印看到

Page({
  data: {
    gender: ""
  },
  handleChange(e){
    // 获取单选框中的值
    let gender=e.detail.value;
    // 把值 赋值给 data中的数据
    this.setData({
      gender
    })
  }
})

(10) checkbox

属性类型默认值必填说明最低版本
valuestring checkbox 标识,选中时触发 checkbox-group 的 change 事件,并携带 checkbox 的 value1.0.0
disabledbooleanfalse是否禁用1.0.0
checkedbooleanfalse当前是否选中,可用来设置默认选中1.0.0
colorstring#09BB07checkbox的颜色,同css的color1.0.0

直接用一下

<view>
  <checkbox-group bindchange="handleItemChange">
    <checkbox value="{{item.value}}" wx:for="{{list}}" wx:key="id">
      {{item.name}}
    </checkbox>
  </checkbox-group>
  <view>
    选中的内容:{{checkedList}}
  </view>
</view>
Page({
  data: {
    list:[
      {
        id:0,
        name:"🌞️",
        value:"太阳"
      },
      {
        id:1,
        name:"🌙",
        value:"月亮"
      },
      {
        id:2,
        name:"⭐️",
        value:"星星"
      }
    ],
    checkedList:[]
  },
  // 复选框的选中事件
  handleItemChange(e){
    // 获取被选中的复选框的值
    const checkedList=e.detail.value;
    // 进行赋值
    this.setData({
      checkedList
    })
  }
})

运行结果:

(二) 自定义组件(标签)

(1) 快速体验

如果我们想要自定义一些组件,也就是说将一些代码抽离出来,可以达到复用等的效果

我们一步一步举个例子:

首先创建文件夹目录 components/header

接着右键创建组件 header,点击新建 Component

结构就是这样的

一般点击创建组件的方式会自动将组件的 json 文件中声明组件,如果没有需要自己手动修改component 为 true

{
  "component": true,
}

接着在组件WXML中随便写点东西,然后打开想要引用组件的页面,首先在 json 中说明引用组件

{
  "usingComponents": {
    "header":"/../../components/header/header"
  }
}

然后直接引用就可以了,效果就出来了

<header></header>

(2) 组件传参

组件传参有两个方向,一个是父组件 --> 子组件 ,还有就是反过来。注:父组件是页面,子组件是自定义组件

  • ⽗组件通过属性的⽅式给⼦组件传递参数
  • 组件通过事件的⽅式向⽗组件传递参数

通过一个例子来演示

在上面结构上自己写一个自定义的组件,一个导航条的效果

自定义组件的页面代码

<!-- components/header/header.wxml -->
<view class="header">
    <view class="header_tabs_title">
        <view wx:for="{{headerTabs}}" 
        wx:key="id" 
        class="header_tabs_title_item {{item.isActive?'active':''}}"
        bindtap="hanldeItemTap"
        data-index="{{index}}"
        >
            {{item.name}}
        </view>
    </view>
</view>

自定义组件的样式文件如下

/* components/header/header.wxss */
.header_tabs_title{
    display: flex;
    padding: 10px;
}
.header_tabs_title_item{
    flex: 1;
    display: flex;
    justify-content: center;
    align-items: center;
}

.active{
    color:blue;
    border-bottom: 5rpx solid currentColor;
}

自定义组件的 js文件,在 properties 中的内容,就是接收到父(页面)的数据,也就是一个关于导航的数组,其中包括首页测试关于等等导航文字内容

  • headerTabs的位置:要接受的名称,自己定
  • type:要接收的数据的类型
  • value:默认值

而下面的方法就是关于父传数据到子组件的内容,其代表触发父组件中的自定义事件,同时传递数据给 父组件

// components/header/header.js
Component({
  /**
   * 组件的属性列表
   */
  properties: {
    headerTabs:{
      type:Array,
      value:[]
    }
  },

  /**
   * 组件的初始数据
   */
  data: {

  },

  /**
   * 组件的方法列表
   */
  methods: {
    hanldeItemTap(e){
      const {index}=e.currentTarget.dataset;
      // 触发父组件中的自定义事件 同时传递数据给  
      this.triggerEvent("itemChange",{index});
    }
  }
})

补充:e.currentTarget.dataset; 是怎么来的,还是老办法,console 打印一下

父页面

绑定一个事件,同时把等会再 js 中的定义数据,传递到自定义组件中去,名称就是刚才接收的 headerTabs

<header headerTabs="{{headerTabs}}" binditemChange="handleItemChange" ></header>

父页面的 js

说明:let { headerTabs } = this.data; 这是 ES6 的写法,也可以写成

let headerTabs = this.data.headerTabs;

遍历数组的时候 修改了 v ,就把源数组也修改了

目的就是通过点击修改定义导航中的 isActive 为 true 或 false

// pages/test08/test08.js
Page({

  /**
   * 页面的初始数据
   */
  data: {
    headerTabs:[
      {
        id:0,
        name:"首页",
        isActive:true
      },
      {
        id:1,
        name:"测试",
        isActive:false
      },
      {
        id:2,
        name:"测试",
        isActive:false
      },
      {
        id:3,
        name:"关于",
        isActive:false
      },
    ]
  },
  // 自定义事件 用来接收子组件传递的数据的
  handleItemChange(e) {
    // 接收传递过来的参数
    const { index } = e.detail;
    let { headerTabs } = this.data;
    headerTabs.forEach((v, i) => i === index ? v.isActive = true : v.isActive = false);
    this.setData({
      headerTabs
    })
  }
})

结尾

如果文章中有什么不足,欢迎大家留言交流,感谢朋友们的支持!

如果能帮到你的话,那就来关注我吧!如果您更喜欢微信文章的阅读方式,可以关注我的公众号

在这里的我们素不相识,却都在为了自己的梦而努力 ❤

一个坚持推送原创开发技术文章的公众号:理想二旬不止


二境志
191 声望26 粉丝