Vuetify有一套基于CSS FLEX-BOX的栅格系统。

Vuetify的栅格也是12栅格系统,其中的主要标签是:

  1. v-container,类似于各种前端框架的container,是一个把内容集中于屏幕中央的容器,可以加上fluid属性扩展至全屏。
  2. v-layout,用于区分不同的大区域,是v-flex元素的容器,大概近似于其他样式库的row。
  3. v-flex,就是响应式格子,这个标签会自动设置其子元素为flex: 1 1 auto

上边是官方文档的原文。具体还是要来看一看是怎么实现这些排布的。本文的目录如下:

  1. Grid系统
  2. 基础布局元素分析 v-app
  3. 基础布局元素分析 v-container
  4. 基础布局元素分析 v-layout
  5. v-layout API
  6. v-flex API
  7. v-spacer

Grid系统

基础布局元素分析 v-app

最直观的办法就是用这三个元素创建一个简单的页面,来看看浏览器里实际渲染的页面和样式。

<!DOCTYPE html>
<html lang="zhHans">
<head>
    <link href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900|Material+Icons" rel="stylesheet">
    <link href="https://cdn.jsdelivr.net/npm/vuetify/dist/vuetify.min.css" rel="stylesheet">
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no, minimal-ui">
</head>
<body>
<div id="app">
    <v-app>
        <v-container>
            <v-layout>
                <v-flex>
                    <div>ITEM</div>
                </v-flex>
            </v-layout>
        </v-container>
    </v-app>
</div>

<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vuetify/dist/vuetify.js"></script>
<script>
    new Vue({el: '#app'})
</script>
</body>
</html>

首先要知道的是:

  1. Vuetify作为Vue的插件,要在Vue内部才生效。所以外部需要#app挂载Vue,这和正常使用Vue是一样的。
  2. 所有的Vuetify内容,都要被包裹在v-app标签内才能正常发挥作用

然后来看一下浏览器中实际页面元素:

<div id="app">
    v-app生成的标签
    <div data-app="true" class="application theme--light" id="app">
        <div class="application--wrap">
            v-container生成的标签
            <div class="container">
                v-laygout生成的标签
                <div class="layout">
                    <div class="flex">
                        <div>ITEM1</div>
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>

查看了一下样式,最外层的<div id="app">是Vue的挂载点,被设置成了所有padding和margin都是0的一个block。

之后的两层嵌套标签是v-app生成的:来看一看其中奥妙:

  1. <div data-app="true" ...>标签的样式是display:flex,而且没有任何其他的FLEX相关属性,很显然,这个是作为最外层的FLEX容器。默认是就是row
    和 nowrap。
  2. <div class="application--wrap">也具有display:flex属性,所以既是一个FLEX
    ITEM(FLEX项目)也是一个FLEX容器,所以这是第二个嵌套FLEX容器。这其上还有其他相关的FLEX属性是:

    1. flex-basis: auto,说明宽度根据其中的项目来确定。
    2. flex-direction: column,注意,这里其内部包裹的FLEX项目排布变成了竖直方向。
    3. flex-grow: 1,说明允许放大。
    4. flex-shrink: 1,说明允许缩小。

通过分析这两个元素可以看到,v-app这个元素直接将其中的所有内容包含在了一个两层嵌套,竖直排布的FLEX项目容器中。也就是说其中的所有内容,都是竖直排列的,显然是为了从上到下一块一块的排布内容。

可见这也是为什么Vuetify要求很多元素都要放在v-app标签内部才生效,这是因为提供了页面的基础布局,在后台可能还有更多的东西依赖于这个元素。

基础布局元素分析 v-container

v-container元素生成的页面元素是:<div class="container">,也来看看其上的属性:

  1. display: block,说明不是FLEX容器
  2. flex-basis: 100%,可见这个元素强行撑开全部的页面
  3. flex-grow: 1,这个加上flex-basis: 100%,让这个元素独占一行
  4. flex-shrink: 1,可缩小

通过这个元素可以发现,这个元素确实是起到分割的作用,每多一个这个元素,就相当于在FLEX容器里增加一个新区域。在行里就可以继续排布了。这个元素还有一个fluid属性用于控制内容集中在视口中心还是平铺到整个宽度,经过看样式变化,加上fluid其实就是取消了原本媒体查询在960px屏幕上最大宽度为900px和1264px屏幕上最大宽度1185px的样式。

基础布局元素分析 v-layout

v-layout元素生成的页面元素是:<div class="layout">,也来看看其上的属性:

  1. display: flex,是FLEX容器
  2. flex-basis: auto,由于上一层是100%宽,这一行也是100%宽
  3. flex-grow: 1,这个加上flex-basis: 100%,让这个元素独占一行
  4. flex-shrink: 1,可缩小
  5. flex-wrap: nowrap,不允许换行,一行内排布

通过看其上的属性,可以发现这个元素在v-container分割出的区域内,划出单独不允许换行的一行来排布元素。

基础布局元素分析 v-flex

最后是v-flex元素,渲染的标签是<div class="flex">,其属性是:

  1. display: block,不是FLEX容器
  2. flex-basis: auto,根据内容排布
  3. flex-grow: 1,这个加上flex-basis: 100%,让这个元素独占一行
  4. flex-shrink: 1,可缩小

说明每一个v-flexv-container这一行内的元素。

看完了这一层层元素,就比较清楚了,Vuetify先是强行使用v-app排了一个竖向的布局,在其中用v-layout分割出一个不换行的行,每一行里可以塞一个v-flex元素,每个实际要布局的代码,就放在一行里的v-flex元素中。

所以就可以把v-flex元素认为是一个允许缩放的格子,在其中排布内容就行了。v-container,由于不是FLEX容器,一般就无需控制了,而v-app由Vuetify自动控制,我们也不用管。

分析到最后的结论就是,需要控制的是v-layoutv-flex的属性,就需要看一看Vuetify提供的这两个元素的属性(PROPS)了。

v-layout

v-layout作为Flex容器,其设置主要就是Vuetify提供的设置flex相关属性的API。

在官网的Grid API可以查看相关的设置,除了tagid属性之外,都是用于控制FLEX容器的属性,而且属性设置之后,就会被渲染为标签上的同名样式类,也方便使用Vue来控制。

v-layout API一览
标准W3C样式和属性 v-layout PROPS
flex-direction 排布方向 column
row
reverse
flex-wrap 是否换行 wrap,默认是nowrap
justify-content 主轴对齐 justify-end
justify-center
justify-space-around
justify-space-between
justify-start
align-items 交叉轴对齐 align-baseline
align-center
align-end
align-start
fill-height,这个对应的是align-items:stretch
align-content 交叉轴多行对齐 align-content-center
align-content-end
align-content-space-around
align-content-space-between
align-content-start
好像没有在这种情况下对应stretch的内容。不过试验了一下,对排版没有任何影响。
tag 实际渲染标签 用来控制将这个标签实际渲染成什么元素,比如tag="p"就会渲染成P标签。
display: flex FLEX容器类型 d-{type},比如d-inline-flex就对应display: inline-flex,默认就是d-flex。
id 标准DOM属性 id属性,会被原样渲染到实际的标签中。

上边的所有除了写默认值的以外,其他的默认值都是false,即不设置就相当于是false,会让样式采用CSS FLEX标准默认的样式,比如不设置column则默认就是row

v-flex

既然相当于一个格子,参考其他UI库的经验,肯定会有的就是控制在不同屏幕断点下的宽度的属性了。然后由于是FLEX项目,肯定还会有自身的几个对应标准FLEX属性的属性。此外还有偏移量。

先列出全部API然后分开来看:

v-flex API一览
API 解释
(size)(1-12) 断点紧跟1-12大小,表示不同屏幕宽度下的格子宽度,断点有五个:xs|sm|md|lg|xl,实际写法比如xs12 md6
align-self-baseline 对应 align-self FLEX标准属性
align-self-end
align-self-start
align-self-center
grow 是否占据剩余空间,设置上该属性相当于flex-grow:1。
shrink 是否缩小以适合空间,设置上该属性相当于flex-shrink: 1。
order-(size)(1-12) 在不同大小屏幕之下对应的顺序,对应标准的order属性。
offset-(size)(0-12) 在不同大小屏幕之下的偏移量,使用方法和其他UI库很像。写法是offset-xs1,注意这个也是从小到大覆盖的,单独使用offset-xs1表示所有情况下都缩进一行1/12的距离。
tag 实际渲染标签 用来控制将这个标签实际渲染成什么元素,比如tag="p"就会渲染成P标签。
id 标准DOM属性 id属性,会被原样渲染到实际的标签中。

v-flex上除了标准FLEX属性,和有时候能用到的偏移之外,最重要的属性就是断点。有了断点配合对应的宽度,才能够实现一些特殊的排版。由于Vuetify里的断点设计成可以通过JS代码方便的控制,因此也是构成Grid系统的一个关键部分,需要单独来看。

v-spacer

v-spacer是一个空白的div元素,可以用来进行分离挨的近的元素。一般用在FLEX排版的内容当中。典型的应用就是一个标题栏。

到现在就可以进行简单的排版了,但是如果要通过断点改变FLEX的属性,还需要针对断点编写媒体查询的CSS代码。既然使用了前端UI库,当然不想再写额外的CSS代码了,Vuetify提供了使用JS代码监听断点进而改变属性的功能。在下篇中来看一下断点,就可以非常灵活的进行排版了。