第5章 视图容器组件 通过前面内容的学习,读者对小程序有了一个大致的了解,包括组成小程序的各个文件,它们的作用是什么,以及小程序的MINA框架是怎么回事儿。那么从这一章开始,就要开始学习小程序开发的具体细节。 本章的主要内容是对视图容器组件的介绍。视图容器组件,简单来说与HTML中的
标签一样,是小程序页面布局的基础元素,用来组织元素的排布,设置页面的整体布局。当然小程序的视图容器组件要比单纯的
丰富得多,掌握了这部分内容,才能更好地设计出页面更加合理美观的小程序。 本章学习目标: 了解Flex布局的方式。 掌握对view组件、scrollview组件、swiper组件、movableview组件、movablearea组件、coverview组件、coverimage组件的使用。 5.1Flex布局和view组件 【任务要求】 新建一个如图51 所示的小程序页面,了解小程序页面组件的基本排列方式。 图51view组件布局 【任务分析】 本任务主要练习的是对view组件和微信小程序所采用的Flex布局的操作。观察图51 可以看到,整个页面的元素整体上来看是纵向排列的,而其中又插入了一个横向布局的三个方块和一个纵向布局的三个方块。因此需要对最外层设置成纵向排列,同时单独设置横向布局的三个方块为横向排列。 【任务操作】 (1) 打开示例项目,并在其app.json文件中新注册一个页面"pages/Chapter_5/5_1_view/5_1_view"。同时修改窗口的配置,使其达到如图51 所示的效果。修改完成后的app.json文件如下。 { "pages": [ "pages/Chapter_3/mina/mina", "pages/Chapter_3/page/page", "pages/Chapter_3/WXML/WXML", "pages/Chapter_3/WXKEY/WXKEY", "pages/Chapter_3/WXSS/WXSS", "pages/Chapter_4/frontend/frontend", "pages/index/index", "pages/logs/logs", "pages/Chapter_5/5_1_view/5_1_view" ], "window": { "navigationBarTextStyle": "black", "navigationBarTitleText": "演示", "navigationBarBackgroundColor": "#F8F8F8", "backgroundColor": "#F8F8F8" } } 微信小程序实用教程 第 5 章视图容器组件 保存文件并编译项目,让开发者工具自动生成所需的目录和页面。 (2) 修改5_1_view.json文件为如下所示代码,让窗口显示“view”。 { "navigationBarTitleText": "view" } (3) 在5_1_view.wxml文件中写入如下代码,填充页面元素。涉及本任务关键的元素会加粗表示。 view组件 flex-direction: row\n横向布局 flex-direction: column\n纵向布局 (4) 在5_1_view.wxss文件中编写如下代码,实现对页面的样式调整。涉及本任务重点的样式设置将会用粗体显示。 /* pages/Chapter_5/5_1_view/5_1_view.wxss */ page { background-color: #F8F8F8; height: 100%; font-size: 32rpx; line-height: 1.6; } .container { display: flex; flex-direction: column; min-height: 100%; justify-content: space-between; font-size: 32rpx; font-family: -apple-system-font,Helvetica Neue,Helvetica,sans-serif; } .page-head{ padding: 60rpx 50rpx 80rpx; text-align: center; } .page-head-title{ display: inline-block; padding: 0 40rpx 20rpx 40rpx; font-size: 32rpx; color: #BEBEBE; } .page-head-line{ margin: 0 auto; width: 150rpx; height: 2rpx; background-color: #D8D8D8; } .page-body { width: 100%; flex-grow: 1; overflow-x: hidden; } .page-section{ width: 100%; margin-bottom: 60rpx; } .page-section-title{ font-size: 28rpx; color: #999999; margin-bottom: 10rpx; padding-left: 30rpx; padding-right: 30rpx; } .page-section-spacing{ box-sizing: border-box; padding: 0 80rpx; } .flex-wrp{ margin-top: 60rpx; display:flex; } .flex-item{ width: 200rpx; height: 300rpx; font-size: 26rpx; } .demo-text-1{ position: relative; align-items: center; justify-content: center; background-color: #1AAD19; color: #FFFFFF; font-size: 36rpx; } .demo-text-1:before{ content: 'A'; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); } .demo-text-2{ position: relative; align-items: center; justify-content: center; background-color: #2782D7; color: #FFFFFF; font-size: 36rpx; } .demo-text-2:before{ content: 'B'; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); } .demo-text-3{ position: relative; align-items: center; justify-content: center; background-color: #F1F1F1; color: #353535; font-size: 36rpx; } .demo-text-3:before{ content: 'C'; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); } .flex-item-V{ margin: 0 auto; width: 300rpx; height: 200rpx; } (5) 在前面的任务中,均是将需要预览的页面放在app.json文件里pages数组的第一项,这样固然方便,但是当需要调试多个页面时, 图52添加编译模式 不停去修改app.json文件也比较麻烦。因此从这一部分起,将使用设置“编译模式”的方式来对页面进行预览。在工具栏中打开“普通编译”下拉框,选择“添加编译模式”(如图52 所示),在弹出的对话框中,给“模式名称”起名为“view”,从“启动页面”下拉框中选择“pages/Chapter_5/5_1_view/5_1_view”为启动页面(如图53 所示)。 图53自定义编译条件将页面5_1_view设置为启动页面 (6) 如图54 所示,选择刚刚新建的view编译模式,单击“编译”按钮,便可以在界面左边的模拟器中查看到刚刚编写的5_1_view页面的效果了。 图54使用自定义编译模式编译 【相关知识】 要想学习小程序的前端页面设计,Flex布局是一个非常重要的部分。和传统的布局解决方案使用 “盒状模型”,依赖display+position+float属性来控制元素的排列位置不同的是,于2009年由W3C(World Wide Web Consortium,万维网联盟)提出的新的Flex布局方案,可以简便、完整、响应式地实现各种页面布局。目前,它已经得到了所有浏览器的支持。在默认情况下,Flex布局是从左向右水平依次放置组件,或者是从上到下垂直依次放置组件。当一个标签的样式属性display的值设为flex时,便表示使用了Flex弹性布局方案。在本任务的实现过程中,使用到的flex样式属性见表51 。 表51常见Flex样式属性说明 属性 作用 可选值 说明 flexdirection 表示元素的排列方式 row 元素横向排列 column 元素纵向排列 justifycontent 表示元素在主轴上的排列方式。如果元素为横向排列,则主轴为水平轴 flexstart 紧挨着主轴开始处对齐 flexend 紧挨着主轴结尾处对齐 center 在主轴居中处对齐 spacebetween 元素平均分布在主轴上 spacearound 元素平均分布在主轴上,两边留有一半的间隔空间 alignitems 表示元素在侧轴上的排列方式。如果元素为横向排列,则侧轴为纵轴 stretch 默认值,元素被拉伸以适应容器 center 元素位于侧轴中心 flexstart 元素在侧轴开始处 flexend 元素在侧轴结尾处 baseline 元素位于容器内基线上 在上面任务的实现过程中,可以看到,在5_1_view.wxss文件中,container类的display属性值为Flex,表示整个页面布局采取的是flex方案; flexdirection属性值为column,表示元素整体为纵向排列; justifycontent属性值为spacebetween,表示元素平均分布在主轴(也就是纵轴)上。同时,在demotext1、demotext2和demotext3这三个类中,alignitems和justifycontent这两个属性值都被设为center,使得色块中的文本A、B、C能在色块中水平、垂直都居中显示。 在文件5_1_view.wxml中可以看到,第一个横向排列的色块组合,在标签中使用了内联样式style="flexdirection:row;",表示里面包含的三个色块采用横向排列,第二个纵向排列的三个色块组合,在标签中使用了内联样式style="flexdirection:column;",表示里面包含的三个色块采用的是纵向排列。因此,通过对元素的flex相关的属性进行设置,得到了任务要求所展示的元素排列。 除了Flex样式的相关属性设置和在3.6节组件部分提到的所有组件共有的属性外,view组件还包含的属性见 表52 。 表52view组件属性 属性名 类型 默认值 说明 最低版本 hoverclass String none 指定按下去的样式类。当 hoverclass="none" 时,没有效果 hoverstoppropagation Boolean false 指定是否阻止本节点的祖先节点出现单击态 1.5.0 hoverstarttime Number 50 按住后多久出现单击态,单位: 毫秒 hoverstaytime Number 400 手指松开后单击态保留时间,单位: 毫秒 表52 中的属性主要是给用户的单击操作提供视觉反馈,例如,如果要让一个view组件(以任务中的A色块为例)在被按住时背景颜色透明度发生改变,可以在view组件中编写如下代码。 然后定义类changecolor的样式为: .change-color{ background: rgba(26, 173, 25, 0.7); } 因此,每当该view组件(A色块)被单击时,其背景透明度就将变成0.7,可以给用户一个直观的视觉反馈效果。 5.2滚动视图组件scrollview 【任务要求】 使用滚动视图组件scrollview,使A、B、C三个色块能如图55 所示纵向滚动和横向滚动。同时监听滚动、滚动到顶部、滚动到底部的事件,在控制台观察事件输出。 图55scrollview组件任务示例 【任务分析】 本任务主要是练习scrollview组件的使用。从图55 可以看出,主要包含纵向滚动和横向滚动两部分。要想观察相关滚动事件的输出,还需要绑定滚动事件bindscroll,滚动到顶部/左边事件bindscrolltoupper,滚动到底部/右边事件bindscrolltolower。针对这些事件,需要在js文件中编写对应的处理函数,将事件详情输出在控制台中。 【任务操作】 (1) 打开示例项目,在app.json文件的pages数组中新增一项"pages/Chapter_5/5_2_scrollview/5_2_scrollview"。保存并编译项目,让开发者工具自动生成必要的目录和页面文件。 (2) 修改5_2_scrollview.json中的内容为如下代码,使页面窗口标题显示为scrollview。 { "navigationBarTitleText": "scroll-view" } (3) 在5_2_scrollview.wxml文件中编写如下代码,排列好页面元素。 scroll-view Vertical Scroll\n纵向滚动 Horizontal Scroll\n横向滚动 (4) 在5_2_scrollview.js文件中,添加对应的scroll函数,upper函数和lower函数用来处理滚动事件,滚动到顶部事件和滚动到底部事件。完成后的5_2_scrollview.js文件内容如下。和本任务相关的函数已加粗显示。 // pages/Chapter_5/5_2_scroll-view/5_2_scroll-view.js Page({ data: {}, onLoad: function (options) {}, onReady: function () {}, onShow: function () {}, onHide: function () {}, onUnload: function () {}, onPullDownRefresh: function () {}, onReachBottom: function () {}, onShareAppMessage: function () {}, upper(e) { console.log(e) }, lower(e) { console.log(e) }, scroll(e) { console.log(e) } }) (5) 在5_2_view.wxss文件中写入如下内容,完成对页面样式的调整。 /* pages/Chapter_5/5_2_scroll-view/5_2_scroll-view.wxss */ page { background-color: #F8F8F8; height: 100%; font-size: 32rpx; line-height: 1.6; } .container { display: flex; flex-direction: column; min-height: 100%; justify-content: space-between; font-size: 32rpx; font-family: -apple-system-font,Helvetica Neue,Helvetica,sans-serif; } .page-head{ padding: 60rpx 50rpx 80rpx; text-align: center; } .page-head-title{ display: inline-block; padding: 0 40rpx 20rpx 40rpx; font-size: 32rpx; color: #BEBEBE; } .page-head-line{ margin: 0 auto; width: 150rpx; height: 2rpx; background-color: #D8D8D8; } .page-body { width: 100%; flex-grow: 1; overflow-x: hidden; } .page-section{ width: 100%; margin-bottom: 60rpx; } .page-section-title{ font-size: 28rpx; color: #999999; margin-bottom: 10rpx; padding-left: 30rpx; padding-right: 30rpx; } .page-section-spacing{ margin-top: 60rpx; box-sizing: border-box; padding: 0 80rpx; } .scroll-view_H{ white-space: nowrap; } .scroll-view-item{ height: 300rpx; } .scroll-view-item_H{ display: inline-block; width: 100%; height: 300rpx; } .demo-text-1{ position: relative; align-items: center; justify-content: center; background-color: #1AAD19; color: #FFFFFF; font-size: 36rpx; } .demo-text-1:before{ content: 'A'; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); } .demo-text-2{ position: relative; align-items: center; justify-content: center; background-color: #2782D7; color: #FFFFFF; font-size: 36rpx; } .demo-text-2:before{ content: 'B'; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); } .demo-text-3{ position: relative; align-items: center; justify-content: center; background-color: #F1F1F1; color: #353535; font-size: 36rpx; } .demo-text-3:before{ content: 'C'; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); } (6) 添加一个名叫scrollview的编译模式,将页面5_2_scrollview设置为启动页,单击“编译”按钮,就可以在左边的模拟器中看到新建的页面的效果了。在模拟器中的纵向滚动区域滚动鼠标,可以在下方控制台看到对应事件的输出结果,分别如图56 ~图58 所示。 图56输出滚动到顶部事件详情 图57输出滚动事件详情 图58输出滚动到底部事件详情 【相关知识】 scrollview表示的是可滚动的视图区域。其包含的属性见表53 。 表53scrollview组件属性说明 属性名 类型 默认值 说明 scrollx Boolean false 允许横向滚动 scrolly Boolean false 允许纵向滚动 upperthreshold Number / String 50 距顶部/左边多远时(单位: px,2.4.0起支持rpx),触发 scrolltoupper 事件 lowerthreshold Number / String 50 距底部/右边多远时(单位: px,2.4.0起支持rpx),触发 scrolltolower 事件 scrolltop Number / String 设置竖向滚动条位置(单位: px,2.4.0起支持rpx) scrollleft Number / String 设置横向滚动条位置(单位: px,2.4.0起支持rpx) scrollintoview String 值应为某子元素id(id不能以数字开头)。设置哪个方向可滚动,则在哪个方向滚动到该元素 scrollwithanimation Boolean false 在设置滚动条位置时使用动画过渡 enablebacktotop Boolean false iOS单击顶部状态栏、安卓双击标题栏时,滚动条返回顶部,只支持竖向 bindscrolltoupper EventHandle 滚动到顶部/左边,会触发scrolltoupper事件 bindscrolltolower EventHandle 滚动到底部/右边,会触发 scrolltolower 事件 bindscroll EventHandle 滚动时触发,event.detail = {scrollLeft, scrollTop, scrollHeight, scrollWidth, deltaX, deltaY} 在本次任务中,第一组三个色块,通过设置标签的scrolly属性值为true,实现了色块的纵向滚动。需要注意的是,使用竖向滚动时,需要通过WXSS 设置 height,给一个固定高度。在本任务的第一个纵向滚动的scrollview中,设置了内联样式style="height: 300rpx;",固定了整个纵向滚动区域的高度为300rpx。在第二个滚动区域中,设置了标签的scrollx属性值为true,使得三个色块可以横向滚动。 在第一个纵向滚动的scrollview组件中,还对scrolltoupper事件通过设置bindscrolltoupper属性的值绑定了函数upper(),对scrolltolower事件通过设置bindscrolltolower属性的值绑定了函数lower(),对scroll事件通过设置bindscroll属性的值绑定了函数scroll()。在第二个横向滚动的scrollview组件中,同样绑定了scroll事件,并通过函数scroll()来处理。在5_2_scrollview.js文件中,upper()函数、lower()函数和scroll()函数均是将事件详情进行了直接的输出。在输出的内容中,除了事件均包含的公共内容外,其中的event.detail包含当前元素的一些位置信息。scrollLeft表示该元素显示(可见)的内容与该元素实际内容左边的距离,因此该值在第一个纵向滚动区域触发的scroll事件中为零,在第二个横向滚动区域触发的scroll事件中会随着元素的左右滚动发生变化。scrollTop表示该元素显示(可见)的内容与该元素实际内容上边的距离,因此该值在第一个纵向滚动区域触发的scroll事件中会随着元素的上下滚动而变化,在第二个横向滚动区域触发的scroll事件中为零。scrollHeight表示元素的总高度,scrollWidth表示元素的总宽度,均包括由于溢出而无法展示在网页的不可见部分。deltaX和deltaY则分别表示在横向上和纵向上元素移动的距离,纵向滚动的话,deltaX的值为零,横向滚动的话,deltaY的值为零。 使用scrollview组件除了前面提到的纵向滚动需要设置组件的固定高度外,还有以下几点需要注意的地方。 (1) 请勿在scrollview中使用textarea、map、canvas、video组件; (2) scrollintoview的优先级高于scrolltop; (3) 在滚动scrollview时会阻止页面回弹,所以在scrollview中滚动,是无法触发onPullDownRefresh的; (4) 若要使用下拉刷新,请使用页面的滚动,而不是scrollview,这样也能通过单击顶部状态栏回到页面顶部。 5.3滑块视图容器swiper 【任务要求】 创建一个页面,如图59 所示排列A、B、C三个色块,通过使用swiper组件使其可以横向滑动。同时增加一个按钮,动态控制是否显示指示点。 图59swiper组件有指示点(左)和无指示点(右)示例 【任务分析】 本次任务主要是练习swiper组件的使用。除了基本的排列显示三个色块外,还增加了一个动态控制指示点显示的功能,可以通过监听按钮的单击事件,动态修改swiper的indicatordots属性值来实现。 【任务操作】 (1) 打开示例小程序项目,在app.json文件的pages数组中新增页面“pages/Chapter_5/5_3_swiper/5_3_swiper”,单击“编译”按钮,生成5_3_swiper页面所需的文件。 (2) 打开5_3_swiper.json文件,修改其中内容为如下代码,使页面窗口标题栏显示“swiper”。 { "navigationBarTitleText": "swiper" } (3) 打开5_3_swiper.wxml文件,修改其中内容为如下代码,确定页面结构。 swiper (4) 在5_3_swiper.js文件中,新增changeIndicatorDots()函数,用来响应按钮的单击事件,修改指示点的显示状态。同时在data数组中,初始化indicatorDots的值为true,即默认显示指示点。代码如下。 // pages/Chapter_5/5_3_swiper/5_3_swiper.js Page({ data: { indicatorDots: true }, onLoad: function (options) {}, onReady: function () {}, onShow: function () {}, onHide: function () {}, onUnload: function () {}, onPullDownRefresh: function () {}, onReachBottom: function () {}, onShareAppMessage: function () {}, changeIndicatorDots() { this.setData({ indicatorDots: !this.data.indicatorDots }) } }) (5) 打开5_3_swiper.wxss文件,写入如下代码,完成对页面样式的设置。 /* pages/Chapter_5/5_3_swiper/5_3_swiper.wxss */ page { background-color: #F8F8F8; height: 100%; font-size: 32rpx; line-height: 1.6; } .container { display: flex; flex-direction: column; min-height: 100%; justify-content: space-between; font-size: 32rpx; font-family: -apple-system-font,Helvetica Neue,Helvetica,sans-serif; } .page-head{ padding: 60rpx 50rpx 80rpx; text-align: center; } .page-head-title{ display: inline-block; padding: 0 40rpx 20rpx 40rpx; font-size: 32rpx; color: #BEBEBE; } .page-head-line{ margin: 0 auto; width: 150rpx; height: 2rpx; background-color: #D8D8D8; } .page-body { width: 100%; flex-grow: 1; overflow-x: hidden; } .page-section{ width: 100%; margin-bottom: 60rpx; } .page-section-title{ font-size: 28rpx; color: #999999; margin-bottom: 10rpx; padding-left: 30rpx; padding-right: 30rpx; padding: 0; } .page-section-spacing{ box-sizing: border-box; padding: 0 80rpx; } .swiper-item{ display: block; height: 150px; } .demo-text-1{ position: relative; align-items: center; justify-content: center; background-color: #1AAD19; color: #FFFFFF; font-size: 36rpx; } .demo-text-1:before{ content: 'A'; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); } .demo-text-2{ position: relative; align-items: center; justify-content: center; background-color: #2782D7; color: #FFFFFF; font-size: 36rpx; } .demo-text-2:before{ content: 'B'; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); } .demo-text-3{ position: relative; align-items: center; justify-content: center; background-color: #F1F1F1; color: #353535; font-size: 36rpx; } .demo-text-3:before{ content: 'C'; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); } .btn-area { margin-top: 20rpx; box-sizing: border-box; width: 100%; padding: 0 30rpx; } (6) 添加一个名为swiper的编译模式,并将5_3_swiper设置为启动页面,使用新的swiper编译模式编译项目并在模拟器中预览效果。 【相关知识】 swiper组件和前面学到的scrollview组件不一样的是,swiper组件是一次滑动一项,而scrollview组件里的内容可以连续滑动。因此在我们的swiper示例页面中,除了一个标签外,里面还包含表示滑块项目的标签。 swiper组件的相关属性见表54 。 表54swiper组件属性 属性名 类型 默认值 说明 最低版本 indicatordots Boolean false 是否显示面板指示点 indicatorcolor Color rgba(0, 0, 0, .3) 指示点颜色 1.1.0 indicatoractivecolor Color #000000 当前选中的指示点颜色 1.1.0 autoplay Boolean false 是否自动切换 current Number 0 当前所在滑块的 index currentitemid String "" 当前所在滑块的 itemid ,不能与 current 被同时指定 1.9.0 interval Number 5000 自动切换时间间隔 duration Number 500 滑动动画时长 circular Boolean false 是否采用衔接滑动 vertical Boolean false 滑动方向是否为纵向 previousmargin String "0px" 前边距,可用于露出前一项的一小部分,接受 px 和 rpx 值 1.9.0 nextmargin String "0px" 后边距,可用于露出后一项的一小部分,接受 px 和 rpx 值 1.9.0 displaymultipleitems Number 1 同时显示的滑块数量 1.9.0 skiphiddenitemlayout Boolean false 是否跳过未显示的滑块布局,设为 true 可优化复杂情况下的滑动性能,但会丢失隐藏状态滑块的布局信息 1.9.0 bindchange EventHandle current改变时会触发 change 事件,event.detail = {current: current, source: source} bindanimationfinish EventHandle 动画结束时会触发animationfinish事件,event.detail 同上 1.9.0 在swiper组件中,只可以放置swiperitem组件,反之,swiperitem组件也只能放置在swiper组件中,而且其宽高会自动设置为100%。swiperitem组件的属性说明见表55 。 表55swiperitem组件属性说明 属性名 类型 默认值 说明 最 低 版 本 itemid String "" 该 swiperitem 的标识符 1.9.0 在本例中,我们在标签里面放置了三个标签,分别表示三个色块。在标签中,swiper组件用于确定是否显示面板指示点的属性indicatordots的值绑定到了后端的indicatorDots变量上。在5_3_swiper.js文件中的data对象中,indicatorDots被赋值为true,也就是默认显示指示点。我们为按钮的单击事件绑定了处理函数changeIndicatorDots,每次单击按钮,changeIndicatorDots函数便会将当前的indicatorDots变量值取反,实现通过单击按钮切换指示点显示状态的效果。 使用swiper组件,需要注意以下几点。 (1) swiper组件里只能放置swiperitem组件,swiperitem组件也只能被放置在swiper组件中。 (2) swiper组件的change事件返回的detail里面,source字段表示导致变更的原因。source字段的可能值如下。 ① autoplay: 自动播放导致swiper发生变化。 ② touch: 用户滑动引起swiper发生变化。 ③ "": 其他原因将用空字符串表示。 (3) 如果在bindchange的事件回调函数中使用setData改变current值,则有可能导致setData被不停地调用,因而通常情况下请在改变current值前检测source字段来判断是否是由于用户触摸引起的。 5.4可移动视图容器movableview和movablearea 【任务要求】 使用movableview组件和movablearea组件新建如图510 所示页面,分别实现滑块的横向移动,纵向移动,以及任意移动。实现按钮的单击移动到固定位置的功能,并在任意移动的滑块C中,绑定change事件,在控制台观察滑块移动事件的输出。 图510movableview组件示例 【任务分析】 本任务使用到的是可移动视图容器movableview和movablearea。movableview表示可移动的组件/视图,movablearea表示可移动的范围。在本例中,需要限制可以移动的方向,可以通过设置movableview组件的direction属性值来实现。需要实现单击按钮将滑块移动到指定位置的功能,可以通过监听按钮单击事件,动态修改movableview的x、y属性值来实现。 【任务操作】 (1) 打开示例小程序项目,在app.json文件的pages数组中新增页面“pages/Chapter_5/5_4_movableview/5_4_ movableview”,单击“编译”按钮,生成5_4_ movableview页面所需的文件。 (2) 修改5_4_movableview.json文件内容为如下代码,使页面的窗口标题显示movableview。 { "navigationBarTitleText": "movable-view" } (3) 修改文件5_4_movableview.wxml的内容为如下代码,完成页面元素的布局。 movable-view 只可以横向移动 A 只可以纵向移动 B movable-view可以在movable-area区域内任意移动 C (4) 修改文件5_4_movableview.wxss的内容为如下代码,完成页面的样式调整。 /* pages/Chapter_5/5_4_movable-view/5_4_movable-view.wxss */ page { background-color: #F8F8F8; height: 100%; font-size: 32rpx; line-height: 1.6; } button{ margin-top: 20rpx; margin-bottom: 20rpx; } .container { display: flex; flex-direction: column; min-height: 100%; justify-content: space-between; font-size: 32rpx; font-family: -apple-system-font,Helvetica Neue,Helvetica,sans-serif; } .wrap { display: flex; flex-direction: row; min-height: 100%; } .page-head{ padding: 60rpx 50rpx 50rpx; text-align: center; } .page-head-title{ display: inline-block; padding: 0 40rpx 20rpx 40rpx; font-size: 32rpx; color: #BEBEBE; } .page-head-line{ margin: 0 auto; width: 150rpx; height: 2rpx; background-color: #D8D8D8; } .page-body { width: 100%; flex-grow: 1; overflow-x: hidden; } .page-section{ width: 100%; margin-bottom: 20rpx; } .page-section-title{ margin-top: 50rpx; font-size: 28rpx; color: #999999; margin-bottom: 10rpx; padding-left: 30rpx; padding-right: 30rpx; } .page-section-title.top { margin-top: 0; } movable-view { display: flex; align-items: center; justify-content: center; height: 100rpx; width: 100rpx; background: #1AAD19; color: #fff; } movable-area { height: 300rpx; width: 300rpx; margin: 50rpx 0rpx 0 50rpx; background-color: #ccc; overflow: hidden; } .btn-area { margin-top: 20rpx; box-sizing: border-box; width: 100%; padding: 0 30rpx; } (5) 在5_4_movableview.js文件中,设定属性x,y的初始值为0,新增用于处理按钮单击事件的tap()函数以及处理滑块移动事件的onChange()函数。修改完成后的5_4_movableview.js文件内容如下。 // pages/Chapter_5/5_4_movable-view/5_4_movable-view.js Page({ data: { x: 0, y: 0, }, onLoad: function (options) {}, onReady: function () {}, onShow: function () {}, onHide: function () {}, onUnload: function () {}, onPullDownRefresh: function () {}, onReachBottom: function () {}, onShareAppMessage: function () {}, tap() { this.setData({ x: 30, y: 30 }) }, onChange(e) { console.log(e.detail) } }) (6) 新建名为movableview的编译模式,并设置“pages/Chapter_5/5_3_swiper/5_3_swiper”为启动页面。使用movableview编译模式编译项目,观察模拟器显示效果。 (7) 使用鼠标按住并移动滑块“C”,打开控制台,可以看到onChange()函数被执行并输出如图511 所示change事件的详情。 图511onChange()函数输出结果 【相关知识】 movableview表示可移动的视图容器,从基础库1.2.0开始支持,该容器可以在页面中拖曳滑动。其属性值说明见表56 。 表56movableview组件属性说明 属性名 类型 默认值 说明 最低版本 direction String none movableview的移动方向,属性值有all、vertical、horizontal、none inertia Boolean false movableview是否带有惯性 outofbounds Boolean false 超过可移动区域后,movableview是否还可以移动 x Number / String 定义x轴方向的偏移,如果x的值不在可移动范围内,会自动移动到可移动范围; 改变x的值会触发动画 续表 属性名 类型 默认值 说明 最低版本 y Number / String 定义y轴方向的偏移,如果y的值不在可移动范围内,会自动移动到可移动范围; 改变y的值会触发动画 damping Number 20 阻尼系数,用于控制x或y改变时的动画和过界回弹的动画,值越大移动越快 friction Number 2 摩擦系数,用于控制惯性滑动的动画,值越大摩擦力越大,滑动越快停止; 必须大于0,否则会被设置成默认值 disabled Boolean false 是否禁用 1.9.90 scale Boolean false 是否支持双指缩放,默认缩放手势生效区域是在movableview内 1.9.90 scalemin Number 0.5 定义缩放倍数最小值 1.9.90 scalemax Number 10 定义缩放倍数最大值 1.9.90 scalevalue Number 1 定义缩放倍数,取值范围为0.5~10 1.9.90 animation Boolean true 是否使用动画 2.1.0 bindchange EventHandle 拖动过程中触发的事件,event.detail = {x: x, y: y, source: source},其中,source表示产生移动的原因,值可为touch(拖动)、touchoutofbounds(超出移动范围)、outofbounds(超出移动范围后的回弹)、friction(惯性)和空字符串(setData) 1.9.90 bindscale EventHandle 缩放过程中触发的事件,event.detail = {x: x, y: y, scale: scale},其中x和y字段在2.1.0之后开始支持返回 1.9.90 除了基本事件外,movableview提供了两个特殊事件,说明见表57 。 表57movableview特殊事件 类型 触 发 条 件 最 低 版 本 htouchmove 初次手指触摸后移动为横向的移动,如果catch此事件,则意味着touchmove事件也被catch 1.9.90 vtouchmove 初次手指触摸后移动为纵向的移动,如果catch此事件,则意味着touchmove事件也被catch 1.9.90 movablearea表示movableview可移动的区域。其属性说明见表58 。 表58movablearea属性说明表 属性名 类型 默认值 说明 最低版本 scalearea Boolean false 当里面的movableview设置为支持双指缩放时,设置此值可将缩放手势生效区域修改为整个movablearea 1.9.90 movableview组件必须被包含在movablearea组件中,并且必须是直接子节点,否则便没有移动效果。当movableview小于movablearea时,movableview的移动范围是在movablearea内; 当movableview大于movablearea时,movableview的移动范围必须包含movablearea(x轴方向和y轴方向分开考虑)。 在本例中,三个可移动区域均是movableview小于movablearea,因此带有文本的色块也就只能在限定区域内移动。滑块“A”通过设定其direction属性值为horizontal,限制了其只能横向移动; 同理,滑块“B”的direction属性值被设置为vertical,因此只能纵向滑动。滑块“C”的direction属性值为all,表示不限制滑动方向,即可以在movablearea组件区域内任意移动。同时,滑块“C”的x属性,也就是横坐标值绑定到了后端变量x上; y属性,也就是纵坐标值,绑定到了后端变量y上,并且在5_4_movableview.js文件的data对象中,将x,y初始化为0,也就是顶齐movablearea区域的左上顶点显示。按钮的单击事件处理函数tap()则通过直接将x,y的值设置为30,实现了单击移动滑块“C”到指定位置的功能。 在使用鼠标按住并拖动滑块“C”的过程中,可以看到change事件的输出(如图511 所示),e.detail包含滑块的横、纵坐标信息,还有一个source字段表示产生改变的原因。当我们使用鼠标拖动时,可以看到source的值为“touch”,而当我们单击按钮直接将其定位到坐标为(30,30)的点时,可以看到控制台的输出如图512 所示。 图512使用按钮设置位置触发change事件输出 控制台的输出展示了滑块“C”从位置(0,0)移动到(30,30)的全过程,由于篇幅限制,图512 只截取了最后的四次输出。可以看到和图511 展示的输出不同的是,图512 的source字段为空字符串,因为这里的移动,是通过tap()函数里面的setData()直接改变x,y的值实现的,因此为空字符串。 使用movableview和movablearea组件,还有以下几点注意事项。 (1) movableview必须设置width和height属性,不设置则默认为10px; (2) movableview默认为绝对定位,top和left属性为0px; (3) movablearea必须设置width和height属性,不设置则默认为10px。 5.5coverview组件和coverimage组件 【任务要求】 新建如图513 所示页面,使用video标签在页面上放置一个视频,视频地址为http://t.cn/RIt6r8j。在视频上面使用coverview组件和coverimage组件放置三个由图片组成的控件,从左至右分别是播放、暂停以及停止,实现对视频播放的控制。 图513coverview和coverimage任务示例 【任务分析】 本次任务主要是针对coverview和coverimage组件的应用。这两个组件都是可以覆盖在其他组件之上的。在本次任务中,涉及视频组件的使用,包括对视频的控制操作,这部分内容可以参考第8章以及第12章内容,本次任务视频控制部分将不作重点讲解。 【任务操作】 (1) 打开示例小程序项目,在app.json文件的pages数组中新增页面“pages/Chapter_5/5_5_coverview/5_5_ coverview”,单击“编译”按钮,生成5_5_ coverview页面所需的文件。 (2) 在示例小程序项目的根目录下新建一个image文件夹,用于放置图片文件。在阿里巴巴矢量图标库(http://www.iconfont.cn/)中,分别以play、pause、stop为关键字搜索图标并下载,并将下载好的图片放置到image文件夹中。完成后的小程序文件目录结构如图514 所示。 图514image文件夹 (3) 在文件5_5_coverview.json中写入如下代码,配置窗口显示为“coverview”。 { "navigationBarTitleText": "cover-view" } (4) 在文件5_5_coverview.wxml中写入如下代码,完成页面元素的排布。 cover-view (5) 在5_5_coverview.wxss文件中写入如下代码,完成页面样式的调整。 /* pages/Chapter_5/5_5_cover-view/5_5_cover-view.wxss */ page { background-color: #F8F8F8; height: 100%; font-size: 32rpx; line-height: 1.6; } .container { display: flex; flex-direction: column; min-height: 100%; justify-content: space-between; font-size: 32rpx; font-family: -apple-system-font,Helvetica Neue,Helvetica,sans-serif; } .page-head{ padding: 60rpx 50rpx 80rpx; text-align: center; } .page-head-title{ display: inline-block; padding: 0 40rpx 20rpx 40rpx; font-size: 32rpx; color: #BEBEBE; } .page-head-line{ margin: 0 auto; width: 150rpx; height: 2rpx; background-color: #D8D8D8; } .page-body { width: 100%; flex-grow: 1; overflow-x: hidden; } .page-section{ width: 100%; margin-bottom: 20rpx; } .page-section-title{ margin-top: 50rpx; font-size: 28rpx; color: #999999; margin-bottom: 10rpx; padding-left: 30rpx; padding-right: 30rpx; } .page-section-gap{ box-sizing: border-box; padding: 0 30rpx; } .controls { position: relative; top: 50%; height: 50px; margin-top: -25px; display: flex; } .play,.pause,.stop { flex: 1; height: 100%; } .img { width: 40px; height: 40px; margin: 5px auto; } video{ width: 100% } (6) 在5_5_coverview.js文件中,新建play()函数、pause()函数、stop()函数实现对视频播放的控制。 // pages/Chapter_5/5_5_cover-view/5_5_cover-view.js Page({ data: {}, onLoad: function (options) {}, onReady: function () { this.videoCtx = wx.createVideoContext('myVideo') }, onShow: function () {}, onHide: function () {}, onUnload: function () {}, onPullDownRefresh: function () {}, onReachBottom: function () {}, onShareAppMessage: function () {}, play() { this.videoCtx.play() }, pause() { this.videoCtx.pause() }, stop() { this.videoCtx.stop() } }) (7) 新建一个名为coverview的编译模式,设置“pages/Chapter_5/5_5_coverview/5_5_coverview”为启动页面。使用coverview编译模式编译项目并在模拟器中观察页面效果。 【相关知识】 coverview和coverimage组件均是从基础库1.4.0开始支持。coverview表示覆盖在原生组件之上的文本视图,可覆盖的原生组件包括map、video、canvas、camera、liveplayer和livepusher,只支持嵌套coverview和coverimage,可在coverview中使用button。coverimage表示覆盖在原生组件之上的图片视图,可覆盖的原生组件同coverview,支持嵌套在coverview里。 coverview组件的属性说明见 表59。 表59coverview组件属性说明 属性名 类型 默认值 说明 最低版本 scrolltop Number/String 设置顶部滚动偏移量,仅在设置了 overflowy: scroll 成为滚动元素后生效(单位为px,2.4.0起支持rpx) 2.1.0 coverimage组件的属性说明见表510。 表510coverimage组件属性说明 属性名 类型 默认值 说明 最低版本 src String 图标路径,支持临时路径、网络地址(1.6.0起支持)、云文件ID(2.2.3起支持)。暂不支持base64格式 bindload EventHandle 图片加载成功时触发 2.1.0 binderror EventHandle 图片加载失败时触发 2.1.0 在本次任务中,在标签中嵌套了一个coverview组件,在这个coverview组件中,又嵌套了三个coverview组件,其中,每个coverview组件都嵌套了一个coverimage组件,用于放置三个控件图片。在三个coverview组件中,每个组件都绑定了tap事件,对应的处理函数play(),pause()和stop()实现了对视频播放的控制。 使用coverview组件和coverimage组件需要注意以下几点。 (1) 基础库2.2.4起支持touch相关事件,也可使用hoverclass设置单击态; (2) 基础库2.1.0起支持设置scalerotate的CSS样式,包括transition动画; (3) 基础库1.9.90起coverview支持overflow:scroll,但不支持动态更新overflow; (4) 基础库1.9.90起最外层coverview支持position:fixed; (5) 基础库1.9.0起支持插在view等标签下。在此之前只可嵌套在原生组件map、video、canvas和camera内,避免嵌套在其他组件内; (6) 基础库1.6.0起支持csstransition动画,transitionproperty只支持transform(translateX,translateY)与opacity; (7) 基础库1.6.0起支持cssopacity; (8) 事件模型遵循冒泡模型,但不会冒泡到原生组件; (9) 文本建议都套上coverview标签,避免排版错误; (10) 只支持基本的定位、布局、文本样式,不支持设置单边的border、backgroundimage、shadow、overflow:visible等; (11) 建议子节点不要溢出父节点; (12) 默认设置的样式有: whitespace:nowrap;lineheight:1.2;display:block; (13) 自定义组件嵌套coverview时,自定义组件的slot及其父节点暂不支持通过wx:if控制显隐,否则会导致coverview不显示。 练习题 1. 请使用表51中的justifycontent属性,通过为其设置不同的值,实现如图515所示的显示效果。 2. 请使用表51 中的alignitems属性,通过为其设置不同的值,实现如图516 所示的显示效果。 图515主轴对齐方式练习 图516侧轴对齐方式练习 3. 在页面上新增两个按钮,一个按钮实现单击一次,色块向下移动10px的功能,另一个按钮实现单击一次,滑动到下一个色块的功能(如图517 所示)。提示: 需要使用到表53 中的scrolltop和scrollintoview属性,然后为按钮设置监听单击事件,动态改变上述两个属性的值。 4. 新建如图518 所示页面,要求滑块为纵向滑动,默认显示指示点,同时实现四个按钮的相关功能。 5. 新建一个如图519 所示页面,放置A、B、C三个可移动区域和滑块。其中,区域A的movableview大于movablearea,对A色块设置渐变色便于观察movableview和movablearea的边界; 对B色块的属性值进行设置使得movableview边界可以超出movablearea边界; 对C色块绑定change事件和scale事件,新增一个按钮实现单击放大C色块的功能,并在控制台观察C色块change事件和scale事件的输出详情。 图517通过按钮控制滚动 图518swiper组件练习示例 图519movableview练习示例 6. 新建如图520 所示页面,在地图组件上覆盖A、B、C三个色块,并给色块设置一定的透明度。 图520coverview练习