@coder-pig
2019-07-04T15:52:43.000000Z
字数 23238
阅读 1653
小程序
标题和内容无关,只是前几天看卢姥爷的鬼畜:https://www.bilibili.com/video/av12611527,顺带消费下,上柱香~
看上一节《我写小程序像菜虚鲲——2、鸡你太美》的人比预想中少很多哇...
可能是我不够骚了(或者发的时间不对),不过还是建议阅读下「逆向微信小程序」那部分内容。本节来肝下
「微信小程序中布局」相关姿势点。希望你学完本章后,可以:根据设计尸给的设计稿,堆砌控件。
本节内容较多,建议点赞收藏以后有时间再看,毕竟 收藏了≈我会了,本文姿势点安排如下:
- 1、物理像素,设备独立像素,DPR,微信小程序特有尺寸rpx,设计稿尺寸;
- 2、WXSS样式导入的几种方式;
- 3、如何通过选择器定位到元素;
- 4、文档流与脱离文档流;
- 5、块级元素与行内元素,通过display属性转换;
- 6、盒子模型,box-sizing,外边距合并问题;
- 7、定位:相对定位,绝对定位,固定定位;
- 8、浮动与清除浮动;
- 9、多列布局multi-column,实现多列文本与简单图片瀑布流;
- 10、flex弹性布局;
- 11、布局实战:仿写每日优鲜首页。
px(pixel)像素,相信大家都不陌生吧,但是有三个名词要说下:
看到这里,读者可能会有疑问:为何像素还要分两种,有区别吗?
答:很久以前是没区别的,在CSS里写1px,屏幕就渲染一个物理像素,即DPR=1。随着苹果Retina技术的出现,这种局面被打破,使用Retina技术可以使用多个物理像素来渲染一个逻辑像素,屏幕尺寸没变,分辨率变高了,而人的视网膜无法分辨出屏幕上的像素点,这也是感觉Retina屏却比非Retina屏细腻的原因。
在Retina屏上DPR不再是1,而是大于1,比如iPhone 6的DPR=2,物理像素是:750x1334,对应的逻辑像素: (750x1334)/2 = 375x667。
名词科普到这里,接着说回rpx(responsive pixel),微信小程序特有尺寸单位,可以根据「屏幕宽度进行自适应」,规定:小程序屏幕宽度为750rpx。可以简单地理解为:
把页面按比例分割为750份,而每一份的大小是1rpx。
然后iPhone 6的物理像素刚好为750*1334,所以在iPhone 6中:
1rpx = 1个物理像素(1px)
所以,如果设计尸以 iPhone 6 为标准画设计稿的话,标注是多少px,小程序就直接多少rpx,不用换算,而且还不用担心在各个平台上的适配情况,卧槽,美滋滋啊!!!最后总结下结论,不难得出这样的等式:
在iPhone 6中:1rpx = 0.5px逻辑像素 = 1物理像素
关于CSS样式上节课就谈了,微信小程序中的WXSS稍微有点不一样。除了在目录下创建同名的.wxss文件会自动引用外。还可以使用@import语句 导入外部样式,相对路径,示例如下:
/* app.wxss */
@import './wxss/base.wxss';
除此之外,可以使用 style属性 设置内联样式,一般是接收 动态样式 用,而把 静态样式 统一写到class中,示例如下:
<view style="color:{{color}};" />
为元素设置样式,那你也得先定位到元素是吧!有如下三类最基础的选择器:
接着是具体定位到元素的各种操作示例:
/* 标签选择器*/
p{color: red;}
/* id选择器 */
#id-choose {color: green;}
/* class选择器 */
.class-choose {color: blue;}
/* 对选择器进行分组,共享同一个样式,逗号隔开 */
text, button, checkbox { color: green; }
.text-1, .text-2 { color: gold }
/* x元素内所有的y元素,选择作为x元素后代的y元素,称后代选择器或包含选择器 */
view text{ color: purple }
/* 还可使用*通配符选择所有元素 */
view *{ color: purple }
/* 父元素为x元素中的所有y元素,又称:子元素选择器 */
view > text{ color: red }
/* x元素后的所有y元素,又称:相邻兄弟选择器 */
view + text{ color: red }
/* 选择前面有x元素的每个y元素 */
view ~ text{ color: red }
/* 还可以通过属性来定位元素 */
<view aria-role="button" aria-label="submit-label">提交</view>
[aria-role]{ color: purple } /* 带有某属性 */
[aria-role="button"]{ color: purple } /* 带某属性且等于xxx */
[aria-label~="label"]{color: purple} /* 带某属性且包含XXX单词 */
[aria-label|="submit"]{color: purple} /* 带某属性且XXX单词开头 */
[aria-label^="su"]{color: purple} /* 带某属性且xx开头,不需要单词 */
[aria-label$="el"]{color: purple} /* 带某属性且xx结尾,不需要单词 */
[aria-label*="el"]{color: purple} /* 带某属性且包含xxx */
/* 还可以搭配元素选择器玩耍 */
view[aria-role]{ color: purple }
/* 伪类,根据顺序定位 */
.content-1 text:first-child{ color: pink } /* 父元素首个x元素 */
.content-1 text:last-child{ color: pink } /* 父元素最后一个x元素 */
.content-1 text:nth-child(n){ color: pink } /* 父元素第n个x元素 */
.content-1 text:nth-last-child(n){ color: pink } /* 父元素倒数第n个x元素 */
/* 伪元素 */
<view class="content">中间元素</view>
/* 元素前添加内容 */
.content:before{
content: "插在前面的文字";
color: red;
}
/* 元素后添加内容 */
.content:after {
content:url("http://codingboy.xyz/avator.png");
}
注意一点!!!
wxss无法获取本地图片资源,可使用 网络图片,base64后的图片 或 image标签!
再注意一点!!!
class属性值多个空格分隔,比如:<view class="font small blue">,其实就是指定多个class。这样写是为了CSS模块化设计,减少CSS重复代码,提高复用性。比如小程序中文本有几种,样式是基本一样的,可能只是字体大小或颜色不同,你就可以这样玩,代码示例如下:
<!-- wxml -->
<view class="font">
<view class="font small">
<view class="font small blue">
<!-- wxss -->
.font{ text-align: center; }
.font.small{ text-size: 18rpx; } /* 小号字体 */
.font.big{ text-size: 24rpx; } /* 大号字体 */
.font.small.blue{ text-color: blue; } /* 蓝色小号字体 */
<!-- 写了多个,如果有重复属性定义,那么后面的会覆盖前面的! -->
关于选择器更多内容可移步至:http://www.w3school.com.cn/cssref/css_selectors.asp
文档内元素的流动方向,内联元素从左往右,块级元素从上往下。
简单点说:元素在页面出现的先后顺序。
可能有些模糊,举个例子:
<view style="background-color: #FFBBFF; height: 96rpx; line-height: 96rpx; text-align:center">块元素①</view>
<text style="background-color: #CAFF70; ">行内元素①</text>
<text style="background-color: #EED8AE; ">行内元素②</text>
<text style="background-color: #FFA500; ">行内元素③</text>
<view style="background-color: #F08080; height: 96rpx; line-height: 96rpx; text-align:center">块元素②</view>
<view style="background-color: #EEEE00; height: 96rpx; line-height: 96rpx; text-align:center">块元素③</view>
运行结果如下:
按照:内联元素从左往右,块级元素从上往下(独占一行),这样的规则就是「正常文档流」,如果我们通过一些手段,使得元素不按照这个规则进行排布,就叫「脱离文档流」。比如为行内元素②设置一个向右的浮动:
<text style="background-color: #EED8AE; float:right">行内元素②</text>
就变成了这样:
行内元素②没有跟在①后,而③也没有跟在②后,这就是 脱离文档流。
块级元素:
- 独占一行,且宽度会占满父元素宽度,即容器的100%;
- 可设置width和height,不过即使设置了width还是会独占一行;
- 可设置margin和padding;
- 可容纳内联元素和其他块元素;
- 比如:<view>标签
行内(内联)元素:
- 不独占一行,相邻行内元素可以排在同一行;
- 宽高为文字或图片的宽高,不可变,即设置width/height无效;
- 设置margin和padding 水平方向有效,垂直方向无效;
- 只能容纳文本或者其他内联元素;
- 比如:<text>标签
可以通过 display
属性来完成行内元素和块级元素的切换,有三个可选值:
- block:设置为块元素。
- inline:设置为行内元素。
- inline-block:行内块元素,让元素具有块级元素和行内元素的特性,即能
设置宽高,margin和padding生效,还可以和其他行内元素并排。
举个例子:
<!-- test.wxml -->
<view class="container">
<view class="block-1">块元素-1</view>
<view class="block-2">块元素-2</view>
<view class="block-3">块元素-3</view>
<view class="block-3">块元素-4</view>
<text class="inline-1">行内元素-1</text>
<text class="inline-2">行内元素-2</text>
<text class="inline-3">行内元素-3</text>
<view>
<view class="display-inline">行内块元素-1</view>
<view class="display-inline">行内块元素-2</view>
</view>
<view>
<text class="display-block">行内块元素-3</text>
<text class="display-block">行内块元素-4</text>
</view>
<view>
<view class="display-inline-block">行内块元素-5</view>
<view class="display-inline-block">行内块元素-6</view>
</view>
</view>
/* test.wxss */
/* 块元素 */
.block-1{
background: red
}
/* 块元素可以直接设置margin和padding */
.block-2 {
background: greenyellow;
margin-right: 50rpx;
margin-top: 50rpx;
padding-bottom: 25rpx;
padding-left: 25rpx;
}
/* 块元素设置宽高,但是依旧是占一行 */
.block-3 {
background: paleturquoise;
height: 96rpx;
width: 200rpx;
}
/* 行内元素 */
.inline-1 {
background: red
}
/* 行内元素设置margin和padding,只有水平方向生效 */
.inline-2 {
background: greenyellow;
margin-right: 50rpx;
margin-top: 50rpx;
padding-bottom: 25rpx;
padding-left: 25rpx;
}
/* 行内元素设置宽高不生效 */
.inline-3 {
background: paleturquoise;
height: 96rpx;
width: 200rpx;
}
/* 块元素转换为行内元素 */
.display-inline {
display: inline;
background: orange;
margin-right: 50rpx;
padding-bottom: 25rpx;
padding-left: 25rpx;
}
/* 行内元素转换为块元素 */
.display-block {
display: block;
background: pink;
margin-right: 50rpx;
padding-bottom: 25rpx;
padding-left: 25rpx;
margin-top: 40rpx;
height: 96rpx;
width: 200rpx;
}
/* 行内块元素,同时拥有块级元素和行内元素的特性 */
.display-inline-block {
display: inline-block;
width: 300rpx;
height: 100rpx;
background: gold;
margin-left: 50rpx;
margin-top: 20rpx;
}
运行结果如下:
元素被描绘成「矩形盒子」,这些盒子通过一个模型来描绘它的占用空间,即「盒子模型」。
如图,盒子模型通过下述四个边界来描述:
暂且把这个大盒子称为「元素框」,设置width和height指的是内容部分宽高,设置内外边距和边框不会影响内容区域的尺寸,但是会增加元素框的总尺寸。举个例子,你定义了一个48rpx*48rpx的view,但是如果你还设置了margin或padding,那么这个元素的元素框尺寸就不止48rpx*48rpx了!
如果你想设置「元素框」的宽高固定,不会因为设置了边距和边框而改变宽高,可以使用「box-sizing」来实现,该属性有下述两个可选值:
- content-box:宽高仅是内容宽高,加上padding和border,模型宽高会变大.
- border-box:以border为边界,宽高是包括边框和内边距的,设置padding模型宽高也不会变。
使用代码示例如下:
<!-- test.wxml -->
<view class="view-wrapper">
<view class="view-1">元素1</view>
<view class="view-2">元素2</view>
</view>
/* test.wxss */
page {
background: gray;
}
view {
text-align: center;
width: 240rpx;
height: 240rpx;
line-height: 240rpx;
border: 10rpx solid white;
}
.view-wrapper {
width: 75%;
background: gold;
padding: 50rpx;
overflow: hidden;
border: none;
}
.view-1 {
background: greenyellow;
box-sizing: content-box;
float: left;
}
.view-2 {
background: blueviolet;
box-sizing: border-box;
float: right;
}
运行结果如下:
当两个或更多垂直外边距相遇时,它们将形成一个外边距,合并后的外间距高度等于两个元素中外边距高度中的较大者。
单看概念有点含糊,写个简单的例子来帮助理解(相邻元素):
<!-- test.wxml -->
<view class="container">
<view class="view-1">元素1</view>
<view class="view-2">元素2</view>
</view>
接着设置两个样式
.view-1 { background: gold; }
.view-2 { background: red; }
接着按照下述步骤修改样式:
- ① view-1设置:margin-bottom: 50rpx。
- ② 注释掉view-1的样式,view-2设置:margin-top: 10rpx。
- ③ 去掉view-1的注释。
每一步的结果如下:
如图,两个元素最后的边距是50rpx,而不是50rpx + 10rpx = 60rpx;
接着我们再来试试 负值 的情况
.view-1 { background: gold; margin-bottom: -10rpx}
.view-2 { background: red; margin-top: 30rpx}
运行结果如下:
不难发现此时的外边距是20rpx,再试试负数比整数大的情况:
.view-1 { background: gold; margin-bottom: 10rpx}
.view-2 { background: red; margin-top: -20rpx}
同样不难发现此时的外边距是-10rpx,再试试两个都是负数的情况:
.view-1 { background: gold; margin-bottom: -10rpx}
.view-2 { background: red; margin-top: -20rpx}
此时的外边距是-20rpx,分析计算下规律:
- 一正一负,先求绝对值差(绝对值大-绝对值小),再设置正负;
- 同正同负:去绝对值大的那个,在设置正负。
如果不想面对外边距合并问题,有下述几种规避方法:
- ① 下面的元素设置绝对定位:position:absolute;
- ② 下面的元素设置下浮动:float:left;
- ③ 任意一个盒子设置为为行内块元素:dispaly:inline-block;
除了上面这种「相邻元素」会出现外边距合并问题外「父子元素」也可能会,
没有内边距和边框隔开。写个简单的测试例子体验下:
<view class="view-1">
<view class="view-2">元素</view>
</view>
设置两个样式,灰色背景方便对比,设置一个左边的间距方便看。
page { background: gray; }
.view-1 { background: gold; }
.view-2 { background: red; margin-left: 50rpx;}
接着按照下述步骤修改样式:
- ① view-2设置:margin-top:20rpx。
- ② 注释掉view-2,view-1设置:margin-top: 50rpx。
- ③ 去掉view-2的注释。
每一步的结果如下:
有下述几种方法可以规避父子元素外边距合并问题:
- ① 父元素设置内边距:padding-top:1rpx;
- ② 父元素设置:overflow: hidden;
- ③ 父元素设置边框:border:1rpx solid transparent;
关于外边距合并就说那么多吧,知道怎么规避就好,具体原因涉及到BFC(Block Formatting Context,块级格式化上下文),目前还不知道具体是啥,后面研究了再另外开一片介绍吧。
让元素脱离文档流的办法是:定位,浮动或者多列布局,这里先讲解一波定位。
通过一个例子来帮助理解,先定义一个没有使用定位的页面。
<!-- test.wxml -->
<view class="view-wrapper">
<view class="view-1">元素1</view>
<view class="view-2">元素2</view>
<view class="view-3">元素3</view>
<view class="view-4">元素4</view>
</view>
/* test.wxss */
view {
display: inline-block;
padding: 10px
}
.view-wrapper { background: gold; }
.view-1 { background: greenyellow; }
.view-2 { background: blueviolet; }
.view-3 { background: orange; }
.view-4 { background: pink; }
运行结果如下:
相对于它在「文档流中的位置的起始点」进行移动,通过例子来体验下,这里我们为元素2添加下述样式:
position: relative;
left: 50rpx;
top: 50rpx;
运行结果如下:
可以看到元素2从起始点开始,左边和上面都偏移50rpx,此处有个细节:偏移前的空间依旧存在!另外,另外注意 起始点 这个字眼,元素是基于起始点进行偏移的,比如为外层元素设置一个margin-left: 50rpx; 运行后的效果如下:
完全从文档流中抽离出来,可放到页面的任何位置。把上面设置的margin-left:50rpx删掉,接着把relative; 改为 absolute;运行效果如下:
可以看到,偏移前的空间已被删除!绝对布局是这样的定位的:
「相对于它的父元素来定位」,如果父元素没有设置定位,就找父元素的父元素,依次往上,直至遇到设置了定位的父元素未知,如果没找到,就会相对于文档 body进行定位。所以这里是基于body进行定位的,我们可以试下为外层的view设置position: relative,接着运行看下效果:
购物车那种数字小红点一般就是用绝对定位实现的。另外还可以通过 z-index 属性来控制重叠排列顺序,值大的在上面。改下样式:
/* index.wxss */
.view-1 {
background: greenyellow;
position: absolute;
left: 0rpx;
}
.view-2 {
background: blueviolet;
position: absolute;
left: 108rpx;
top: 20rpx;
}
.view-3 {
background: orange;
position: absolute;
top: 100rpx;
left: 20rpx
}
.view-4 {
background: pink;
position: absolute;
left: 100rpx;
top: 80rpx;
}
运行结果如下:
加入index-z属性,控制重叠排列顺序:
/* index.wxss */
.view-1 {
background: greenyellow;
position: absolute;
left: 0rpx;
z-index: 50;
}
.view-2 {
background: blueviolet;
position: absolute;
left: 108rpx;
top: 20rpx;
z-index: 30;
}
.view-3 {
background: orange;
position: absolute;
top: 100rpx;
left: 20rpx;
z-index: 20;
}
.view-4 {
background: pink;
position: absolute;
left: 100rpx;
top: 80rpx;
z-index: 10;
}
运行结果如下:
fixed:和absolute类似,超出屏幕的时候也是固定,参考的是窗口,常用于需要悬浮固定的场景。比如商品详情页,有个一直固定在底部的购买按钮,页面内容可以正常滚动;还有基于窗口的悬浮框等。
使元素脱离文档流,按照指定方向(左或右)移动,直到外边缘碰到包含框或另一个浮动框的边框为止。浮动前竖向排列,浮动后横向排列;float属性,可选值left左,right右。写个例子体验下,复用上面的wxml,然后设置新的样式:
/* test.wxss */
view > view {
line-height: 100rpx;
width: 140rpx;
text-align: center;
}
.view-1 {
background: greenyellow;
}
.view-2 {
background: blueviolet;
}
.view-3 {
background: orange;
}
.view-4 {
background: pink;
}
运行效果如下:
接着为元素1设置一个向右的浮动 float:right; 运行结果如下:
如图,元素1脱离了文档流(所占空间被删除),然后浮动到右侧了,如果想调整元素1的位置,可以设置margin,比如这里设置margin-right:20rpx;
接着我们如果为元素2也设置一个向右的浮动:
按顺序排到了右侧,之所以没有像元素1一样贴着右边而是在元素1的左侧,因为碰到元素1浮动框了。接着为元素4页设置一个右浮动:
另外有一种情形要注意一下,把样式文件修改为:
/**index.wxss**/
view > view {
line-height: 100rpx;
width: 240rpx;
float: left;
text-align: center;
}
.view-1 {
background: greenyellow;
height: 140rpx;
}
.view-2 {
background: blueviolet;
}
.view-3 {
background: orange;
}
.view-4 {
background: pink;
}
包含框太窄,无法容纳水平排列的三个浮动元素,那么其它浮动块向下移动,直到有足够的空间。如果浮动元素的高度不同,那么当它们向下移动时可能被其它浮动元素“卡住”.
接着说下「清除浮动」,示例代码如下:
<!-- test.wxml -->
<view class="view-wrapper">
<view class="view-1">元素1</view>
<view class="view-2">元素2</view>
</view>
/* test.wxss */
page {
background: gray;
}
.view-wrapper {
width: 75%;
background: gold;
padding: 10rpx;
}
view > view {
width: 240rpx;
text-align: center;
}
.view-1 {
background: greenyellow;
}
.view-2 {
background: blueviolet;
}
.view-3 {
background: orange;
}
.view-4 {
background: pink;
}
运行结果如下:
接着为两个元素分别设置左和右的浮动,运行结果如下:
卧槽,怎么就这样了?浮动带来的影响,可以为通过设置属性overflow: hidden; 来清除浮动。
除此之外还可以添加一个组件,然后设置clear:both实现相同的效果。
<view style="clear:both"/>
还有一种玩法:通过伪元素:after直接添加
.view-2:after {
content: "";
display: block;
clear: both;
}
当然,你也可以直接写死容器元素的高度~
CSS3新增了一个多栏布局,用来实现「文本多列」和「瀑布流」非常方便,就顺带讲下吧~
相关属性如下:
- column-rule-style:列与列间的边框样式;
- column-rule-width:两列的边框厚度;
- column-rule-color:两列的边框颜色;
- column-rule:上述所有属性的简写,示例: column-rule: 1px solid lightblue;
- column-count:创建多列,指定需要分割的列数;
- column-width:列的宽度;
- columns:column-width 和 column-count 的简写。
- column-gap:列与列间的间隙;
- column-span:是否跨多栏显示;
- column-fill:指定如何填充列;
文本多列的代码示例如下:
<!-- test.wxml -->
<view class="view-wrapper">
<view class="view-1">大家好,我是练习时长两年半的个人练习生菜虚鲲,我喜欢唱,跳,rap,篮球,Music!</view>
</view>
/* test.wxss */
.view-1 {
columns:auto 5;
column-rule: 5rpx solid lightblue;
}
运行结果如下:
实现一个简易图片瀑布流示例如下:
//test.js,新增一堆图片URL
Page({
data: {
pics: [
"http://img4.imgtn.bdimg.com/it/u=529905932,1803087578&fm=26&gp=0.jpg",
"http://img5.imgtn.bdimg.com/it/u=823139735,3514716232&fm=26&gp=0.jpg",
"http://img4.imgtn.bdimg.com/it/u=529905932,1803087578&fm=26&gp=0.jpg",
"http://img5.imgtn.bdimg.com/it/u=2958310391,871610286&fm=26&gp=0.jpg",
"http://img5.imgtn.bdimg.com/it/u=2958310391,871610286&fm=26&gp=0.jpg",
"http://img5.imgtn.bdimg.com/it/u=2958310391,871610286&fm=26&gp=0.jpg",
"http://img2.imgtn.bdimg.com/it/u=3924656228,1474918552&fm=26&gp=0.jpg",
"http://img4.imgtn.bdimg.com/it/u=529905932,1803087578&fm=26&gp=0.jpg",
"http://img2.imgtn.bdimg.com/it/u=3924656228,1474918552&fm=26&gp=0.jpg",
"http://img5.imgtn.bdimg.com/it/u=823139735,3514716232&fm=26&gp=0.jpg",
"http://img5.imgtn.bdimg.com/it/u=2958310391,871610286&fm=26&gp=0.jpg",
"http://img5.imgtn.bdimg.com/it/u=2958310391,871610286&fm=26&gp=0.jpg",
"http://img5.imgtn.bdimg.com/it/u=823139735,3514716232&fm=26&gp=0.jpg",
"http://img2.imgtn.bdimg.com/it/u=3924656228,1474918552&fm=26&gp=0.jpg",
"http://img5.imgtn.bdimg.com/it/u=823139735,3514716232&fm=26&gp=0.jpg",
"http://img4.imgtn.bdimg.com/it/u=529905932,1803087578&fm=26&gp=0.jpg",
"http://img2.imgtn.bdimg.com/it/u=3924656228,1474918552&fm=26&gp=0.jpg",
]
},
})
<!-- test.wxml,利用wx:for生成控件 -->
<view class="content">
<block wx:for="{{pics}}">
<image src="{{item}}" mode="widthFix"></image>
</block>
</view>
/* test.wxss */
page {
background: gray;
}
.content {
columns: auto 3;
width: 100%;
column-gap: 5rpx;
}
image {
width: 100%;
display: block;
box-sizing: border-box;
padding: 5rpx;
}
运行结果如下:
瀑布流是实现了,但是左下角的蕾姆酱被切成两半了,如果不想切断,可以为子元素设置「break-inside」属性来防止多列布局,分页媒体和多区域上下文中的意外中断。直接在image的样式里添加:
break-inside: avoid;
运行后结果如下:
学习完前面的内容,我们可以通过display,position,float来布局,但是灵活性较差。2009年,w3c提出了一种新的布局方案:flex弹性布局,可以简便、完整、响应式地实现多种页面布局。任何元素都可以开启弹性布局,采用Flex布局的元素,称为「Flex容器(flex container)」,它里面所有的子元素会自动成为容器成员,称为「Flex 项目(flex item)」。
留意下上面的「主轴」和「侧轴」,其实就是「水平」和「垂直」两个方向。
Flex的属性分为两个部分:「容器属性」和「项目属性」,具体如下图所示:
因为属性较多,限于偏于,也不一一展示具体效果了,Runoob上有对应的效果展示,读者请自行移步至:
https://www.runoob.com/cssref/css3-pr-align-content.html,查看学习:
最后再提下和flex有关的两点:
第一点
设置flex布局后,子元素的float,clear和vertical属性将失效!
第二点:
行内元素也可以使用Flex布局,设置display:inline-flex;即可。
看那么多,总得练下手,随手找个小程序参(chao)考(xi)下吧,这里选择的是每日优鲜,利用上一节学到的姿势反编译一波,拿下图片素材。如果不知道如何反编译微信小程序,可自行查阅上一节:《我写小程序像菜虚鲲——2、鸡你太美》,反编译后的文件如下:
打开images文件夹,可以看到小程序里用到的一些图标:
试下把反编译后的项目导入到微信开发者工具中,设置记得关下域名检验
2333,这已经不算是开卷考试了,而是拿着参考答案来做题了,行吧,开始干活,实现下这个页面~
把标题设置为抠腚优鲜,打开app.json
进行如下配置:
"navigationBarTitleText": "抠腚优鲜",
接着是底部tab选项卡,关于tabBar的详细介绍可自行查阅官方文档:
https://developers.weixin.qq.com/miniprogram/dev/reference/configuration/app.html#tabBar
把反编译后的项目里的images目录直接拷贝到项目中,打开app.json
,添加下述配置:
"tabBar": {
"color": "#969696",
"selectedColor": "#ff4891",
"borderStyle": "white",
"backgroundColor": "#ffffff",
"list": [
{
"pagePath": "pages/index/index",
"text": "首页",
"iconPath": "images/tab-bar-home.png",
"selectedIconPath": "images/tab-bar-home-active.png"
},
{
"pagePath": "pages/index/index",
"text": "赚钱",
"iconPath": "images/tab-bar-group-sign.png",
"selectedIconPath": "images/tab-bar-group-sign-active.png"
},
{
"pagePath": "pages/index/index",
"text": "分类",
"iconPath": "images/tab-bar-category.png",
"selectedIconPath": "images/tab-bar-category-active.png"
},
{
"pagePath": "pages/index/index",
"text": "购物车",
"iconPath": "images/tab-bar-cart.png",
"selectedIconPath": "images/tab-bar-cart-active.png"
},
{
"pagePath": "pages/index/index",
"text": "我的",
"iconPath": "images/tab-bar-mine.png",
"selectedIconPath": "images/tab-bar-mine-active.png"
}
]
},
接着运行看下效果:
写界面之前先划分一下区域,如图,划分成六个:
划分完,接着一个个来实现~
页面结构如下:
<!-- index.wxml -->
<view class="container">
<!-- 顶部栏 -->
<view class="top-wrapper">
<!-- 定位部分 -->
<view class="location_box">
<image class="location_icon" src="{{yx.location_icon_url}}"></image>
<image class="express_icon" src="{{yx.express_icon_url}}"></image>
</view>
<!-- 搜索部分 -->
<view class="search-wrapper">
<image class="search_icon" src="{{yx.search_icon_url}}"></image>
<text class="search_text">搜索</text>
</view>
</view>
</view>
样式调整顺序如下:
- 定位图片宽高44rpx * 44rpx,快速图片宽高120rpx * 30rpx;
- 搜索字体大小28rxp,字体颜色#969696;
- 顶部栏宽度占满100%,高度88rpx,flex布局,space-between两端占满,垂直居中;
- 定位部分左侧偏移16rpx;
- 搜索部分,flex布局,宽高534rpx * 60rpx,圆角12rpx,背景颜色#f5f5f5,
Item水平居中,垂直居中;- 搜索部分右侧偏移16rpx;
- 搜索文字右侧偏移16rpx;
对应样式文件如下:
.top-wrapper {
display: flex;
width: 100%;
height: 88rpx;
align-items: center;
justify-content: space-between;
}
.location_box {
margin-left: 16rpx;
}
.location_icon {
width: 44rpx;
height: 44rpx;
}
.express_icon {
width: 120rpx;
height: 30rpx;
}
.search-wrapper {
display: flex;
width: 534rpx;
height: 60rpx;
border-radius: 12rpx;
background-color: #f5f5f5;
align-items: center;
justify-content: center;
margin-right: 16rpx;
}
.search_icon {
width: 26rpx;
height: 26rpx;
margin-right: 16rpx;
}
.search_text {
font-size: 28rpx;
color: #969696;
}
运行结果如下:
小程序提供了一个滑块视图容器swiper组件,利用它可以实现简单的轮播图。详细官方文档:
https://developers.weixin.qq.com/miniprogram/dev/component/swiper.html
页面结构如下:
<!-- Banner -->
<view class="banner-wrapper">
<!-- 轮播图部分 -->
<swiper class="banner-swiper">
<block wx:for="{{yx.banner_urls}}">
<swiper-item>
<image class="banner_image" src="{{item}}" mode="widthFix"></image>
</swiper-item>
</block>
</swiper>
<!-- 当前页数 -->
<view class="pagination">1/5</view>
</view>
样式调整顺序如下:
对应样式文件如下:
.banner-wrapper {
width: 100%;
position: relative;
}
.banner-swiper {
height: 280rpx;
}
.banner-item {
overflow: hidden;
display: block
}
.banner_image {
width: 100%;
margin-top: -168rpx;
}
.pagination {
position: absolute;
bottom: 15rpx;
right: 20rpx;
background: rgba(0, 0, 0, 0.3);
line-height: 1;
padding: 8rpx 15rpx;
border-radius: 24rpx;
color: #fff;
font-size: 24rpx;
}
运行结果如下:
不过现在只能手动滑切换图片,接着添加定时自动滑动和页数变化,swiper提供下面三个属性:
- autoplay:是否自动切换。
- interval:自动切换的时间间隔。
- duration:滑动动画时长。
添加上述属性到代码中:
<swiper class="banner-swiper" autoplay="true" interval="5000" duration="5000">
编译后可以看到图片已经能自动滚动了,接着绑定下页面切换的事件,当页面改变时切换右下角那个页数的显示,添加下述代码:
<!-- index.js -->
current: 1,
onPageChange: function(e) {
this.setData({
current: e.detail.current + 1
})
},
<!-- index.wxml -->
<swiper ..bindchange="onPageChange">
<view class="pagination">{{current}}/5</view>
运行结果如下:
页面结构如下:
<!-- 新人福利 -->
<view class="welfare">
<view class="welfare-container">
<!-- 顶部图片 -->
<image class="welfare-top-image" src="{{yx.welfare_top_url}}"></image>
<!-- 商品部分 -->
<view class="welfare-goods-container">
<block wx:for="{{yx.welfare_goods}}">
<view class="goods-wrapper">
<image class="goods-image" src="{{item.icon}}"></image>
<image class="goods-price" src="{{item.price}}"></image>
</view>
</block>
</view>
<!-- 底部图片 -->
<image class="welfare-bottom-image" src="{{yx.welfare_bottom_url}}"></image>
</view>
</view>
先把商品部分的标签注释掉,样式调整顺序如下:
- 最外层设置flex布局,主轴从上往下,item居中,背景白色,上下内间距24rpx;
- 外层设置flex布局,主轴从上往下,item居中,宽690rpx,高434rpx,圆角12rpx,背景颜色#d4545a;
- 顶部图片100%,高度110rpx,左上和右上圆角12rpx;
- 商品部分最外层设置flex布局,主轴从上往下,item居中;
- 商品部分外层宽度660rpx,高度212rpx,圆角12rpx,上下内间距12rpx,左右内间距20rpx;
- 底部图片宽660rpx,高96rpx,圆角12rpx;
对应样式文件如下:
.welfare {
display: flex;
flex-direction: column;
align-items: center;
background: #fff;
padding: 24rpx 0;
}
.welfare-container {
display: flex;
flex-direction:column;
align-items:center;
width: 690rpx;
height: 434rpx;
border-radius: 12rpx;
background: #d4545a;
}
.welfare-top-image {
width: 100%;
height: 110rpx;
border-radius: 12rpx 12rpx 0 0;
}
.welfare-goods {
display: flex;
flex-direction: column;
align-items: center;
}
.welfare-goods-container {
width: 660rpx;
height: 212rpx;
box-sizing: border-box;
border-radius: 12rpx;
background: #fff;
padding: 12rpx 20rpx;
}
.welfare-bottom-image{
width: 660rpx;
height: 96rpx;
border-radius: 12rpx;
}
运行结果如下:
接着去掉商品部分的标签注释,调整样式:
- 商品外层设置flex布局,主轴从上往下,item居中,宽度134rpx,高度100%;
- 商品图片宽高130rpx;
- 商品价格宽100%,高56rpx;
.goods-wrapper {
display: flex;
flex-direction: column;
align-items: center;
width: 134rpx;
height: 100%;
}
.goods-image {
width: 130rpx;
height: 130rpx;
}
.goods-price {
width: 100%;
height: 56rpx;
}
em...商品直接穿出来了,修改下商品外层布局flex布局,从左网友,两端占满:
.welfare-goods-container {
width: 660rpx;
height: 212rpx;
box-sizing: border-box;
border-radius: 12rpx;
background: #fff;
padding: 12rpx 20rpx;
display: flex;
flex-direction: row;
justify-content: space-between;
}
运行结果如下:
页面结构如下:
<!-- 信息标签 -->
<view class="info-tag-container">
<block wx:for="{{yx.tag_info_list}}">
<view class="tag-wrapper">
<image class="tag-image" src="{{item.icon}}"></image>
<view class="tag-text">{{item.text}}</view>
</view>
</block>
</view>
样式调整顺序如下:
- 最外层高度48rpx,flex布局,两端对齐留白;
- 外层flex布局,内容居中;
- 标签图片宽高24rpx,右侧偏离8rpx;
- 标签字体颜色#ff4891,大小22rpx;
对应样式文件如下:
.info-tag-container {
height: 48rpx;
display: flex;
justify-content: space-around;
}
.tag-wrapper {
align-items: center;
display: flex;
}
.tag-image {
width: 24rpx;
height: 24rpx;
margin-right: 8rpx;
}
.tag-text {
font-size: 22rpx;
color: #ff4891;
}
运行结果如下:
这里的商品分类不止10个,滑动到右侧还有3个,可以用官方提供的scroll-view组件来实现,详细官方文档:
https://developers.weixin.qq.com/miniprogram/dev/component/scroll-view.html
scroll-view的用法也很简单:scroll-x横向滚动,scroll-y纵向滚动,说个小bug~
scroll-view本身的display:flex不生效,外层元素需要设置属性white-space: nowrap,内层元素需要设置属性display: inline-block,如果内层元素需要用到flex布局,可以设置属性display: inline-flex; 还有内层元素不可以用float浮动。
接着滑动部分的,一个简单的套路是:宽度写死 = 每个商品View的宽度 * 7,不过这种方法有点low。看了下每日优鲜的玩法,是把这里拆分成了两个部分,这里照葫芦画瓢实现一波。
页面结构如下:
<!-- 商品类别 -->
<view class="good_category_container">
<scroll-view scroll-x class="scroll-view">
<view class="category_first">
<block wx:for="{{yx.category_list_first}}" wx:key="key">
<view class="good_category">
<image class="category-image" src="{{item.icon}}"></image>
<view class="category-text">{{item.text}}</view>
</view>
</block>
</view>
<view class="category_second">
<block wx:for="{{yx.category_list_second}}" wx:key="key">
<view class="good_category">
<image class="category-image" src="{{item.icon}}"></image>
<view class="category-text">{{item.text}}</view>
</view>
</block>
</view>
</scroll-view>
</view>
样式调整顺序如下:
- 最外层宽度100%,设置white-space: nowrap;
- scroll-view设置最大高度360rpx;
- 左侧部分,宽度100%,inline-flex,自动换行;
- 右侧部分,高度384rpx,inline-flex,主轴从上往下;
- 分类外层,flex布局,水平竖直居中,主轴从上往下,宽150rpx,顶部偏移24rpx;
- 分类图标,宽高104rpx;
- 分类文本,高34rpx,行高34rpx让文本垂直居中,字体颜色#474245,大小24rpx,顶部偏移10rpx;
对应样式文件如下:
.good_category_container {
width: 100%;
white-space: nowrap;
}
.scroll-view {
max-height: 360rpx;
}
.category_first {
width: 100%;
display: inline-flex;
flex-wrap: wrap;
}
.category_second {
height: 384rpx;
display: inline-flex;
flex-direction: column;
flex-wrap: wrap;
}
.good_category {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
width: 150rpx;
margin-top: 24rpx;
}
.category-image {
width: 104rpx;
height: 104rpx;
}
.category-text {
font-size: 24rpx;
color: #474245;
height: 34rpx;
line-height: 34rpx;
margin-top: 10rpx;
}
运行结果如下:
这种悬浮在页面上,不会因为页面滚动而滚动的部分,可以使用固定定位来实现。
页面结构如下:
<!-- 浮动提醒 -->
<view class="tip-container">
<image class="tip-image" src="{{yx.tip_image_url}}"></image>
</view>
样式调整顺序如下:
- 外层容器设置绝对定位,宽98rpx,高130rpx,离右边28rpx,离底部40rpx;
- 图片设置宽高100%;
对应样式文件如下:
.tip-container {
position: fixed;
right: 28rpx;
bottom: 40rpx;
width: 98rpx;
height: 130rpx;
}
.tip-image{
width: 100%;
height: 100%;
}
运行结果如下:
Tips:真机预览时发现分类那里滑动时有滚动条,可以在wxss加入下述样式隐藏滚动条~
::-webkit-scrollbar {
width: 0;
height: 0;
color: transparent;
}
相信读者学完本节,基本可以应付日常小程序页面的堆砌了。这种实操性比较强的东西,切忌死记,建议自己找些小程序仿写下,熟能生巧,别说没有设计稿,没有图片没有尺寸,上节学的反编译技能呢???
笔者不是专业前端,以上内容都是现学现卖,如有纰漏或建议,欢迎评论区指出,谢谢~
源码整理下再丢Gayhub,后面再发个地址哈~(另外,蹲个深圳3年半的Android坑)
参考文献: