前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >小程序开发实践:视图容器 view介绍,使用 view 搞定所有常见的 UI 布局

小程序开发实践:视图容器 view介绍,使用 view 搞定所有常见的 UI 布局

作者头像
LIYI
发布2020-04-14 10:09:02
2.1K0
发布2020-04-14 10:09:02
举报
文章被收录于专栏:艺述论专栏艺述论专栏

目录

1,主要属性

1.1,hover-class

1.2,hover-stop-propagation

1.3,hover-start-time、hover-stay-time

1.4,拒绝300毫秒延迟

2,示例代码与最佳实践

2.1,使用hover-class定义按钮状态

2.2,使用view实现flex布局

2.2.1,justify-content的值

2.2.2,align-items的值

2.2.3,flex-wrap的值

2.2.4,align-content的值

2.2.5,flex-direction的值

3,相关问题

3.1,如何把view上的内容绘制在画布上?

文 / 石桥码农

字符16612,阅读13分钟,实践30分钟

1,主要属性

view 是最基础的,也是微信小程序第一个公布的容器组件。所谓容器组件,就像 HTML 里的 div 标签一样,是为容纳其它组件而存在的。它本身也可以有一些自己的样式,因为它本身也可以有样式,但它最重要的功能,是布局。

这个容器组件的主要属性有:

1.1,hover-class

指定按下去的样式类。当 hover-class="none" 时,或者没有设置这个属性时,没有点击态效果。单击后,当松开手指时,组件恢复变化前的状态。

代码:

代码语言:javascript
复制
<view hover-class="bc_red" class="section__title">flex-direction: row</view>

效果:

当按下去时,view容器应用了bc_red样式,松开后,恢复如初。

hover-class这个属性名称具有一定迷惑性。在HTML开发中,mouseHover事件指是的鼠标悬停于某页面元素之上时触发的事件,mouseDown才是鼠标按下去的事件。这里hover-class这个属性名称,从功能上来看,命名为tap-down-classpress-down-class更为合适。

1.2,hover-stop-propagation

指定是否阻止本节点的父及以上节点出现点击态。默认为false,不阻止。

阻止节点出现点击态,什么意思呢?

代码:

代码语言:javascript
复制
<!-- 阻止父节点出现hover状态 --><view hover-class="bc_red" class="section__title">  flex-direction: row  <view hover-stop-propagation hover-class="bc_green" class="section__title">    child view  </view></view>

两个view容器,里面那个view使用了hover-stop-propagation属性。由于它是一个布尔属性,只要写上属性,不填写属性值也代表真。如果写属性值的话,还要使用布尔值绑定:

代码语言:javascript
复制
hover-stop-propagation={{true}}

直接写"true",是字符串,是不行的。

效果:

从效果看,子容器有点击态,父容器没有,虽然父容器也设置了hover-class属性。

官方文档中关于这个属性是这样描述的:“指定是否阻止本节点的祖先节点出现点击态”,什么是“点击态”?既然是点击态,把属性名称全名为hover-stop-propagation就不妥当嘛,此处应该命名为press-stop-propagation更为合适。

现在我们看另外一个问题,通过事件跟踪,验证一下hover-stop-propagation属性的作用。

wxml代码:

代码语言:javascript
复制
<!-- 阻止父节点出现hover状态 --><view id="parentView" bindtap="onTap" hover-class="bc_red" class="section__title">  flex-direction: row  <view id="childView" bindtap="onTap" hover-stop-propagation hover-class="bc_green" class="section__title">    child view  </view></view>

在父子容器同时绑定了tap事件。为方便追踪,为父子容器分别分配了一个id。父容器idparentView,子容器idchildView

js:

代码语言:javascript
复制
onTap(e){  console.log(e.target)}

单击一次,输出:

代码语言:javascript
复制
{id: "childView", offsetLeft: 20, offsetTop: 64, dataset: {…}}{id: "childView", offsetLeft: 20, offsetTop: 64, dataset: {…}}

为什么输出两次?单击一次,为什么触发两次tap事件?

这是因为每个事件都有捕捉、目标与冒泡三个阶段,在view视图容器上使用bind绑定的事件,默认会在目标与冒泡两个阶段派发事件,一个是本身派发的,一个是子内容冒泡派发的。

冒泡事件会继续向上传递。hover-stop-propagation属性就是阻止冒泡事件向上传递的。当设置该属性后,父容器即parentView,便不会触发onTap的执行,这是我们在输出中只看到childView的原因。

那么怎么样可以让viewtap事件只触发一次呢?

可以使用catch绑定事件函数。catchbind的作用相同,与 bind 不同的是, catch 会阻止事件向上冒泡。

代码:

代码语言:javascript
复制
<!-- 阻止父节点出现hover状态,阻止冒泡 --><view id="parentView" bindtap="onTap" hover-class="bc_red" class="section__title">  flex-direction: row  <view id="childView" catchtap="onTap" hover-stop-propagation hover-class="bc_green" class="section__title">    child view  </view></view>

与前面代码只有一处不同,就是将子容器的bindtap改为了catchtap

读者朋友们可以自行测试一下,改用catch绑定事件函数后,onTap函数单击一次执行一次。

1.3,hover-start-time、hover-stay-time

hover-start-time是按住后多久出现点击态,hover-stay-time是手指松开后点击态保留多长时间,单位均是毫秒。没有特殊说明,微信小程序中所有属性中的时间单位都是毫秒。

这两个属性的设置说明,在view容器组件内部,有人掐表做了定时。当touchstart事件发生时,开始计时,到达hover-start-time时,应用hover-class样式;当touchstart结束,即startend事件发生时,开始hover-stay-time倒计时,时间到则移除hover-class样式。

设置hover-start-time属性,是为了方便开发者控制hover-class样式出现的时机。在测试中发现,但凡在view上单击一下,很正常的速度单击,不需要悬停,也会出现hover-class样式的应用。50ms是极短的时间,但是在计算机的微观世界却是一个极长的时间,这个时间已经足以包裹一次系统单击事件。

单击事件不是一个点事件,也是一个跨一定时间段的物理现象。在mac系统上,设置里有一个地方可以改变单击事件的跟踪速度。

改变这个跟踪速度后,在微信开发者工具模拟器中的tap事情也受其影响。如果你把跟踪速度调整到快的一侧,单击时只是轻轻慢慢地一按,系统是不会触发单击事件的。

1.4,拒绝300毫秒延迟

我们知道,当延迟超过100毫秒时,用户就会感觉到明显的卡顿。但是在移动设备上,特别在苹果的Safari浏览器上,我们不得不忍受300毫秒的延时。

这是为什么呢?

乔本斯在发布会上演示过这样一个功能,对于一个Safari浏览器打开的网页:

在右边内容区快速双击,苹果会帮助我们准确定位到文章的主体内容,并将其放大:

这个功能很酷。

但是有一个问题,如果用户不小心在双击时单击了一个链接,这让软件怎么处理呢?是马上跳转,还是等待用户的另一个单击以判断是不是双击事件?

苹果采用的是第二种方式,所有Safafi中的链接都要延迟300毫秒,如果用户没有发出第二个单击事件,再跳转链接。这导致苹果手机中的Html5页面都非常卡顿。

但是微信小程序没有这个问题,hover-start-time的默认时间是50ms,只需要50ms甚至更短就可以触发单击事件,微信小程序已经打破了300毫秒迟延的魔咒。

如果有人问你,使用微信小程序开发相比Html5开发,有什么优势?没有单击延迟就是在体验上一个很大的优势。

有一个问题留给读者朋友们思考,hover-start-time这个属性的值,最小可以设置为多少?设置为1毫秒可以吗,为什么?这个问题在之前的推文中提到过。

2,示例代码与最佳实践

使用hover-class,必使用hover-stop-propagation属性。

代码:

代码语言:javascript
复制
<view hover-stop-propagation hover-class="bc_green"></view>

这是为了避免父容器受子容器影响。

在自定义用于触发单击的按钮时,hover-class特别有用。一般按钮有两种状态:常态与按下的状态。使用hover-class正好可以定义按下的状态。

2.1,使用hover-class定义按钮状态

wxml代码:

代码语言:javascript
复制
<!-- 距形按钮 --><view class="section">  <button type="default" class="btn" plain hover-class="rect-btn__hover_btn"><icon type="success_no_circle" size="26px"></icon>完成</button></view><!-- 圆形按钮 --><view class="section">  <button hover-class="circle-btn__hover_btn"><icon type="success" size="80px"></icon></button></view><!-- 普通按钮 --><view class="section">  <button hover-class="rect-btn__hover_btn" type="primary">完成</button></view>

三个按钮均是基于button组件改造的。button是组件,同时实际上也是容器,所以在button上面也可以应用hover-class属性。

wxss代码:

代码语言:javascript
复制
.btn{  display: flex;  align-items: middle;  padding: 8px 50px 8px;  border: 1px solid #b2b2b2;  background-color: #f2f2f2;}.circle-btn__hover_btn {  opacity: 0.8;  transform: scale(0.95, 0.95);}.rect-btn__hover_btn {  position: relative;  top: 3rpx;  left: 3rpx;  box-shadow: 0px 0px 8px rgba(175, 175, 175, .2) inset;}

我们看看这三个类样式都有什么作用。

.btn是普通的自定义按钮样式。flexalign-items是为了实现文本与图标的横向对齐。#b2b2b2是符合微信设计规范的按钮边框色,#f2f2f2是按钮背景色。

transform使圆形按钮在单击时缩小0.05。按钮单击时微微缩小,这是从Flash交互时代传承下来的体验技巧。

#b2b2b2做为边框色,rgba(175, 175, 175, .2)是其做为rgba格式的20%透明形式,将它作为方形按钮按下状态的内阴影颜色,这也是符合微信颜色设计规范的。box-shadow这个样式用于定义组件的内阴影。

运行效果:

2.2,使用view实现flex布局

view容器组件最大的作用,就是实现ui布局。最常用的是flex布局,基本所有常见的布局都可以用它实现。flex布局指将display样式设置为flex,再加以其它相关的样式实现的布局。

关于flex布局有三个十分重要的样式:

  1. justify-content:调整内容,主轴方向的排列方式
  2. align-items:对齐元素,侧轴方向的对齐方式
  3. align-content:对齐多行内容,侧轴方向多行排列方式

以默认的flex-directionrow来看,即从左到右为主轴,自上而下为侧轴。

在这种情况下,justify-content管制的是元素在x方向的排列策略;align-items管制的是主轴上排列的元素,在侧轴方向,即y方向上的对齐方式;align-content管制的是当出现多行以后,多行内容在侧轴方向上,即y轴方向上的排列策略。

这三个属性很不好记,一时记住了,过一段时间用的时候可能还要查文档。可以这样辅助记住:

  1. 在默认的以x轴为主轴的情况下,即flex-directionrowjustify单词的意思为「调整」,css样式text-align有一个值是justify,意思是左右横向对齐,这里的justify也是横向调整的意思。至于content,它比items 的字面宽,更能代表行。
  2. 负责元素排列与对齐的样式,除了justify-content,就是align-items。既然justify-content负责的是横向调整,那么align-items负责的就是纵向对齐。
  3. 至于align-content,结合align-itemsjustify-content记忆。align指的是纵向对齐,content指的是行,那么align-content指的就是多行的纵向排列方式。
  4. flex-directionrow时,横向就是主轴,纵向就是侧轴。

下面分别看一下这三个样式的作用。

2.2.1,justify-content的值

flex-start:主轴起点对齐,默认值

wxml代码:

代码语言:javascript
复制
<view class="section">  <view class="section__title">justify-content:flex-start</view>  <view class="flex-wrp" style="flex-direction:row;;justify-content:flex-start">    <view class="flex-item bc_green">1</view>    <view class="flex-item bc_red">2</view>    <view class="flex-item bc_blue">3</view>  </view></view>

运行效果:

元素向主轴的起点看齐。与flex-start对应的值是flex-end

flex-end:主轴结束点对齐

wxml代码:

代码语言:javascript
复制
<view class="section">  <view class="section__title">justify-content:flex-end</view>  <view class="flex-wrp" style="flex-direction:row;justify-content:flex-end">    <view class="flex-item bc_green">1</view>    <view class="flex-item bc_red">2</view>    <view class="flex-item bc_blue">3</view>  </view></view>

运行效果:

元素在主轴方向上向尾部看齐。

center:在主轴中居中对齐

wxml代码:

代码语言:javascript
复制
<view class="section">  <view class="flex-wrp" style="flex-direction:row;justify-content:center">    <view class="flex-item bc_green">1</view>    <view class="flex-item bc_red">2</view>    <view class="flex-item bc_blue">3</view>  </view></view>

运行效果:

有空隙往首尾放,居中看齐。

space-between:向首尾看齐,相当于align-textjustify效果

wxml代码:

代码语言:javascript
复制
<view class="section">  <view class="flex-wrp" style="flex-direction:row;justify-content:space-between">    <view class="flex-item bc_green">1</view>    <view class="flex-item bc_red">2</view>    <view class="flex-item bc_blue">3</view>  </view></view>

运行效果:

两端的子元素靠向父容器两端,其他子元素之间的间隔相等。

space-around:元素之间的间隔,与与父容器之间的间隔相同

wxml代码:

代码语言:javascript
复制
<view class="section">  <view class="flex-wrp" style="flex-direction:row;justify-content:space-around">    <view class="flex-item bc_green">1</view>    <view class="flex-item bc_red">2</view>    <view class="flex-item bc_blue">3</view>  </view></view>

运行效果:

在视图效果上两边间隔较多一点,是因为外容器本身已经有了一个页边距。

2.2.2,align-items的值

stretch:填充整个容器,默认值

wxml代码:

代码语言:javascript
复制
<view class="section">  <view class="flex-wrp" style="flex-direction:row;justify-content:space-around;align-items:stretch;">    <view class="flex-item bc_green">1</view>    <view class="flex-item bc_red">2</view>    <view style="height:auto;" class="flex-item bc_blue">3</view>  </view></view>

bc_blue样式本身有一个height设定,为了让第三个子元素可以自由伸放,所以给它设置了heightautostyle内嵌样式的优先级高于class类样式。

运行效果:

第一个元素与第三个元素,均填充了整个父容器。在使用stretch这个值时,容器高度取决于最高的那个,其它次高元素必须在高度上可以自由伸缩,才可以发挥作用。不可以有heightmin-height等样式束缚。

flex-start:侧轴的起点对齐

wxml代码:

代码语言:javascript
复制
<view class="section">  <view class="flex-wrp" style="flex-direction:row;justify-content:space-around;align-items:flex-start;">    <view class="flex-item bc_green">1</view>    <view class="flex-item bc_red">2</view>    <view style="height:auto;" class="flex-item bc_blue">3</view>  </view></view>

运行效果:

默认x轴为主轴的情况下,效果就是顶部对齐了。

flex-end:侧轴的终点对齐

wxml代码:

代码语言:javascript
复制
<view class="section">  <view class="flex-wrp" style="flex-direction:row;justify-content:space-around;align-items:flex-end;">    <view class="flex-item bc_green">1</view>    <view class="flex-item bc_red">2</view>    <view style="height:auto;" class="flex-item bc_blue">3</view>  </view></view>

效果:

center:在侧轴中居中对齐

代码语言:javascript
复制
<view class="section">  <view class="flex-wrp" style="flex-direction:row;justify-content:space-around;align-items:center;">    <view class="flex-item bc_green">1</view>    <view class="flex-item bc_red">2</view>    <view style="height:auto;" class="flex-item bc_blue">3</view>  </view></view>

效果:

baseline:以子元素的第一行文字对齐

前面的flex-start、flex-end、center均是以元素本身所占的区域定位的,只有baseline是以内部的文本定位的。

wxml代码:

代码语言:javascript
复制
<view class="section">  <view class="section__title">以子元素的第一行文字对齐</view>  <view class="flex-wrp" style="flex-direction:row;justify-content:space-around;align-items:baseline;">    <view class="flex-item bc_green">1</view>    <view style="padding-top:30px;" class="flex-item bc_red">2</view>    <view style="height:auto;line-height:150px;" class="flex-item bc_blue"><text>3</text></view>  </view></view>

为了使baseline的对齐效果明显,特意给第二、第三个元素设置了不一样的属性。

效果:

这个特性在设计一些以文本居中显示的ui效果时很有用,无论文本周围有什么样的装饰效果,文本始终是在一条线上对齐的。

2.2.3,flex-wrap的值

flex-wrap这个样式是为了控制主轴一行显示不了时候的换行策略的。它有三个值:

  1. nowrap:不换行,默认值
  2. wrap:换行
  3. wrap-reverse:换行,第一行在最下面

默认不换行的情况下,便于实现横向滚动效果。我们重点看一下换行的效果。

wxml代码:

代码语言:javascript
复制
<view class="section">  <view class="section__title">多了换行</view>  <view class="flex-wrp" style="flex-direction:row;justify-content:flex-start;align-items:baseline;flex-wrap:wrap;">    <view class="flex-item bc_green">1</view>    <view class="flex-item bc_red">2</view>    <view style="height:auto;" class="flex-item bc_blue">3</view>    <view style="height:auto;" class="flex-item bc_blue">3</view>    <view style="height:auto;" class="flex-item bc_blue">3</view>  </view></view>

效果:

容器宽度不够的时候,会自动折到下一行显示;如果动态增加宽度,又会自动折回到上一行显示。这种特性方便实现一些瀑布流效果,不限定显示瀑布是几列,可以动态调整显示三列或四列。

2.2.4,align-content的值

通过前面justify-content、align-items两个样式可以看出来,具有相同名称的值定义具有相似的含义。例如flex-start、flex-end、center这三个值,它们表示的含义是近似的。

align-content是为了控制多行在侧轴方向的排列方式,这个样式有这些值:

代码语言:javascript
复制
stretch、center、flex-start、flex-end、space-between、space-around

这些样式值在前面都出现过,在这里代表的含义也与前面类似。我们看一下space-between的效果。

wxml代码:

代码语言:javascript
复制
<view class="section">  <view class="section__title">多行侧轴的对齐方式</view>  <view class="flex-wrp" style="flex-direction:row;justify-content:flex-start;align-items:baseline;flex-wrap:wrap;align-content:space-between;height:300px;">    <view class="flex-item bc_green">1</view>    <view class="flex-item bc_red">2</view>    <view style="height:auto;" class="flex-item bc_blue">3</view>    <view style="height:auto;" class="flex-item bc_blue">3</view>    <view style="height:auto;" class="flex-item bc_blue">3</view>    <view style="height:auto;" class="flex-item bc_blue">3</view>    <view style="height:auto;" class="flex-item bc_blue">3</view>  </view></view>

运行效果:

三行之间的间隔是相等的。

2.2.5,flex-direction的值

还有一个样式在flex布局中不得不提:flex-direction。它用于决定是x轴,还是y轴是主轴。默认情况下,也就是前面所讲的情况,是以x轴为主轴的。

如果将flex-direction的值改为column,效果:

值得一提的是,如果将y轴定为主轴的话,决定元素横向排列的就不是justify-content,而是align-items了。

wxml代码:

代码语言:javascript
复制
<view class="section">  <view class="section__title">flex-direction: column,align-items:center</view>  <view class="flex-wrp" style="height: 300px;flex-direction:column;align-items:center;">    <view class="flex-item bc_green">1</view>    <view class="flex-item bc_red">2</view>    <view class="flex-item bc_blue">3</view>  </view></view>

将侧轴方向上的对齐方式设定为center

效果:

x轴为侧轴,所以三个元素表现为左右居中。

flex-direction一共有四个值:

  1. row:从左到右的水平方向为主轴,是默认值
  2. row-reverse:从右到左的水平方向为主轴
  3. column:从上到下的垂直方向为主轴
  4. column-reverse:从下到上的垂直方向为主轴

row-reverserow相反,使元素在横向从右向左排列;column-reversecolumn相反,使元素从向下向上排列。

3,相关问题

3.1,如何把view上的内容绘制在画布上?

view目前不能直接转绘到画布上。如果想生成海报,一种可行的办法是:

  1. 使用wx.createCanvasContext创建一个画布
  2. 在画布上绘制内容,文本或图片
  3. 通过wx.canvasToTempFilePath保存到本地,并获取一个临时图片路径
  4. 通过wx.saveImageToPhotosAlbum保存临时图片到本地相册

有一个开源的小程序组件,封闭了通过json数据绘制海报的功能:

//github.com/Kujiale-Mobile/Painter

在阶段代码中集合了这个组件,运行效果为:

单击「保存」就可以将海报保存到本地了。

阶段源码:

//git.weixin.qq.com/rxyk/weapp-practice/repository/archive.zip?ref=2.2-view

好了,我是石桥码农,这就是今天分享的内容,有什么问题欢迎留言讨论,也欢迎进群交流。

2020年4月7日


参考文献

  • 凌征:"300 毫秒点击延迟的来龙去脉".[Online]Available://thx.github.io/mobile/300ms-click-delay(2020).
  • "view".[Online]Available://developers.weixin.qq.com/miniprogram/dev/component/view.html(2020).
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-04-09,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 艺述论 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1,主要属性
    • 1.1,hover-class
      • 1.2,hover-stop-propagation
        • 1.3,hover-start-time、hover-stay-time
          • 1.4,拒绝300毫秒延迟
          • 2,示例代码与最佳实践
            • 2.1,使用hover-class定义按钮状态
              • 2.2,使用view实现flex布局
                • 2.2.1,justify-content的值
                • 2.2.2,align-items的值
                • 2.2.3,flex-wrap的值
                • 2.2.4,align-content的值
                • 2.2.5,flex-direction的值
            • 3,相关问题
              • 3.1,如何把view上的内容绘制在画布上?
              相关产品与服务
              容器服务
              腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档