零、文章目录
微信小程序07-开发进阶
1、案例:自定义标签栏
(1)案例分析
- 需求:通过前面的学习,我们知道微信小程序的底部标签栏可以在app.json全局配置文件中通过添加tabBar配置项的属性来实现。但是在实际开发中,底部标签栏会有不同的需求,例如需要设计更美观的样式或者需要添加更多的功能,此时就需要自定义标签栏。
(2)知识储备-创建自定义组件
-
自定义组件
- 在实际开发中,可能会遇到多个页面中有相同功能区域的情况。例如,多个页面中都有搜索栏。如果为每个页面复制同一份代码,会造成代码冗余,而且不利于后期代码维护。此时,开发者可以将页面内的重复部分封装成自定义组件,以便于在不同的页面中重复使用,从而有助于代码维护。
- 一个自定义组件是由JSON、JS、WXML和WXSS这4个文件组成的,自定义组件的组成文件通常存放在项目的components目录中,并且为了保证目录结构的清晰,通常会将不同的组件放在不同的子目录下。
-
创建自定义组件
-
①打开微信开发者工具,创建一个新项目或打开现有项目。
-
②在项目的根目录中右键单击,选择“新建文件夹”,然后输入新文件夹的名称“components”,按回车键确认。
-
③在components文件夹上右键单击,选择“新建文件夹”,然后输入新文件夹的名称“test”,按回车键确认。
-
④在test文件夹上右键单击,选择“新建Component”,然后输入组件的名称“test”,按回车键确认。确认后,微信开发者工具会自动生成组件的JS、JSON、WXML和WXSS文件。
-
组件和页面的JS与JSON文件区别如下
-
①组件的JSON文件中需要声明component属性,将属性值设为true,表示它是一个组件,而页面的JSON文件不需要添加该属性。
-
②组件的JS文件中调用的是Component()函数,而页面的JS文件调用的是Page()函数。
-
③组件的事件处理函数需要定义到methods中,页面的事件处理函数需要定义在Page({})中。
-
-
(2)知识储备-使用自定义组件
-
自定义组件创建完成后,在使用自定义组件之前,首先要引用自定义组件,需要提供每个自定义组件的标签名和对应自定义组件的文件路径。
-
自定义组件的引用方式分为局部引用和全局引用
- 在页面的JSON文件中引用自定义组件的方式称为局部引用,局部引用的自定义组件只能在当前被引用的页面内使用;
- 在app.json全局配置文件中引用组件的方式称为全局引用,全局引用的自定义组件可以在每个页面中使用。
-
局部引用
- 在pages/index/index.json文件中添加引用自定义组件的代码
"usingComponents": { "test": "/components/test/test" }
- 在pages/index/index.wxml文件中通过
<test>
标签使用自定义组件
<test></test>
-
全局引用
- 全局配置文件app.json文件中添加引用自定义组件的代码
"usingComponents": { "test": "/components/test/test" }
- 在pages/index/index.wxml文件中,通过
<test>
标签使用组件
<test></test>
(2)知识储备-用自定义组件渲染标签栏
-
微信小程序允许开发者使用自定义组件渲染标签栏,这样开发者就能自定义标签栏的显示效果,并且可以为自定义标签栏添加功能。
-
首先在app.json文件中配置两个页面
"pages": [
"pages/home/home",
"pages/message/message"
],
- 然后在app.json文件的tabBar配置项中添加"custom": true开启自定义标签栏
"tabBar": {
"custom": true,
"list": [{
"pagePath": "pages/home/home"
}, {
"pagePath": "pages/message/message"
}]
}
- 在项目根目录下创建名称为custom-tab-bar的文件夹,并在该文件夹中创建名称为index的组件,最后使用自定义组件的方式编写index组件即可。
(2)知识储备-Vant Weapp组件库
-
Vant Weapp组件库
- 在微信小程序实际开发中,内置的组件经常无法满足需求,手动编写自定义组件又会花费大量的时间,此时可以使用市场上成熟的开源组件库,提高开发效率。
- Vant Weapp是有赞前端团队开发的一套开源的微信小程序UI组件库,其界面风格统一、功能齐全,受到广泛关注。Vant Weapp组件库提供了一整套UI基础组件和业务组件,能够快速搭建出风格统一的页面。
- 若要在微信小程序中使用Vant Weapp组件库,需要利用Node.js提供的npm命令将Vant Weapp组件库安装到项目中,并在项目中进行一些配置。
-
具体的使用步骤如下
- ①在微信开发者工具中创建一个新的微信小程序项目,项目名称为“Vant”。
- ②打开命令提示符,切换工作目录到本项目的根目录,然后在命令提示符中执行以下命令,生成package.json文件。
npm init -y
- ③在命令提示符中执行以下命令,安装Vant Weapp包。
npm install @vant/weapp@1.10.4 -S –production
- ④修改app.json全局配置文件,将里面的"style": "v2"配置项删除,该配置项表示使用微信小程序的新版基础组件样式,删除该配置项表示使用旧版基础组件样式。Vant Weapp组件库需要覆盖基础组件样式才能生效,由于新版基础组件样式难以覆盖,可能会出现样式混乱的问题,所以应使用旧版基础组件样式。
- ⑤构建npm。微信小程序不能直接使用npm安装的包,需要将npm安装的包转换成微信小程序可以使用的包,具体方法是在微信开发者工具的菜单栏中执行“工具”→“构建npm”命令。
- miniprogram_npm是构建npm完成后的包的存放目录
- node_modules是npm安装的包的存放目录。
-
代码演示button组件使用
- 在app.json文件或页面的JSON文件的usingComponents配置项中引入button组件,以app.json文件为例。
"usingComponents": { "van-button": "@vant/weapp/button/index" }
- 在pages/index/index.wxml文件中使用button组件。
<van-button type="primary">按钮</van-button>
(3)案例实现
-
准备工作
- ①创建项目。在微信开发者工具中创建一个新的微信小程序项目,项目名称为“自定义标签栏”,模板选择“不使用模板”。
- ②安装Vant Weapp组件库。根据知识储备中的步骤进行安装。
- ③创建images文件夹。复制需要的图片素材进去,该文件夹保存了自定义标签栏的图片。
-
项目初始化
- ①创建自定义组件。在项目根目录下创建custom-tab-bar文件夹,然后在custom-tab-bar文件夹中创建index组件。
- ②编写全局配置文件app.json。
{ "pages": [ "pages/home/home", "pages/message/message", "pages/contact/contact" ], "window": { "backgroundTextStyle": "light", "navigationBarBackgroundColor": "#fff", "navigationBarTitleText": "自定义标签栏", "navigationBarTextStyle": "black" }, "tabBar": { "custom": true, "list": [{ "pagePath": "pages/home/home" }, { "pagePath": "pages/message/message" }, { "pagePath": "pages/contact/contact" }] }, "usingComponents": { "van-tabbar": "@vant/weapp/tabbar/index", "van-tabbar-item": "@vant/weapp/tabbar-item/index" }, "sitemapLocation": "sitemap.json" }
- ③编写3个页面中的内容。以pages/home/home页面为例,编写pages/home/home.wxml文件。
<!--pages/home/home.wxml--> <view>首页</view>
-
**实现标签栏页面布局:**在custom-tab-bar/index.wxml文件中实现页面布局
<!--components/custom-tab-bar/index.wxml-->
<van-tabbar active="{{ active }}" bind:change="onChange">
<van-tabbar-item wx:for="{{ list }}" wx:key="index" name="{{ item.name }}">
<image slot="icon" src="{{ item.iconPath }}" mode="aspectFit" style="width: 30px; height: 18px;" />
<image slot="icon-active" src="{{ item.selectedIconPath }}" mode="aspectFit" style="width: 30px; height: 18px;" />
{{ item.text }}
</van-tabbar-item>
</van-tabbar>
-
实现标签栏页面逻辑
- 在custom-tab-bar/index.js文件中编写标签栏逻辑。
// components/custom-tab-bar/index.js Component({ /** * 组件的属性列表 */ properties: { }, /** * 组件的初始数据 */ data: { active: 'home', list: [{ // "pagePath": "/pages/home/home", "text": "首页", "iconPath": "/images/tabs/home.png", "selectedIconPath": "/images/tabs/home-active.png", "name": "home" }, { // "pagePath": "/pages/message/message", "text": "消息", "iconPath": "/images/tabs/message.png", "selectedIconPath": "/images/tabs/message-active.png", "name": "message" }, { "pagePath": "/pages/contact/contact", "text": "联系我们", "iconPath": "/images/tabs/contact.png", "selectedIconPath": "/images/tabs/contact-active.png", "name": "contact" }] }, /** * 组件的方法列表 */ methods: { onChange({ detail }) { wx.switchTab({ url: `/pages/${ detail }/${ detail }`, }) } } })
- 在pages/home/home.js文件的Page({})中编写onShow()函数,将该页面对应的标签项激活。
onShow: function () { this.getTabBar().setData({ active: 'home' }) },
- 在pages/message/message.js文件的Page({})中编写onShow()函数,将该页面对应的标签项激活。
onShow: function () { this.getTabBar().setData({ active: 'message' }) },
- 在pages/contact/contact.js文件的Page({})中编写onShow()函数,将该页面对应的标签项激活。
onShow: function () { this.getTabBar().setData({ active: 'contact' }) },
-
页面实现效果
2、案例:电影列表
(1)案例分析
- 需求:电影列表”微信小程序用于展示正在热映的电影。
- “电影列表”微信小程序利用WeUI组件库实现页面效果,页面顶部有一个标签栏,标签栏中有3个标签项,分别是“正在热映”“搜索”“分类”,当用户点击其中一个标签项时,就会跳转到对应的标签页。
- 页面顶部的标签栏使用了WeUI组件库中的tab和navbar组件。
- “正在热映”标签页使用了WeUI组件库中的panel组件;
- “搜索”标签页使用了WeUI组件库中的searchbar组件;
- “分类”标签页使用了WeUI组件库中的grid组件。
(2)知识储备-WeUI组件库
-
在微信小程序开发中,经常会遇到多人协作开发的情况,不同开发者的风格不同,很难做到风格统一。微信官方设计团队为微信移动Web开发量身设计了一套与微信原生视觉体验一致的组件库——WeUI,该组件库可以让用户的使用感知更加统一。
-
在微信小程序中引入WeUI组件库有两种方式
-
通过useExtendedLib扩展库引入WeUI组件库:app.json文件中的useExtendedLib配置项用于添加扩展库,通过这种方式引入的组件将不会计入代码包大小。在app.json文件中添加配置。
"useExtendedLib": { "weui": true },
-
通过npm构建的方式引入WeUI组件库
- ①打开命令提示符,切换工作目录到当前项目的根目录,然后在命令提示符中执行如下命令,生成package.json文件。
npm init -y
- ②安装WeUI组件库。在项目根目录下执行以下命令进行安装。
npm install weui-miniprogram@1.2.3 --save
- ③构建npm。打开微信小程序开发工具,在菜单栏中执行“工具”→“构建npm”命令,构建完成后会在项目根目录生成miniprogram_npm文件夹。
- ④在项目的app.wxss文件中引入WeUI组件库
@import 'miniprogram_npm/weui-miniprogram/weui-wxss/dist/style/weui.wxss';
-
-
WeUI组件库中的组件有两种类型
- 一种是直接通过class样式类使用的组件
- 另一种是需要在页面的JSON文件或app.json文件中引入的组件。
- 关于这些组件的详细用法可以参考WeUI官方文档。
-
代码演示使用dialog弹窗组件
- 在pages/index/index.json文件中引入dialog弹窗组件。
{ "usingComponents": { "mp-dialog": "/miniprogram_npm/weui-miniprogram/dialog/dialog" } }
- 在pages/index/index.wxml文件中使用dialog弹窗组件。
<!--index.wxml--> <mp-dialog title="微信小程序" show="{{ show }}" bindbuttontap="tapDialogButton" buttons="{{ buttons }}"> <view>好好学习,天天向上!!!</view> </mp-dialog>
- 在pages/index/index.js文件中编写页面逻辑。
// index.js Page({ data: { show: true, buttons: [{ text: '取消' }, { text: '确认' } ] }, tapDialogButton: function (e) { console.log(e.detail) this.setData({ show: false }) } })
(2)知识储备-navigator组件
-
navigator组件
- 在HTML中,
<a>
标签可以实现页面间的跳转。 - 在WXML中,navigator组件常用于实现页面之间的跳转。
<navigator>navigator组件</navigator>
- navigator组件的常用属性如下。
- navigator组件的open-type属性用于指定跳转方式,常用的open-type合法值如下。
- 跳转tabBar页面,必须设置open-type属性值为switchTab;
- 跳转非tabBar页面且保留当前页面,设置open-type属性值为navigate时open-type属性可以省略。
- 在HTML中,
-
代码演示
- 创建pages/index/index和pages/detail/detail这两个页面。
- 在pages/index/index.wxml文件中添加navigator组件,实现点击“跳转到详情页”的时候进行页面跳转。
<navigator url="/pages/detail/detail?id=1" open-type="navigate">跳转到详情页</navigator>
- 在pages/detail/detail.js文件的onLoad()函数中输出options参数的值。
onLoad: function(options) { console.log(options) }
(3)案例实现
-
准备工作
- ①创建项目。在微信开发者工具中创建一个新的微信小程序项目,项目名称为“电影列表”,模板选择“不使用模板”。
- ②配置页面。本项目中的页面文件如下。
- ③配置导航栏。在pages/index/index.json文件中配置页面导航栏。
- ④配置样式和图片。在pages/index/index.wxss文件中配置样式,在images文件夹中放入图片素材。
- ⑤通过useExtendedLib扩展库的方式引入WeUI组件库,在全局配置文件app.json中添加配置
"useExtendedLib": { "weui": true }
-
**实现标签栏页面结构:**在pages/index/index.wxml文件中编写页面结构。
<!--index.wxml-->
<view class="page" data-weui-theme="{{ theme }}" data-weui-mode="{{ mode }}">
<view class="page__bd" style="height: 100%;">
<view class="weui-tab">
<!-- 标签栏 -->
<view class="weui-navbar">
<block wx:for="{{ tabs }}" wx:key="index">
<view aria-selected="{{ activeIndex == index ? true: false }}" id="{{ index }}" class="weui-navbar__item {{ activeIndex == index ? 'weui-bar__item_on' : '' }}" aria-role="tab" bindtap="tabClick">
{{ item }}
</view>
</block>
</view>
<!-- 正在热映 -->
<view id="panel1" aria-labelledby="tab1" class="weui-tab__panel" aria-role="tabpanel" hidden="{{ activeIndex != 0 }}">
<include src="tab1.wxml" />
</view>
<!-- 搜索 -->
<view id="panel2" aria-labelledby="tab2" class="weui-tab__panel" aria-role="tabpanel" hidden="{{ activeIndex != 1 }}">
<include src="tab2.wxml" />
</view>
<!-- 分类 -->
<view id="panel3" aria-labelledby="tab3" class="weui-tab__panel" aria-role="tabpanel" hidden="{{ activeIndex != 2 }}">
<include src="tab3.wxml" />
</view>
</view>
</view>
</view>
- **实现“正在热映”标签页页面结构:**在pages/index/tab1.wxml文件中编写页面结构。
<view class="page__hd">
<view class="page__title">电影列表</view>
</view>
<view class="page__bd">
<view class="weui-panel weui-panel_access">
<view class="weui-panel__bd">
<navigator wx:for="{{ contents }}" wx:key="index" aria-labelledby="js_p1m1_bd" class="weui-media-box weui-media-box_appmsg" url="../test/test">
<view aria-hidden="true" class="weui-media-box__hd">
<image class="weui-media-box__thumb" src="{{ item.poster }}" />
</view>
<view aria-hidden="true" id="js_p1m1_bd" class="weui-media-box__bd">
<text class="weui-media-box__title">{{ item.title }}</text>
<view class="weui-media-box__desc">{{ item.article }}</view>
</view>
</navigator>
</view>
<view class="weui-panel__ft">
<navigator class="weui-cell weui-cell_active weui-cell_access weui-cell_link" url="../index/index">
<text class="weui-cell__bd">查看更多</text>
<text class="weui-cell__ft"></text>
</navigator>
</view>
</view>
</view>
- **实现“搜索”标签页页面结构:**在pages/index/tab2.wxml文件中编写搜索框的页面结构。
<view class="page__bd">
<view class="weui-search-bar {{ inputShowed ? 'weui-search-bar_focusing' : '' }}" id="searchBar">
<form class="weui-search-bar__form" aria-role="combobox" aria-haspopup="true" aria-expanded="{{ inputVal.length > 0 ? 'true' : 'false' }}" aria-owns="searchResult">
<view class="weui-search-bar__box">
<i class="weui-icon-search"></i>
<input aria-controls="searchResult" type="text" class="weui-search-bar__input" placeholder="搜索" value="{{ inputVal }}" focus="{{ inputShowed }}" bindinput="inputTyping" />
<view aria-role="button" aria-label="清除" class="weui-icon-clear" wx:if="{{ inputVal.length > 0 }}" bindtap="clearInput"></view>
</view>
<label class="weui-search-bar__label" bindtap="showInput">
<i class="weui-icon-search"></i>
<span class="weui-search-bar__text">搜索</span>
</label>
</form>
<view aria-role="button" class="weui-search-bar__cancel-btn" bindtap="hideInput">取消</view>
</view>
</view>
<view class="page__bd page__bd_spacing">
<view class="weui-flex">
<view class="weui-flex__item">
<view class="placeholder">英雄儿女</view>
</view>
</view>
<view class="weui-flex">
<view class="weui-flex__item">
<view class="placeholder">大国工匠</view>
</view>
<view class="weui-flex__item">
<view class="placeholder">大国重器</view>
</view>
</view>
<view class="weui-flex">
<view class="weui-flex__item">
<view class="placeholder">长津湖</view>
</view>
<view class="weui-flex__item">
<view class="placeholder">集结号</view>
</view>
<view class="weui-flex__item">
<view class="placeholder">红海行动</view>
</view>
</view>
</view>
- **实现“分类”标签页页面结构:**在pages/index/tab3.wxml文件中编写页面结构。
<view class="weui-grids">
<navigator class="weui-grid" aria-role="button" url="../index/index" wx:for="{{ grids }}" wx:key="index">
<view class="weui-grid__icon">
<image src="../../images/icon_tabbar.png" />
</view>
<view class="weui-grid__label">{{ item }}</view>
</navigator>
</view>
- **实现页面逻辑:**在pages/index/index.js文件中实现页面逻辑。
// index.js
Page({
data: {
activeIndex: 0,
tabs: [
'正在热映', '搜索', '分类'
],
contents: [{
title: '英雄儿女',
article: '该影片讲述了多位英雄人物的故事,其中有浴血奋战的志愿军英模。',
poster: '/images/1.jpg',
}, {
title: '大国工匠',
article: '这部影片讲述了不同岗位劳动者用自己的灵巧双手,匠心筑梦的故事。',
poster: '/images/2.jpg',
}, {
title: '我和我的祖国',
article: '该影片取材新中国成立以来经历的无数个历史性经典瞬间,讲述普通人与国家之间息息相关密不可分的动人故事。',
poster: '/images/3.jpg',
}],
inputShowed: false,
inputVal: '',
grids: [
'爱情', '剧情', '喜剧', '家庭', '动画', '文艺', '都市', '动作', '科幻'
]
},
tabClick: function (e) {
this.setData({
activeIndex: e.currentTarget.id
})
},
inputTyping: function(e) {
this.setData({
inputVal: e.detail.value
})
},
showInput: function () {
this.setData({
inputShowed: true
})
},
hideInput: function () {
this.setData({
inputVal: '',
inputShowed: false
})
},
clearInput() {
this.setData({
inputVal: ''
})
},
})
- 页面实现效果