微信小程序开发
覆盖电商,教育,医疗,游戏等领域,还是非常重要的。
这里主要有小程序基础和项目两个版块。
小程序基础
什么是微信小程序
微信小程序是一种运行在微信内部的轻量级应用程序。
在使用小程序时不需要下载安装,用户扫一扫或 搜一下 即可打开应用。它也体现了“用完即走”的理念,用户不用关心安装太多应用的问题。它实现了应用“触手可及”的梦想,应用无处不在,随时可用,但又无须安装卸载。
小程序的四大特性:无须安装、用完即走、无须卸载、触手可及
注册账号
小程序开发与网页开发不一样,在开始微信小程序开发之前,需要访问微信公众平台,注册一个微信小程序账号。有了小程序的账号以后,我们才可以开发和管理小程序,后续需要通过该账号进行开发信息的设置、开发成员的添加,也可以用该账号查看小程序的运营数据。
账号信息完善
在完成小程序账号的注册后,需要打开微信公众平台对小程序账号进行一些设置,这是因为小程序在 上线阶段-提交审核 的时候小程序账号信息是必填项,因此在注册小程序以后,需要补充小程序的基本信息,如名称、图标、类目等。同时需要进行小程序备案和微信认证
然后根据提示填写接口,主要要遵守平台规则。在微信小程序类目是先不要选择游戏。因为我们学的是小程序开发,选择游戏的话会被识别成小游戏开发.
这里只完成小程序信息和类目即可,后续上面上线前把后两项完成即可。
注意:如果要修改信息和类目的话,可以在左侧菜单栏最下方中修改。
项目成员&体验成员
为了企业对人员的管理,微信小程序提供两个成员角色。
小程序提供了两种不同的成员角色:项目成员和体验成员
项目成员:表示参与小程序开发、运营的成员,包括运营者、开发者及数据分析者,项目成员可登陆微信公众后台,管理员可以在成员管理中添加、删除项目成员,并设置项目成员的角色。
体验成员:表示参与小程序内测体验的成员,可使用体验版小程序,但不属于项目成员。管理员及项目成员均可添加、删除体验成员。
可以在微信公众平台设置,个人账号这里都是十五个,到企业中会达到就是个
点击添加,搜索微信号即可
小程序开发中ID
微信小程序账号只要开发者满足开发资质都可以进行注册,并且会获得对应的开发者ID
一个完整的开发者 ID 由 小程序 ID(AppID)和一个 小程序密钥(AppSecret)组成
小程序 ID 是小程序在整个微信账号体系内的唯一身份凭证,后续在很多地方都会用到例如:新建小程序项目、真机调试、发布小程序等操作时,必须有小程序ID。
小程序密钥 是开发者对小程序拥有所有权的凭证,在进行 微信登录、微信支付,或进行发送消息等高级开发时会使用到
小程序ID很常用,建议复制到本机文件中,方面使用。
微信开发者工具下载
为了帮助开发者简单和高效地开发和调试微信小程序,微信官方提供了 微信开发者工具,利用开发者工具可以很方便地进行小程序开发、代码查看以及编辑、预览和发布等。
微信开发者工具包含三个版本:
- 稳定版:稳定性高,开发中一般推荐大家使用稳定版本。
- 预发布版:稳定性尚可,一般包含新的、大的特性,通过了内部测试
- 开发版:稳定性差,主要用于尽快修复缺陷和敏捷上线小的特性
注意事项:微信开发者工具必须联网使用!
这里下载稳定版最为稳妥,然后根据电脑情况选择即可
创建项目
- 打开微信开发者工具,左侧选择小程序,点击+号即可新建项目
- 弹出的新页面,填写项目信息
注意:这不是用云开发,不适用模板
然后点击确定即可。
打开后可以按习惯进行页面布局的微调,如在”视图->外观->将模拟器移至右侧“、”设置->编辑器设置->设置行高字号“
文件和目录结构介绍
一个完整的小程序项目分为两个部分:主体文件、页面文件
主体文件
主体文件 又称 全局文件,能够作用于整个小程序,影响到小程序的每个页面,主体文件必须放到项目的根目录下
主体文件由三部分组成:
- appjs:小程序入口文件
- app.json:小程序的全局配置文件
- app.wxss:小程序的全局样式
注意事项:主体文件的名字必须是 app,app.js 和 app.json 文件是必须的
页面文件
页面文件 是每个页面所需的文件,小程序页面文件都存放在 pages 目录下,一个页面一个文件夹
每个页面通常由四个文件组成,每个文件只对当前页面有效
- .js:页面逻辑
- .wxml:页面结构
- .wxss:页面样式
- .json:小页面配置
注意事项:.js 文件和 .wxml 文件是必须的!
渲染模式的选择
现在支持两种模式,Skyline是新型的,但是WebView能够支持低版本的客户端,所以这里可以改为WebView渲染模式。在app.json文件中删除renderer、rendererOptions和componentFramework属性并保存即可。
新建页面和调试基础库
新建页面
新建页面方法一:
- 右键pages。
- 新建文件夹,然后输入页面名,以login为例。
- 右键login。
- 新建page,然后输入页面名,注意:不要加后缀名,回车自动创建四个文件。
新建页面方法二:
- 在app.json中找到pages。
- 照葫芦画瓢,添加对应路径保存即可。注意:逗号别少了。
调试基础库
小程序调试基础库是指 微信开发者工具中可以选择的微信基础库版本。
微信基础库是指小程序的运行环境,给小程序提供了运行所需的各种 API和工具,以及基础框架和运行逻辑等。【如果在开发过程中有的API或工具用不了,就要检查基础库版本是不是太老了,不符合开发项目的要求】
小程序开发者可以在微信开发者工具中选择所需的微信基础库版本,作为运行和调试小程序时的运行环境.
每个小程序有自己所允许使用的基础库最低版本要求,开发者需要选择要兼容的基础库版本,从而确保小程序的功能正常运行。
调试小程序
在进行项目开发的时候,不可避免的需要进行调试,那么如何调试小程序呢
注意事项
微信开发者工具缓存非常严重。
如果发现代码和预期不一样,先点击编译!
编译后还是没有达到预期的效果,就需要清除缓存!甚至重启项目才可以!
配置文件
配置文件介绍
JSON 是一种轻量级的数据格式,常用于前后端数据的交互,但是在小程序中,JSON 扮演的配置项的角色,用于配置项目或者页面属性和行为,每个页面或组件也都有一个对应的json 文件。
小程序中常见的配置文件有以下几种:
- app.json:小程序全局配置文件,用于配置小程序的一些全局属性和页面路由。
- 页面.json:小程序页面配置文件,也称局部配置文件,用于配置当前页面的窗口样式、页面标题等
- project[.private].config.json:小程序项目的配置文件,用于保存项目的一些配置信息和开发者的个人设置
- sitemap.json:配置小程序及其页面是否允许被微信索引,提高小程序在搜索引擎搜索到的概率
具体配置属性的规则可以在微信官方文档查看
全局配置-pages配置
pages 字段:用来指定小程序由哪些页面组成,用于让小程序知道由哪些页面组成以及页面定义在哪个目录,每一项都对应一个页面的路径信息。
在配置 pages 字段时,有以下 注意事项:
-
页面路由不需要写文件后缀,框架会自动去寻找对应位置的四个文件进行处理
-
小程序中新增/减少页面,都需要对 pages 数组进行修改
-
未指定 entryPagePath 时,数组的第一项代表小程序的初始页面(首页)
全局配置-window配置
window 字段:用于设置小程序的状态栏、导航条、标题、窗口背景色
注意:窗口是下滑刷新时出来的区域,在字段值开启才会有效果。
具体代码示例如下:
"window": {
"navigationBarTitleText": "一起来学习",
"navigationBarBackgroundColor": "#3faaf8",
"enablePullDownRefresh": true,
"backgroundColor": "#2beeff",
"backgroundTextStyle": "light"
},
全局配置-tabBar配置
tabBar 字段:定义小程序顶部、底部 tab 栏,用以实现页面之间的快速切换
可以通过 tabBar 配置项指定 tab 栏的表现,以及 tab 切换时显示的对应页面
注意事项:
- tab 按数组的顺序排序,list 配置最少2个、最多5个tab。
- tabBar属性是和window同级的
这些属性可以具体查看开发文档。
样例代码:
"tabBar": {
"selectedColor": "#3faaf8",
"color": "#521262",
"list": [
{
"text": "首页",
"pagePath": "pages/index/index",
"iconPath": "/assets/tabbar/index.png",
"selectedIconPath": "/assets/tabbar/index-active.png"
},
{
"text": "课程",
"pagePath": "pages/class/class",
"iconPath": "/assets/tabbar/class.png",
"selectedIconPath": "/assets/tabbar/class-active.png"
},
{
"text": "练习",
"pagePath": "pages/test/test",
"iconPath": "/assets/tabbar/test.png",
"selectedIconPath": "/assets/tabbar/test-active.png"
},
{
"text": "我的",
"pagePath": "pages/my/my",
"iconPath": "/assets/tabbar/my.png",
"selectedIconPath": "/assets/tabbar/my-active.png"
}
]
},
页面配置
小程序的页面配置,也称局部配置,每一个小程序页面也可以使用自己的 .json 文件来对本页面的窗口表现进
行配置。
需要注意的是:页面配置文件的属性和 全局配置文件中的 wndow 属性几乎一致,只不过这里不需要额
外指定 window 字段,因此如果出现相同的配置项,页面中配置项会覆盖全局配置文件中相同的配置项。
项目配置文件
相关配置项具体可看设置 / 项目配置文件。
其实在“详情->本机设置中修改的属性”本质修改的就是这两个配置文件
在创建项目的时候,每个项目的根目录生成两个 confg.json 文件,用于保存开发者在工具上做的个性化配
置,例如和编译有关的配置。
当重新安装微信开发者工具或换电脑工作时,只要载入同一个项目的代码包,开发者工具就会自动恢复到当时
开发项目时的个性化配置。
项目根目录中的 project.config.json 和 project.private.config.json 文件都可以对项目进行配置
project.config.json:项目配置文件,常用来进行配置公共的配置
project.private.config.json:项目私有的配置,常用来配置个人的配置
注意事项:
- project.private.config.json 写到 .gitignore 避免版本管理的冲突
- 与最终编译结果有关的设置 必须 设置到 project.config.json 中
配置sass
我们可以把页面的.wxss文件换成css的拓展语言的sass
-
首先在project.config.json配置,因为与最终编译结果有关的设置
"setting": { "useCompilerPlugins": [ "sass" ], ... },
-
将对应页面的.wxss后缀文件改为.scss。然后可以在其中编写属性了,如下
text { color: "#6639a6" }
sitemap.json文件
sitemap.json 文件:配置小程序及其页面是否允许被微信索引,提高小程序在微信内部被用户搜索到的概率
微信现已开放小程序内搜索,开发者可以通过 sitemap.json 配置来设置小程序页面是否允许微信索引。当开
发者允许微信索引时,微信会通过爬虫的形式,为小程序的页面内容建立索引。当用户的搜索词条触发该索引
时,小程序的页面将可能展示在搜索结果中
注意事项:
-
没有 sitemap.json 则默认所有页面都能被索引
-
{"action":"allow","page":"*"}是优先级最低的默认规则,未显式指明"disallow"的都默认被索引
-
其中action属性中allow与disallow的作用就是解释下方page属性的意义。在某个action属性中没有被page属性显示声明的页面,那就属于另一个属性的状态。
如下为只允许index页面
"rules": [{ "action": "allow", "page": "pages/index/index" }]
样式和组件的介绍
在开发 Web 网站的时候:页面的结构由 HTML进行编写,例如:经常会用到 div、p、span、img、a等标签页面
的样式由 CSS 进行编写,例如:经常会采用.class、#d、element 等选择器
但在小程序中不能使用 HTML 标签,也就没有 DOM 和 BOM,CSS 也仅仅支持部分选择器小程序提供了
WXML 进行页面结构编写,同时提供了 WXSS 进行页面的样式编写
WXML 提供了 view、text、image、navigator 等标签来构建页面结构,只不过在小程序中将标签称为 组件
WXSS 对 CSS 扩充和修改,新增了尺寸单位rpx、提供了全局的样式和局部样式,另外需要注意的是 WXSS 仅
支持部分 CSS 选择器
上述区别具体可见开发文档
样式-尺寸单位rpx
随着智能手机的发展,手机设备的宽度也逐渐多元化,这就需要开发者在开发的时候,需要适配不同屏幕宽度
的手机。为了解决屏幕适配的问题,微信小程序推出了rpx 单位
rpx:是小程序新增的自适应单位,它可以根据不同设备的屏幕宽度进行自适应缩放
小程序规定任何型号手机:屏幕宽都为 750rpx
开发建议:
- 开发微信小程序时设计师可以用 iPhone6 作为视觉稿的标准,iPhone6 的设计稿一般是 750px
- 如果用 iPhone6 作为视觉稿的标准 量取多少 px,直接写多少rpx 即可,开发起来更方便,也能够适配屏幕的宽度设计稿宽度是 750px,而iPhone6 的手机设备宽度是 375px,设计稿想完整展示到手机中,就需要缩小一倍在 iPhone6下,px和rpx 的换算关系是:1rpx=0.5px,750rpx=375px,刚好能够填充满整个屏幕的宽度
代码示例
exam.wxml:
<!-- view 是小程序提供的组件,是容器组件,类似于 div,也是一个块级元素,占据一行 -->
<view class="container">
<a>随堂检测</a>
</view>
<view class="container">
<a>课后练习</a>
</view>
<view class="container">
<a>月度练习</a>
</view>
<view class="container">
<a>期末练习</a>
</view>
exam.scss:
.container {
float: left;
width: 375rpx;
height: 300rpx;
padding: 10rpx;
}
.container a {
width: 100%;
height: 100%;
background-color: #d6c8ff;
border-radius: 5px;
text-align: center;
line-height: 300rpx;
font-size: 60rpx;
font-family: 'Courier New', Courier, monospace;
}
样式-全局样式局部样式
在进行网页开发时,我们经常创建 global.css、base.css 或者 reset.css 作为全局样式文件进行重置样式或者样
式统一,然后在每个页面或组件中写当前页面或组件的局部样式,小程序中也存在全局样式和局部样式。
全局样式:指在 app.wxss 中定义的样式规则,作用于每一个页面,例如:设置字号、背景色、宽高等全局样式
局部样式:指在 page.wxss 中定义的样式规则,只作用在对应的页面,并会覆盖 app.wxss 中相同的选择器。
这里文件后缀名可同一改为scss。
view-划分页面结构
小程序常用的组件:
- view 组件
- swiper 和 swiper-item 组件
- image 组件
- text 组件
- navigator 组件
- scroll-view 组件
- 字体图标
注意:当属性值为布尔值true时,可以直接写属性名即可
下面实现一个项目首页效果、
示例代码如下:
index.wxml
<!-- view 小程序提供的容器组件,可以直接点当成div使用即可 -->
<!-- 轮播图区域 -->
<view class="swiper"></view>
<!-- 分类信息 -->
<view class="info"></view>
<!-- 课程导航 -->
<view class="course-nav"></view>
<!-- 推荐课程 -->
<view class="course-hot"></view>
index.scss
在调试器的Wxml可以看出,自己写的页面元素上一级是page标签,可以把其当作网页中body标签来看
page {
height: 100vh;
background-color: #efefef !important;
}
swiper-轮播图区域绘制
在进行网页开发的时候,实现轮播图的时候,我们通常先使用 HTML、CSS 实现轮播图的结构样式,然后使用JS 控制轮播图的效果,或者直接使用插件实现轮播图的功能,而在小程序中实现小程序功能则相对简单很多
在小程序中,提供了 swiper 和 swiper-item 组件实现轮播图
swiper:滑块视图容器,其中只能放置 swiper-item 组件
swiper-item:只可放置在 swiper 组件中,宽高自动设置为100%,代表swiper 中的每一项
具体可见微信开发文档!!!
示例代码如下:
index.wxml
<view class="swiper">
<swiper
autoplay
circular
indicator-dots
interval="2000"
indicator-color="#fff"
indicator-active-color="#3faaf8"
>
<swiper-item>
1
</swiper-item>
<swiper-item>
2
</swiper-item>
<swiper-item>
3
</swiper-item>
</swiper>
</view>
index.scss
.swiper {
swiper {
height: 360rpx;
background-color: skyblue;
swiper-item {
//& 在Sass中代表的是父选择器,引用的意思
//swiper-item: first-child
&:first-child {
background-color: lightsalmon;
}
&:last-child {
background-color: lightseagreen;
}
}
}
}
tips:
- 当输入信息是没有弹出提示时,可以重新打开该文件
- 鼠标悬浮在属性上方时,会弹出前往开发文档的链接
image-轮播图图片添加
在小程序中,如果需要渲染图片,需要使用image 组件,常用的属性有4个:
- src 属性:图片资源地址
- mode:图片裁剪、缩放的模式。如展示图片哪部分,按短边展示还是按场边展示
- show-menu-by-longpress:长按图片显示菜单,菜单中有转发给好友、收藏、保存等功能
- lazy-load:图片懒加载,在滑动到一定的距离(上下三屏)以后展示图片。用到的时候再加载。
注意事项:
- image 默认具有宽度和高度,宽是 320px 高度是 240px
- image 组件不给 src 属性设置图片地址,也占据宽和高
示例代码如下:
index.wxml
<swiper-item>
<image src="../../assets/banner/banner-1.jpg" mode=""/>
</swiper-item>
<swiper-item>
<image src="../../assets/banner/banner-2.jpg" mode=""/>
</swiper-item>
<swiper-item>
<image src="../../assets/banner/banner-3.jpg" mode=""/>
</swiper-item>
index.scss
swiper-item {
image {
width: 100%;
height: 100%;
}
}
text-公司信息区域
在小程序中,如果需要渲染文本,需要使用 text 组件,常用的属性有2个
- user-select:文本是否可选,用于长按选择文本
- space:显示连续空格。可以设置空格的半角全角等属性
注意事项:
- 除了文本节点以外的其他节点都无法长按选中
- text 组件内只支持 text 嵌套
示例代码:
<view class="info">
<text>线上课程</text>
<text>行业新秀</text>
<text>点击可听</text>
<text>100% 好评</text>
</view>
然后可以添加样式,再布局中用display: flex还是比较方便的。
商品导航区域
这部分主要用到了以下组件
- view:视图容器
- image:图片组件
- text:文本组件
index.wxml
<view class="course-nav">
<view>
<image src="../../assets/info/info-1.png" mode=""/>
<text>课程中心</text>
</view>
<view>
<image src="../../assets/info/info-2.png" mode=""/>
<text>练习提升</text>
</view>
<view>
<image src="../../assets/info/info-3.png" mode=""/>
<text>知识回顾</text>
</view>
<view>
<image src="../../assets/info/info-4.png" mode=""/>
<text>满分答卷</text>
</view>
<view>
<image src="../../assets/info/info-1.png" mode=""/>
<text>知识预习</text>
</view>
</view>
index.scss
.course-nav {
display: flex;
justify-content: space-between;
background-color: #fff;
padding: 20rpx 16rpx;
border-radius: 10rpx;
view {
display: flex;
flex-direction: column;
align-items: center;
image {
width: 80rpx;
height: 80rpx;
}
text {
font-size: 24rpx;
margin-top: 12rpx;
}
}
}
navigation-跳转页面
在小程序中,如果需要进行跳转,需要使用 navigation 组件,常用的属性有2个:
-
url:当前小程序内的跳转链接
-
open-type:跳转方式
- navigate:保留当前页面,跳转到应用内的某个页面。但是不能跳到tabbar 页面
- redirect:关闭当前页面,跳转到应用内的某个页面。但不能跳转到tabbar页面
- switchTab:跳转到 tabBar 页面,并关闭其他所有非tabBar 页面
- reLaunch:关闭所有页面,打开到应用内的某个页面
- navigateBack:关闭当前页面,返回上一页面或多级页面。默认delta: 1。想返回几级就写几。
注意事项:
- 路径后可以带参数。参数与路径之间使用?分隔,参数键与参数值用=相连,不同参数用&分隔
例如:/list?id=10&name=hua,在 onLoad(options)生命周期函数 中获取传递的参数 - open-type=“switchTab” 时不支持传参
- 路径前面要加/否则不成功
示例代码:
index.wxml
<view>
<navigator url="/pages/course/course" open-type="switchTab">
<image src="../../assets/info/info-1.png" mode=""/>
<text>课程中心</text>
</navigator>
</view>
<view>
<navigator url="/pages/exam/exam" open-type="switchTab">
<image src="../../assets/info/info-2.png" mode=""/>
<text>练习提升</text>
</navigator>
</view>
小tips:涉及到多行编辑时,可以按住alt键,用鼠标左键选中多个欲编辑位置,同时编辑。
scroll-view推荐商品区域
在微信想小程序中如果想实现内容滚动,需要使用 scroll-view 组件
scroll-view:可滚动视图区域,适用于需要滚动展示内容的场景,用于在小程序中实现类似于网页中的滚动条效果,用户可以通过手指滑动或者点击滚动条来滚动内容
先来学习两个属性:
- scroll-x:允许横向滚动
- scroll-y:允许纵向滚动
横竖滚动分别的示例代码:
index.wxml
<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>
index.scss
.scroll-x {
width: 100%;
white-space: nowrap;
background-color: skyblue;
view {
display: inline-block;
width: 300rpx;
height: 80rpx;
&:first-child {
background-color: lightsalmon;
}
&:last-child {
background-color: lightseagreen;
}
}
}
.scroll-y {
height: 400rpx;
white-space: nowrap;
background-color: skyblue;
view {
height: 400rpx;
&:first-child {
background-color: lightsalmon;
}
&:last-child {
background-color: lightseagreen;
}
}
}
字体图标的使用
在项目中使用到的小图标,一般由公司设计师进行设计,设计好以后上传到阿里巴巴矢量图标库,然后方便程序员来进行使用。
小程序中的字体图标使用方式与 Web 开发中的使用方式是一样的。
注意事项:
使用字体图标可能会报错:[渲染层网络层错误] Failed to load font..……该错误可忽略
但在控制台出现错误,会影响开发调试,解决方案是:在网站上项目设置中将字体图标转换成 base64的格式
图标库使用步骤
-
登录账号
-
在首页搜索框输入自己想要的图标。
-
然后点击对应的购物车添加入库
-
点击导航栏右上角购物车
-
添加至项目,没有项目的创建即可
-
生成代码,将代码复制到项目中
-
在项目根目录中新建iconfont文件夹,并且在中新建iconfont.scss文件,代码复制其中
-
因为图片最后可能在多个页面中使用,所以要在app.scss文件中全局导入。这里要分号结尾
@import "./iconfont/iconfont.scss";
使用代码如下:
本质上就是设置上对应类名就行
index.wxml
<view class="info">
<text><text class="iconfont icon-kecheng"></text>线上课程</text>
<text><text class="iconfont icon-hangyejingzhengli"></text>行业新秀</text>
<text><text class="iconfont icon-tingkepingke"></text>点击可听</text>
<text><text class="iconfont icon-pingfenxiangguanli"></text>100% 好评</text>
</view>
然后可以在index.wcss中调整图标大小
.iconfont {
font-size: 24rpx;
}
背景图的使用
当编写小程序的样式文件时,我们可以使用 background-image 属性来设置元素的背景图像
注意事项:
小程序的 background-image 不支持本地路径!需要使用网络图片,或者 base64【不建议,因为生成的代码太多了】,或者使用<image >
组件
可以转base64的网站魔方工具箱。
网络图片挺简单的,可以部署到公司服务器上,也可以用博客园图片链接。
示例代码如下
index.wxml
<view class="background"></view>
index.scss
.background {
height: 400rpx;
background-image: url(https://img2024.cnblogs.com/blog/2818864-20250716233311272-1625153654.png);
}
事件系统
事件绑定和事件对象
小程序中绑定事件与在网页开发中绑定事件几乎一致,只不过在小程序不能通过 on 的方式绑定事件,也没有 click 等事件,小程序中绑定事件使用 bind 方法,click 事件也需要使用 tap 事件来进行代替,绑定事件的方式有两种:
- 第一种方式:bind:事件名,bind 后面需要跟上冒号,冒号后面跟上事件名,例如:
<view bind:tap="inName"><view>
- 第二种方式:bind事件名,bind后面直接跟上事件名,例如:
<viewbindtap=“inName”></view>
事件处理函数需要写到 js 文件中,在 .js 文件中需要调用小程序提供的 Page 方法来注册小程序的页面,我们可以直接在 Page 方法中创建事件处理函数。
示例代码如下:
.wxml文件
<text>pages/course/course.wxml</text>
<button type="warn" bind:tap="handler">绑定事件1</button>
<button type="primary" size="mini" bindtap="handler">绑定事件2</button>
<input type="text" bindinput="getInputVal"/>
.js文件
Page ({
handler() {
console.log('事件触发了')
},
getInputVal(event) {
// console.log(event)
console.log(event.detail.value)
}
})
注意:
-
触发事件时,绑定的函数会接收到一个事件对象参数,可以携带数据,比如这里的event.detail.value
-
在微信小程序中input标签时默认没有边框的,要进行样式设置
app.scss
input { border: 1rpx solid #ccc; }
事件分类以及阻止事件冒泡
事件分为 冒泡事件 和 非冒泡事件:
冒泡事件:当一个组件的事件被触发后,该事件会向父节点传递
非冒泡事:当一个组件的事件被触发后,该事件不会向父节点传递
使用 bind 绑定的事件,会触发事件冒泡,如果想阻止事件冒泡,可以使用 catch 来绑定事件
示例代码如下:
.wxml
<view class="catch" bind:tap="parentHandler">
<!-- 冒泡 -->
<button bind:tap="btnHandler">绑定事件</button>
<!-- 非冒泡 -->
<button catch:tap="btnHandler">绑定事件</button>
</view>
.js
parentHandler() {
console.log('父事件触发了')
},
btnHandler() {
console.log('子事件触发了')
}
.scss
.catch {
display: flex;
height: 300rpx;
background-color: skyblue;
align-items: center;
}
事件传参-data-*自定义数据
事件传参:在触发事件时,将一些数据作为参数传递给事件处理函数的过程,就是事件传参在微信小程序中,我们经常会在组件上添加一些自定义数据,然后在事件处理函数中获取这些自定义数据,从而完成业务逻辑的开发
在组件上 通过 data-”的方式,定义需要传递的数据,其中"是自定义的属性,例如:<view data-id="100" bindtap="handler”/>然后通过事件对象进行获取自定义数据。
通过打印event对象发现有两个带着数据呢,分别是
- currentTarget 事件绑定者,也就是指:哪个组件绑定了当前事件处理的函数
- target 事件触发者,也就是指:哪个组件触发了当前事件处理的数
- 例如:点击的是子级,那么父级接收到的是currentTarget中的数据是本身,而target是子级的数据。
示例代码如下
.wxml
<view class="catch" data-age="0" data-ddd="aaa" bind:tap="parentHandler">
<button data-id="2" data-name="tony">绑定事件</button>
</view>
.js
parentHandler(event) {
console.log(event.currentTarget.dataset.ddd)
console.log(event.target.dataset.name)
}
点击按钮,输出如下
aaa
tony
注意:
- 在传递参数的时候,如果自定义属性是多个单词,单词与词直接使用中划线-进行连接。在事件对象中会被转换为小托峰写法
- 在传递参数的时候,如果自定义属性是多个单词,单词如果使用的是小托峰写法。在事件对象中会被转为全部小写的
事件传参-mark 自定义属性
小程序进行事件传参的时候,除了使用 data-*属性传递参数外,还可以 使用 mark 标记传递参数
mark 是一种自定义属性,可以在组件上添加,用于来识别具体触发事件的target节点。同时 mark 还可以用于承载一些自定义数据
在组件上使用 mark:自定义属性 的方式将数据传递给事件处理函数,例如:<view mark:id=“100" bindtap="handler”/>然后通过事件对象进行获取自定义数据
比如这里有两个,一个是view蓝色区域,其中包含按钮,绑定事件是view,具体代码可参考data-的示例代码。两个组件都用mark传参。有两种情况,来体现mark特点
- 先点击蓝色区域(不点击按钮)。通过事件对象获取的是 view 身上绑定的数据
- 先点击按钮(不点击蓝色区域).通过事件对象获取到的是 触发事件的节点已经父节点身上所有的mark 数据
mark 和 data-*
很相似,主要区别在于:
mark 包含从触发事件的节点到根节点上所有的 mark: 属性值currentTarget.dataset 或者 target.dataset 只包含事件绑定者 或者 事件触发者那一个节点的 data-*值
wxml语法
声明和绑定数据
小程序页面中使用的数据均需要在 Page()方法的 data 对象中进行声明定义
在将数据声明好以后,在 WXML使用 Mustache 语法(双大括号{{}})将变量包起来,从而将数据绑定
在{{}}内部可以做一些简单的运算,支持如下几种方式:
- 算数运算
- 三元运算
- 逻辑判断
- 其他...
注意事项:在{{}}语法中,只能写表达式,不能写语句,也不能调用js 相关的方法
数据声明示例代码
.js文件中
Page ({
data: {
id: 1,
msg: {
code: 0,
state: true,
detail: '正常'
}
}
})
setData()修改数据
小程序中修改数据不推荐通过赋值的方式进行修改,通过赋值的方式修改数据无法改变页面的数据而是要通过调用 setData()方法进行修改,setData()方法接收对象作为参数,key 是需要修改的数据,value 是最新的值
setData()方法有两个作用:
- 更新数据
- 驱动视图更新
示例代码如下
.wxml
<text>num={{ num }}</text>
<button bind:tap="addNum">+1(赋值)</button>
<button bind:tap="addNumSetData">+1(setData)</button>
.js
Page ({
data: {
num: 1
},
addNum() {
this.data.num++;
console.log(this.data.num)
},
addNumSetData() {
this.setData({
// key:是需要更新的数据
// value:是录新的值
num: this.data.num + 1
})
}
})
setData()修改对象类型数据
- 新增 单个/多个属性
- 修改 单个/多个属性
- 删除 单个/多个 属性
新增或修改单个多个属性的代码【没有对应属性就新建】
updateUserInfo() {
this.setData({
//如果给对象新增属性,可以将 key写成数据路径的方式a.b.c
'userInfo.name': '李白',
'userInfo.age': '3000'
})
}
上面进行新增和修改都是使用效据路径,如果新增和修改的数据量比较小,还可以如果修改的数据很多,每次都写数据路径,就太麻烦了可以使用 ES6 提供的展开运算行和Object.assign()
示例代码如下
updateUserInfo() {
const userInfo = {
//通过展开运算符能够将对象中的属性复制给另一个对象
//后面的属性会覆盖前面的属性
...this.data.userInfo,
name: '刘邦',
age: 4000
}
this.setData({
// userInfo: userInfo
//属性和值名一样的时候,可以省略复制过程
userInfo
})
}
Object.assign(),将多个对象合并为一个对象
updateUserInfo() {
const userInfo = Object.assign(this.data.userInfo, {name: '李白'}, {age: 2000}, {works: {name: '蜀道难', detail: '行路难,行路难!'}})
this.setData({
// userInfo: userInfo
//属性和值名一样的时候,可以省略复制过程
userInfo
})
console.log(userInfo)
}
删除单个属性
updateUserInfo() {
delete this.data.userInfo.name
this.setData({
userInfo: this.data.userInfo
})
}
删除多个属性 rest 剩余参数
updateUserInfo() {
const {name, age, ...rest } = this.data.userInfo
this.setData({
userInfo: rest
})
console.log(this.data.userInfo)
}
setData()-修改数组类型属性
- 新增数组元素
- 修改数组元素
- 删除数组元素
.wxml
<view wx:for="{{ list }}" wx:key="index">{{ item }}</view>
<button type="primary" bind:tap="addList" style="margin: 16rpx">增加</button>
<button type="primary" bind:tap="updateList" style="margin: 16rpx">修改</button>
<button type="primary" bind:tap="deleteList" style="margin: 16rpx">删除</button>
.js
addList() {
//新增数组元素
//方法一
this.data.list.push(4)
this.setData({
list: this.data.list
})
//方法二
const newListOne = this.data.list.concat(5)
this.setData({
list: newListOne
})
//方法三
const newListTwo = [ ...this.data.list, 6 ]
this.setData({
list: newListTwo
})
},
updateList() {
this.setData({
'list[1]': 6
//'list[0].name': '刘邦'
})
},
deleteList() {
//方法一
this.data.list.splice(1, 1)
this.setData({
list: this.data.list
})
//方法二
const newList = this.data.list.filter(item => item !== 2)
this.setData({
list: newList
})
}
简易双向数据绑定
在 WXML中,普通属性的绑定是单向的,例如:<input value=”{{value}}"/>
如果希望用户输入数据的同时改变 dala 中的数据,可以借助简易双向绑定机制。在对应属性之前添加 model: 前缀即可
例如<input model:value="{{value}}" />
注意事项:简易双向绑定的属性值如下限制:
- 只能是一个单一字段的绑定,例如:错误用法:
<input model:value="值为{{value}}"/>
- 尚不能写 data 路径,也就是不支持数组和对象,例如:错误用法:<input model:value=“{{a.b}}"/>
测试时可以在调试器中AppData查看
列表渲染-基本使用
列表渲染 就是指通过循环遍历一个数组或对象,将其中的每个元素渲染到页面上
在组件上使用 wx:for 属性绑定一个数组或对象,既可使用每一项数据重复渲染当前组件
每一项的变量名默认为 item,下标变量名默认为 index
在使用 wx:for 进行遍历的时候,建议加上 wx:key 属性, wx:key 的值以两种形式提供:
-
字符串:代表需要遍历的 array 中 item 的某个属性,该属性的值需要是列表中唯一的字符串或数字,且不能动态改变
fruitList: [ { id: 1, name: '苹果'}, { id: 2, name: '香蕉'}, { id: 3, name: '梨'} ]
用wx:key="id"
-
保留关键字 *this 代表在 for 循环中的 item 本身,当 item 本身是一个唯一的字符串或者数字时可以使用
numList: [1, 2, 3]
wx:key="*this"
当然也可以用index,但建议写清晰点,具体可见修改数组类型属性的示例代码。
注意事项:
- 如果不加 wx:key,会报一个 waming,如果明确知道该列表是静态,即以后数据不会改变,或者不必关注其顺序,可以选择忽!
- 在给 wx:key 添加属性值的时候,不需要使用双大括号语法,直接使用遍历的 aray 中 item 的某个属性。
列表渲染-进阶用法
-
如果需要对默认的变量名和下标进行修改,可以使用 wx:for-item和 wx:for-index
- 使用 wx:for-item 可以指定数组当前元素的变量名
- 使用 wx:for-index 可以指定数组当前下标的变量名
注:其实就是起个新名字,在当前标签中要用新名,可以避免与其他数据重名。
-
将 wx:for 用在
<block />
标签上,以渲染一个包含多个节点的结构块<block />
并不是一个组件,它仅仅是一个包装元素,不会在页面中做任何渲染,只接受控制属性<block />
标签在 wxml 中可以用于组织代码结构,支持列表渲染、条件渲染等
注:其实很像vue中的temlate,在wxml中看不到其标签。
条件渲染
条件渲染主要用来控制页面结构的展示和隐藏,在微信小程序中实现条件渲染有两种方式:
- 使用 wx:if、wx:elif、wx:else 属性组
- 使用 hidden 属性
wx:if和 hidden 二者的区别:
- wx:if:当条件为 true 时将结构展示出来,否则结构不会进行展示,通过 移除/新增节点 的方式来实现
- hidden:当条件为 tue 时会将结构隐藏,否则结构会展示出来,通过 display 样式属性 来实现的
声明周期
小程序运行机制
小程序启动可以分为两种情况,一种是冷启动,一种是热启动
冷启动:如果用户首次打开,或小程序销毁后被用户再次打开,此时小程序需要重新加载启动
热启动:如果用户已经打开过某小程序,然后在一定时间内再次打开该小程序,此时小程序并未被销毁,只是从后台状态进入前台状态
前台 和 后台状态
小程序启动后,界面被展示给用户,此时小程序处于「前台」状态。
当用户「关闭」小程序时,小程序并没有真正被关闭,而是进入了「后台」状态,当用户再次进入微信并打开小程序,小程序又会重新进入「前台」状态
挂起:小程序进入「后台」状态一段时间后(5秒),微信停止小程序JS 线程执行,小程序进入「挂起」状态当开发者使用了后台播放音乐、后台地理位置等能力时,小程序可以在后台持续运行,不会进入到挂起状态
销毁:如果用户很久没有使用小程序,或者系统资源紧张,小程序会被销毁,即完全终止运行当小程序进入后台并被「挂起」后,如果很长时间(目前是30分钟)都未再次进入前台,小程序会被销毁当小程序占用系统资源过高,可能会被系统销毁或被微信客户端主动回收。
小程序更新机制
在访问小程序时,微信会将小程序代码包缓存到本地,
开发者在发布了新的小程序版本以后,微信客户端会检査本地缓存的小程序有没有新版本,并进行小程序代码包的更新。
小程序的更新机制有两种:启动时同步更新 和 启动时异步更新
启动时同步更新:微信运行时,会定期检査最近使用的小程序是否有更新。如果有更新,下次小程序启动时会同步进行更新,更新到最新版本后再打开小程序。如果 用户长时间未使用小程序时,会强制同步检查版本更新
启动时异步更新:在启动前没有发现更新,小程序每次 冷启动 时,都会异步检査是否有更新版本。如果发现有新版本,将会异步下载新版本的代码包,将新版本的小程序在下一次冷启动进行使用,当前访问使用的依然是本地的旧版本代码
在启动时异步更新的情况下,如果开发者希望立刻进行版本更新,可以使用 wx.getUpdateManager API进行处理。在有新版本时提示用户重启小程序更新新版本,
示例代码如下
App({
//onLaunch 是小程序的钩子的数,这个钩子的数在冷启动时肯定会执行到
//当小程序冷启动时,会自动微信后台请求新版本的信息,如果有新版本,会立即进行下载
//使用 wx.getUpdateManager 方法监听下我的状态
onLaunch () {
//使用 wx.getUpdateManager 方法监听下载的状态
const updateManager = wx.getUpdateManager()
//当下载完成新版本以后,会触发onUpdateReady 回调函数
updateManager.onUpdateReady(function () {
//在回调函数中给用户提示
wx.showModal({
title: '更新提示',
content: '新版本已经准备好,是否重启应用',
success(res) {
if (res.confirm) {
//强制当前小程序使用新版本并且会重启当前小程序
updateManager.applyUpdate()
}
}
})
})
}
})
测试
小程序声明周期介绍
应用生命周期是指应用程序进程从创建到消亡的整个过程
小程序的生命周期指的是 小程序从启动到销毁的整个过程
一个小程序完整的生命周期由 应用生命周期、页面生命周期 和 组件生命周期 三部分来组成小程序生命周期伴随着一些函数,这些函数由小程序框架本身提供,被称为生命周期函数【vue中的钩子函数】,生命周期函数会按照顺序依次自动触发调用。帮助程序员在特定的时机执行特定的操作,辅助程序员完成一些比较复杂的逻辑
应用生命周期
应用生命周期通常是指一个小程序从 启动 一> 运行 一 >销毁的整个过程
应用生命周期伴随着一些函数,我们称为 应用生命周期函数,应用生命周期函数需要 在 app.s 文件的 ApP() 方法中进行定义ApP()方法必须在 app.js 中进行调用,主要用来注册小程序,
应用生命周期函数由 onLaunch、onShow、onHide 三个函数组成
注:从小程序生命周期的角度来看,我们一般讲的「启动」专指冷启动,热启动一般被称为后台切前台。
页面生命周期
页面生命周期就是指小程序页面从 加载 →运行 销毁的整个过程
页面生命周期函数需要在Page()方法进行定义,这里的onShow也很有用,一般用于跳转到其他页面修改数据后,回到原来页面时数据的同步。
组件生命周期
后面跟组件一起说
生命周期两个细节
- tabBar 页面之间相互切换,页面不会被销毁
- 点击左上角,返回上一个页面,会销毁当前页面
小程序API
介绍
小程序开发框架提供丰富的微信原生AP!,可以方便的调起微信提供的能力,例如:获取用户信息、微信登录、微信支付等,小程序提供
的API几乎都挂载在 wx对象下,例如:wx.request()、wx.setStorage()等,wx 对象实际上就是小程序的宿主环境微信所提供的全局对象
异步 API 支持 callback & Promise 两种调用方式:
- 当接口参数 Object 对象中不包含 success/fail/complete 时将默认返回 Promise
- 部分接口如 request, uploadFile 本身就有返回值,因此不支持 Promise 风格的调用方式,它们的 promisify 需要开发者自行封装
网络请求
发起网络请求获取服务器的数据,需要使用 wx.request()接口 API
wx.request 请求的域名必须在微信公众平台进行配置,如果使用 wx.request 请求未配置的域名,在控制台会有相应的报错。
示例代码如下:
.wxml
<button type="primary" bind:tap="getData">获取数据</button>
.js
Page ({
data: {
list: []
},
//事件处理函数
getData () {
//如果需要发起网络请求,需要使用 wx.request API
wx.request({
//接口地址
url: 'https://baidu.com',
//请求方式
method: 'GET',
//请求参数
data: {},
//请求头
header: {},
//API 调用成功以后,执行的回调
success: (res) => {
console.log(res)
if (res.data.code === 200) {
this.setData({
list: res.data.data
})
}
},
//API 调用失败以后,执行的回调
fail: (err) => {
console.log(err)
},
//API 不管调用成功还是失败以后,执行的回调
complete: (res) => {
console.log(res)
}
})
}
})
但是暂时没有注册域名呢,可以通过设置跳过域名的校验,使其不报错。
跳过域名的校验的开发:
- 在微信开发者工具中,点击详情按钮,切换到本地详情,将不校验合法域名、web-view(业务域名)、TLS版本以及HTTPS证书 勾选上
- 在真机上,需要点击胶囊区域的分析按钮,在弹框中选择 开发调试,重启小程序后即可
注意事项:
这两种方式只适用于开发者工具、小程序的开发版和小程序的体验版,项目上线前必须在小程序管理平台进行
合法域名的配置
loading提示框
小程序提供了一些用于界面交互的 API,例如: loading 提示框、消息提示框、模态对话框等 APIloading 提示框常配合网络请求来使用,用于增加用户体验,对应的API有两个:
- wx.showLoading()显示loading 提示框
- wx.hideLoading()关闭 loading 提示框
注意:两个要成对使用,因为自己不会关闭
示例代码如下
Page ({
data: {
list: []
},
//事件处理函数
getData () {
wx.showLoading({
//用来显示提示的内容
//提示的内容不会自动换行,如果提示的内容比较多,因为在同一行展示
//多出来的内容就会被隐藏
title: '数据加载中...',
//是否展示透明蒙层,防止触摸穿透,开启了就无法其他操作了
mask: true
})
//如果需要发起网络请求,需要使用 wx.request API
wx.request({
...
complete: (res) => {
console.log(res)
wx.hideLoading()
}
})
}
})
模态对话框和消息提示框
wx.showModal():模态对话框,常用于询问用户是否执行一些操作
例如:询问用户是否退出登录、是否删除该商品 等
wx.showToast():消息提示框,根据用户的某些操作来告知操作的结果
例如:退出成功给用户提示,提示删除成功等
注意:还有很多属性,可以在开放文档查看
示例代码:
.wxml
<button type="warn" bind:tap="delHandler">删除</button>
.js
delHandler () {
wx.showModal({
title: '提示',
content: '确认要删除吗?',
complete: (res) => {
if (res.cancel) {
wx.showToast({
title: '已取消',
icon: "error"
})
}
if (res.confirm) {
wx.showToast({
title: '已删除',
})
}
}
})
}
本地存储
小程序本地存储是指在小程序中使用 AP! 将数据存储在用户的设备上,以便小程序运行时和下次启动时快速地读取这些数据
注意事项:对象类型的数据,可以直接进行存储获取,无需使用 JSON.stringify()、JSON.parse()转换
可以在调试器冲storage看出来,跟cookie差不多
示例代码
.wxml
<button size="mini" plain type="primary" bind:tap="setStorage">存储</button>
<button size="mini" plain type="warn" bind:tap="delStorage">删除</button>
<button size="mini" plain type="primary" bind:tap="getStorage">获取</button>
<button size="mini" plain type="warn" bind:tap="clearStorage">清空</button>
.js
setStorage () {
//同步方法
//传两个参数,键和值
// wx.setStorageSync('num', 1)
//还可以存对象
// wx.setStorageSync('obj', { name: 'tom', age: 10 })
//异步方法
//异步的函数要传对象
wx.setStorage({
key: 'num',
data: 1
})
wx.setStorage({
key: 'obj',
data: {
name: 'tom',
age: 10
}
})
},
delStorage () {
//同步方法
// wx.removeStorageSync('num')
//异步方法
wx.removeStorage({
key: 'num'
})
},
async getStorage () {
//同步方法
// const num = wx.getStorageSync('num')
// const obj = wx.getStorageSync('obj')
// console.log(num);
// console.log(obj);
//异步方法
const num = await wx.getStorage({
key: 'num'
})
//可以用{}来解构对象
const { data } = await wx.getStorage({
key: 'obj'
})
console.log(num);
console.log(data);
},
clearStorage () {
//同步方法
// wx.clearStorageSync()
//异步方法
wx.clearStorage()
}
路由与通信
在小程序中实现页面的跳转,有两种方式:
- 声明式导航:navigator 组件
- 编程式导航:使用小程序提供的 API
和navigatior属性对应。只不过参数是对象{url: "/pages/index/index"}
路径后可以带参数,参数与路径之间使用?分隔,参数键与参数值用=相连,不同参数用&分隔,例如:path?key=value&key2=value2
参数需要在跳转到的页面的 onLoad 钩子函数 中通过形参进行接收
示例代码:
onLoad(options) {
console.log(options)
}
上拉加载更多
上拉加载是小程序中常见的一种加载方式,当用户滑动页面到底部时,会自动加载更多的内容,以便用户继续浏览小程序中实现上拉加载的方式:
- 在 app.json 或者 page.json 中配置距离页面底部距离: onReachBotomDistance; 默认 50px
- 在 页面.js 中定义 onReachBottom 事件监听用户上拉加载
示例代码:
.json
{
"usingComponents": {},
"onReachBottomDistance": 100
}
.js
Page({
data: {
list: [1, 2, 3]
},
onReachBottom () {
// console.log("页面上拉刷新了");
//触发下滑时追究三个元素
wx.showLoading({
title: '正在加载...',
mask: true
})
setTimeout (() => {
let n = this.data.list.length
this.data.list.push(++n)
this.data.list.push(++n)
this.data.list.push(++n)
this.setData({
list: this.data.list
})
wx.hideLoading()
}, 1500)
}
})
.wxml
<view wx:for="{{ list }}" wx:key="*this">{{ item }}</view>
.scss
view {
height: 500rpx;
display: flex;
justify-content: center;
line-height: 500rpx;
&:nth-child(odd) {
background-color: skyblue;
}
&:nth-child(even) {
background-color: springgreen;
}
}
注意:wx.hideLoading()放到setTimeout外面就不会显示加载框。原因:
- JavaScript 是单线程的
微信小程序的 JS 引擎在主线程执行代码,UI 渲染也在同一线程。当代码执行时,UI 渲染会被暂停。 - setTimeout 的异步特性
setTimeout 会将回调函数放入任务队列,等待当前调用栈清空后执行。因此:
当 wx.showLoading() 执行后,加载框需要等待 JS 线程空闲才能渲染到屏幕。
如果 wx.hideLoading() 立即在 setTimeout 外部执行,JS 线程会先执行这行代码,导致 加载框还未渲染就被隐藏。
下拉刷新
下拉刷新是小程序中常见的一种刷新方式,当用户下拉页面时,页面会自动刷新,以便用户获取最新的内容
小程序中实现上拉加载更多的方式:
- 在 app.json 或者 page.json 中开启允许下拉,同时可以配置 窗口、loading 样式等
- 在 页面.js 中定义 onPullDownRefresh 事件监听用户下拉刷新
示例代码如下【结合加载的示例代码了】
.js
onPullDownRefresh () {
// console.log("刷新了");
this.setData({
list: [1, 2, 3]
})
//有时候回弹不上去
if (this.data.list.length === 3) {
wx.stopPullDownRefresh()
}
}
增强scroll-view
使用 scroll-view 实现上拉加载更多和下拉刷新功能
实际上就是通过设置scroll的属性进行实现
属性有很多,可以看开放文档
示例代码如下:
.wxml
<scroll-view
scroll-y
class="scroll-y"
lower-threshold="100"
bindscrolltolower="getMore"
enable-back-to-top
refresher-enabled
refresher-default-style="black"
refresher-background="#f7f7f8"
bindrefresherrefresh="refreshHandler"
refresher-triggered="{{ isTriggered }}"
>
<view wx:for="{{ list }}" wx:key="*this">{{ item }}</view>
</scroll-view>
.scss
.scroll-y {
height: 100vh;
}
view {
height: 500rpx;
display: flex;
justify-content: center;
line-height: 500rpx;
&:nth-child(odd) {
background-color: skyblue;
}
&:nth-child(even) {
background-color: springgreen;
}
}
.js
Page({
data: {
list: [1, 2, 3],
isTriggered: false
},
getMore () {
console.log("页面上拉加载了");
wx.showLoading({
title: '正在加载...',
mask: true
})
setTimeout (() => {
let n = this.data.list.length
this.data.list.push(++n)
this.data.list.push(++n)
this.data.list.push(++n)
this.setData({
list: this.data.list
})
wx.hideLoading()
}, 1500)
},
refreshHandler () {
console.log("下拉刷新了");
this.setData({
list: [1, 2, 3],
isTriggered: false
})
wx.showToast({
title: '刷新成功',
})
}
})
自定义组件
创建和注册组件
小程序目前已经支持组件化开发,可以将页面中的功能模块抽取成自定义组件,以便在不同的页面中重复使用也可以将复杂的页面拆分成多个低耦合的模块,有助于代码维护。
开发中常见的组件有两种:
- 公共组件:将页面内的功能模块抽取成自定义组件,以便在不同的页面中重复使用
- 页面组件:将复杂的页面拆分成多个低耦合的模块,有助于代码维护
创建
如果是公共组件,建议放在项目根目录的 components 文件夹中
如果是页面组件,建议放在对应页面的目录下【直接件组件名对应的文件夹就行,不用再创一个components文件夹】
建议:一个组件一个文件夹
注册
开发中常见的组件主要分为 公共组件 和 页面组件 两种,因此注册组件的方式也分为两种:
- 全局注册:在 app.json 文件中配置 usingComponents 进行注册,注册后可以在任意页面使用
- 局部注册:在页面的json 文件中配置 usingComponents进行注册,注册后只能在当前页面使用2
在 usingComponents 中进行组件注册时,需要提供 自定义组件的组件名 和 自定义组件文件路径
在将组件注册好以后,直接将 自定义组件的组件名 当成 组件标签名 使用即可
组件的数据和方法
组件数据和方法需要在 组件.js 的 Component 方法中进行定义,Component 创建自定义组件
- data:定义组件的内部数据
- methods:在组件中事件处理程序需要写到 methods 中才可以
其他与正常页面无异
如图所示:
组件的属性
Properies 是指组件的对外属性,主要用来接收组件使用者传递给组件内部的数据,和 data 一同用于组件的模板渲染
示例代码:
course.wxml
<custom-checkbox label="我已阅读并同意 用户协议 和隐私协议" position="right"/>
<custom-checkbox label="匿名提交" position="left"/>
custom-checkbox.wxml
<view class="custom-checkbox-box {{ position === 'right' ? 'right' : 'left' }}">
<checkbox checked="{{ isChecked }}" bind:tap="updateChecked" />
<view>
<text>{{ label }}</text>
</view>
</view>
custom-checkbox.scss
.custom-checkbox-box {
display: flex;
align-items: center;
}
.custom-checkbox-box.left {
flex-direction: row-reverse;
}
.custom-checkbox-box.right {
flex-direction: row;
}
custom-checkbox.js部分
properties: {
//如果需要接收传递的属性,有两种方式:全写、简写
// label:String
label: {
//type 组件使用者传递的数据类型
// 数据类型: String Number Boolean Object Array
// 也可以设置为 null,表示不限制类型
//value为初始值
type: String,
value: ''
},
position: {
type: String,
value: 'right'
}
},
效果图
注:传过来数据和data一样,也是可以在js中改的,但不建议,容易混淆
组件wxml的slot-插槽
在使用基础组件时,可以在组件中间写子节点,从而将子节点的内容展示到页面中,自定义组件也可以接收子节点只不过在组件模板中需要定义<slot/>
节点,用于承载组件中间的子节点。
示例代码如下:
course.wxml文件
<custom01>
<text>上面</text>
我是一个slot
<text>下面</text>
</custom01>
custom.wxml
<view>
<slot />
</view>
默认情况下,一个组件的 wxml 中只能有一个 slqf(默认插槽)需要使用多 slot 时,可以在组件js 中声明启用。
同时需要给 slot 添加 name 属性来区分不同的 s(ot(具名插槽)
然后给子节点内容添加 slot属性,属性值是对应 sot 的 name 名称,从而将内容插入到 对应的 slot 中
示例代码如下
course.wxml
<view>
<slot name="solt-top" />
<view><slot /></view>
<slot name="solt-bottom" />
</view>
custom.wxml
<view>
<slot name="solt-top" />
<view><slot /></view>
<slot name="solt-bottom" />
</view>
coustom.js
options: {
multipleSlots: true
}
组件样式以及注意事项
自定义组件拥有自己的 wxss 样式,组件 wxss 文件的样式,默认只对当前组件生效
编写组件样式时,需要注意以下几点:
- app.wxss 或页面的 wxss 中使用了标签名(view)选择器(或一些其他特殊选择器)来直接指定样式,这些选择器会影响到页面和全部组件,通常情况下这是不推荐的做法
- 组件和引用组件的页面不能使用id 选择器(#a)、属性选择器([a])和 标签名选择器,请改用 class 选择器
- 组件和引用组件的页面中使用后代选择器(.a.b)在一些极端情况下会有非预期的表现,如遇,请避免使用
- 子元素选择器(.a>.b)只能用于 vew 组件与其子节点之间,用于其他组件可能导致非预期的情况。
- 继承样式,如 font、color,会从组件外继承到组件内。
- 除继承样式外,全局中的样式、组件所在页面的的样式对自定义组件无效(除非更改组件样式隔离选项)
组件样式隔离
默认情况下,自定义组件的样式只受自身 wxss 的影响,但是有时候我们需要组件使用者的样式能够影响到组件,这时候就需要指定特殊的样式隔离选项 stylelsolation,选择它支持以下取值:
- isolated:表示启用样式隔离,在自定义组件内外,使用 cass 指定的样式将不会相互影响(一般情况下的默认值)
- apply-shared:表示页面 wxss 样式将影响到自定义组件,但自定义组件 wxss 中指定的样式不会影响页面
- shared:表示页面 wxss 样式将影响到自定义组件,自定义组件 wxss 中指定的样式也会影响页面和其他设置了 apply-shared或 shared 的自定义组件。
样式隔离拓展
- 在修改该一些默认组件样式【比如复选框】是,可以在开放平台中用浏览器参看元素类名,来修改样式。
- 同时如果自定义组件用shared的话,可以用后代选择器限制样式范围,避免混乱
数据监听器
数据监听器主要用于监听和响应任何属性(properies)和 数据(data)的变化,当数据发生变化时就会触发对应回调函数,从而方便开发者进行业务逻辑的处理
在组件中如果需要进行数据监听 需要使用 observers 字段
示例代码如下:
properties: {
label: {
type: String,
value: '测试'
}
},
/**
* 组件的初始数据
*/
data: {
num: 10,
count: 100,
obj: { name: 'Tom', age: 10},
arr: [1, 2, 3]
},
//用来监听数据已经属性是否发生了变化
observers: {
//key: 需要监听的数据
//value: 就是一个回调函数,形参:最新的数据
num: function (newNum) {
//对data中的数据进行监听,如果数据没有发生改变,监听器不会执行
console.log(newNum);
},
'num, count': function (newNum, newCount) {
console.log(newNum, newCount);
},
//支持监听属性以及内部数据的变化
'obj.name': function (newName) {
console.log(newName);
},
'arr[1]': function (newItem) {
console.log(newItem);
},
'obj.**': function (newObj) {
console.log(newObj);
},
label: function (newLabel) {
//只要组件使用者传递了数据,这时候监听器中就能获取传递的数据
//也就是说,监听器立即就执行了
console.log(newLabel);
}
},
组件通信 父->子
在组件属性中Properies ,已经提到传值了,不再重复,但提到不建议直接修改Properies 的数据,那我们一般把值赋值到data中,具体赋值可以用observers
示例代码如下:
observers: {
//如果需要将properties中的数据赋值给data
//可以使用observers
checked: function (newChecked) {
this.setData({
isChecked: newChecked
})
}
}
组件通信 子->父
子组件如果需要向父组件传递数据,可以通过小程序提供的事件系统实现,可以传递任意数据。
- 自定义组件内部使用 triggerEvent 方法发射一个自定义的事件,同时可以携带数据
- 自定义组件标签上通过 bind 方法监听 发射的事件,同时绑定事件处理函数,在事件函数函数中通过事件对象获取传递的数据
示例代码如下:
custom01.wxml
<button plain bind:tap="sendData">传递参数</button>
custom01.js
// components/custom01/custom01.js
Component({
/**
* 组件的初始数据
*/
data: {
num: 10
},
/**
* 组件的方法列表
*/
methods: {
sendData () {
//发出自定义事件,并携带参数给父组件
this.triggerEvent('sendEvent', this.data.num)
}
}
})
course.wxml
<custom01 bind:sendEvent="getData" />
course.js
getData(event) {
console.log(event);
this.setData({
num: event.detail
})
}
组件通信 获取组件实例
父组件可以 通过 this.selectComponent方法,获取子组件实例对象,这样就可以直接访问子组件的任意数据和方法this.selectComponent方法在调用时需要传入一个匹配选择器 selector
示例代码如下
course.wxml
<custom01 class="child" bind:sendEvent="getData" />
<button type="primary" plain bind:tap="getChild">获取参数</button>
course.js
getChild() {
//this.selectcomponent 方法获取子组件实例对象
//获取到实例对象以后,就能获取子组件所有的数据、也能调用子组件的方法
const res = this.selectComponent('.child')
console.log(res);
}
组件生命周期
组件的生命周期:指的是组件自身的一些钩子函数,这些函数在特定的时间节点时被自动触发
组件的生命周期函数需要在 lifetimes 字段内进行声明
组件的生命周期函数有5个:created、attached、ready、 moved、 detached
注意事项:created 钩子函数中不能调用 setData
示例代码
Component({
lifetimes: {
created () {
},
attached () {
},
detached () {
}
},
}
组件所在页面的生命周期
组件还有一些特殊的生命周期,这类生命周期和组件没有很强的关联
主要用于组件内部监听父组件的展示、隐藏状态,从而方便组件内部执行一些业务逻辑的处理
组件所在页面的生命周期有4个:show、 hide、resize、routeDone ,需要在 pageLifetimes 字段内进行声明
小程序生命周期总结
一个小程序完整的生命周期由 应用生命周期、页面生命周期 和 组件生命周期 三部分来组成
- 小程序冷启动,钩子函数执行的顺序
- 保留当前页面,进入下一个页面,钩子函数执行的顺序
- 销毁当前页面,进入下一个页面,钩子函数执行的顺序
- 小程序热启动,钩子函数执行的顺序
小程序冷启动,钩子函数执行顺序
拓展
使用Component构造页面
Component方法用于创建自定义组件
小程序的页面也可以视为自定义组件,因此页面也可以使用 Component 方法进行创建,从而实现复杂的页面逻辑开发
注意事项:
- 要求对应 json 文件中包含 usingComponents 定义段
- 页面使用 Component 构造器创建,需要定义与普通组件一样的字段与实例方法
- 页面 Page 中的一些生命周期方法(如 onLoad()等以“on“开头的方法),在 Component 中要写在 methods 属性中才能生效
- 组件的属性 Properties 可以用于接收页面的参数,在 onLoad() 中可以通过 this.data 拿到对应的页面参数
组件复用机制behaviors
小程序的 behaviors 方法是一种代码复用的方式,可以将一些通用的逻辑和方法提取出来,然后在多个组件中复用,从而减少代码冗余,提高代码的可维护性。
如果需要 behavior 复用代码,需要使用 Behavior()方法,每个 behavior 可以包含一组属性、数据、生命周期函数和方法
组件引用它时,它的属性、数据和方法会被合并到组件中,生命周期函数也会在对应时机被调用。
外部样式类
默认情况下,组件和组件使用者之间如果存在相同的类名不会相互影响,组件使用者如果想修改组件的样式,需要就解除样式隔离但是解除样式隔离以后,在极端情况下,会产生样式冲突、CSS 嵌套太深等问题,从而给我们的开发带来一定的麻烦。
外部样式类:在使用组件时,组件使用者可以给组件传入CSS 类名,通过传入的类名修改组件的样式如果需要使用外部样式类修改组件的样式,在 Component 中需要用 externalClasses 定义若干个外部样式类,
示例代码如下
course.scss
.my-class {
color: wheat;
}
course.wxml
<custom01 extend-class="my-class" />
custom01.js
Component({
externalClasses: ['extend-class']
})
custom01.wxml
<view class="extend-class">外部样式类</view>
Vant组件库
用好组件库可以很轻松的实现各种美观且高效的组件,并且各种组件可以相互引用,使用好组件库的前提要对自定义组件有个清晰的理解,这样才能在开源的组件库上进行个性化修改。下面是几个使用技巧。
属性设置
对用组件的个性化设置,比如自定义内容可以结合对solt的理解使用,同时这些属性可以传值,模块显示等控制,首先可以用官方页面的介绍,进行在标签内进行设置,非常的简单明了。
如下:
样式调整
对于前端工作中,样式设置占很大的工作量,对样式的要求往往很细致,对于组件对指定部分进行样式的设置是一个不容易的事情。对于这个工作也有一些小技巧
- 首先最简单的就是看首页有没有相关的类名,进行样式设置
- 其次可以在调试器的wxml中观察页面元素,寻找目标模块的类名,进行设置
- 最后都发现不了的话就要查看组件源代码,可以根据导入地址找到对应文件,根据对自定义组件的理解进行对结构的理解,其中可以先看wxml文件,了解大致结构,然后可以看wxss文件,更容易找到目标类名。
注:用css选择器是尽量用后代选择器进项多代选择,避免样式串扰
npm使用
node_modules
和 miniprogram_npm
在微信小程序开发里有明显区别,核心差异体现在 用途、内容和使用方式 上,帮你梳理清楚:
1. 核心区别总览
对比项 | node_modules |
miniprogram_npm |
---|---|---|
作用 | 存放 npm install 下载的原始依赖包 |
存放适配小程序的依赖包(构建后产物) |
谁生成的 | npm 下载自动生成 |
微信开发者工具构建生成 |
小程序是否用它 | 不用!直接引用会报错 | 必须用它!小程序运行时实际加载的目录 |
内容特点 | 包含所有源码、依赖、配置(体积大、冗余) | 只保留小程序需要的代码(体积小、可运行) |
2. 详细差异拆解
(1)node_modules
:开发时的“原材料”
- 作用:纯 Node.js 环境的依赖目录,存放
npm install
下载的完整包代码(含源码、测试用例、冗余文件等)。 - 问题:
- 小程序运行环境和 Node.js 不同,直接引用
node_modules
里的包会报错(语法、环境 API 不兼容)。 - 体积极大(比如
jspdf
可能依赖一堆 Node 专属库),无法直接打包进小程序。
- 小程序运行环境和 Node.js 不同,直接引用
(2)miniprogram_npm
:小程序的“成品库”
- 作用:微信开发者工具 构建 npm 后,把
node_modules
里的包转换成 小程序能运行的格式,生成的专属目录。 - 做了什么转换:
- 剔除 Node.js 专属代码(比如
fs
、path
等模块)。 - 替换成小程序兼容的语法(比如把
require
改成小程序支持的模块引用)。 - 只保留核心运行代码,体积大幅缩小。
- 剔除 Node.js 专属代码(比如
3. 为什么必须用 miniprogram_npm
?
小程序的运行环境不是完整的 Node.js 环境,缺少 fs
、process
等 Node 专属 API,直接用 node_modules
里的包会:
- 语法报错(比如
import/export
不兼容)。 - 运行报错(调用了小程序没有的 API)。
而 miniprogram_npm
是专门为小程序“裁剪、转换”后的依赖包,必须通过构建 npm 生成,才能被小程序正确识别。
4. 正确使用流程(避免踩坑)
- 安装依赖:
npm install jspdf # 下载到 node_modules
- 构建 npm:
微信开发者工具 → 菜单栏 工具 → 构建 npm → 生成miniprogram_npm
。 - 代码里引用:
// 必须从 miniprogram_npm 里引用! const jsPDF = require('miniprogram_npm/jspdf/jspdf.js').jsPDF;
简单总结:
node_modules
是“开发时的依赖仓库”,小程序不能直接用。miniprogram_npm
是“小程序专属的依赖包”,必须构建后使用。
必坑指南
- 本地图片无法在容器充当背景。微信小程序规定:background-image 只能使用网络图片或 base64 编码的图片,本地图片只能通过
标签展示。
- 请求文件时服务器返回413 Request Entity Too Large。是因为请求过程中,超出了限制,要对文件进行瘦身,比如降低质量,图片png改为jpg等。