开发一个UI框架项目[3]-Layout
本文最后更新于:2020年9月12日 晚上
设计细节
row
组件默认采用flex
布局,可通过left
、center
、right
来设置对齐方式;row
组件可通过设置gutter
参数来设置列之间的间隔;col
组件可通过设置span
参数来设置不同列数,默认将宽度分为24列,同时可搭配offset
参数来设置分栏偏移数;- 响应式布局传递的参数不采用
element-ui
那些xs
、sm
参数,字面上不利于理解,
所以这里采用了phone
、iPad
、narrowPC
和widePC
等参数来分别表示在屏幕大小为
手机、平板、窄屏PC端和宽屏PC端下的展示。
功能处理细节
span
设置分栏数。默认将页面宽度分成了24等分,再通过span/24
来算出分栏的占比,那要怎么设置各占比分栏宽度呢?如果直接通过yv-col-1 ~ 24
这样写24个类名,就会出现一堆重复的代码,维护、改动也麻烦。幸好可以通过css预处理器来处理这种情况,预处理器可以像JS那样写变量,函数,可以为我们提供很多方便的操作,这里采用了scss
来处理:1
2
3
4
5
6@for $n from 1 through 24 {
$class-prefix: yv-col-;
&.#{$class-prefix}#{$n} {
width: ($n / 24) * 100%
}
}先设置通用前缀
yv-col-
,再通过for循环从1到24,算出每一份的宽度,这样就可以根据span
的值得到对应的类名yv-col-n
从而得到对应的宽度。包括offset
设置偏移栏数也是如此:1
2
3
4
5
6@for $n from 1 through 24 {
$class-prefix:yv-col-offset-;
&.#{$class-prefix}#{$n} {
margin-left: ($n / 24) * 100%
}
}gutter
传参问题。设置分栏间隔是通过在row
组件上面传递gutter
参数,但实际上我们还得靠处理col
组件来实现。一开始直接像下面这样直接把gutter
传个每个col
组件:1
2
3
4<yv-row :gutter="10">
<yv-col :gutter="10"></yv-col>
<yv-col :gutter="10"></yv-col>
</yv-row>看起来很不友好。这里可以使用父子组件通信的另一种方法:
$parent
和$children
。如下:1
2
3
4
5
6
7
8
9
10
11
12
13<!-- Row.vue -->
mounted() {
this.$children.forEach(child => {
child.gutter = this.gutter
})
}
<!-- Col.vue -->
data() {
return {
gutter: 0
}
}在
row
的生命周期mounted
中通过$children
给每个子组件的gutter
属性赋值,同时col
组件也要在data
里面定义gutter
属性。gutter
具体设置问题。一开始的想法是直接给每一列的左右加上gutter/2
的外边距,但是这会跟通过offset
设置的偏移分栏外边距产生冲突。那么换成内边距如何呢?试下内边距的效果。
从图片可以发现最左边跟最右边的分栏没有紧挨父级容器,这是设置了内边距的原因,跟父容器的空隙就是gutter/2
px。解决方案是给父级容器加上-gutter/2
的左右外边距,就ok了。响应式处理。这里采用了
phone
、iPad
、narrowPC
、widePC
这种直观的字段来表示不同屏幕宽度。通过createClasses
方法来创建不同的类名:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34computed: {
colClass() {
let {
span,
offset,
phone,
iPad,
narrowPC,
widePC
} = this
return [
'yv-col',
...this.createClasses(phone, 'phone-'),
...this.createClasses(iPad, 'iPad-'),
...this.createClasses(narrowPC, 'narrowPC-'),
...this.createClasses(widePC, 'widePC-'),
...this.createClasses({ span, offset })
]
}
},
methods: {
createClasses(obj, str = '') {
if (!obj) return []
let arr = []
if (obj.span) {
arr.push(`yv-col-${str}${obj.span}`)
}
if (obj.offset) {
arr.push(`yv-col-${str}offset-${obj.offset}`)
}
return arr
}
}设置一个计算属性
colClass
,根据传入不同的尺寸属性生成不同的class添加到col上面,再通过媒体查询的写法,来实现不同尺寸下的宽度计算:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26@media (min-width: 0px) {
@for $n from 1 through 24 {
$class-prefix:yv-col-phone-;
&.#{$class-prefix}#{$n} {
width: ($n / 24) * 100%
}
}
@for $n from 1 through 24 {
$class-prefix:yv-col-phone-offset-;
&.#{$class-prefix}#{$n} {
margin-left: ($n / 24) * 100%
}
}
}
@media (min-width: 577px) {
// ...
}
@media (min-width: 769px) {
// ...
}
@media (min-width: 993px) {
// ...
}
@media (min-width: 1201px) {
// ...
}
人工测试
手动测试。。。已完成。
自动化测试
在test文件夹下增加row.test.js
和col.test.js
文件。
row.test.js
文件有3个测试用例:测试row是否存在、接收getter、接收align;
col.test.js
文件有7个测试用例:测试col是否存在、接收span、接收offset、接收phone、接收iPad、接收narrowPC、接收widePC。
运行命令parcel watch test/* --no-cache
和karma start
查看测试结果:
vuepress
在docs/.vuepress/components文件夹下增加多个layout-*
的vue文件,内容就是我们要展示的layout
示例,然后在docs/components文件夹下增加layout
的md文件,内容就是放置整个layout
组件说明。
具体内容请访问这里。
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!