CSS网格布局完整指南

简介

CSS Grid布局 (又名"网格"),是一个基于二维网格布局的系统,旨在改变我们基于网格设计的用户界面方式。正如我们所知,CSS 总是用于布局我们的网页,但它并没有做的很好。刚开始的时候我们使用表格(table),然后使用浮动(float)、 定位(position)和内联块(inline-block),但所有这些方法本质上来讲都是hacks,并留下了很多需要实现的重要功能问题(例如垂直居中),虽然Flexbox可以起到一定的补救作用,但是旨在用于更简单的一维布局,并不适用于复杂的二维布局(实际上 Flexbox 和 Grid 可以一起结合使用起到最佳效果)。网格(Grid)是第一个专门为解决布局问题而创建的CSS模块,用来解决我们之前在制作网站时使用hacks处理布局问题。
这里有两件事情启发我创建本指南。第一个是 Rachel Andrew 的令人敬畏的书--为 CSS Grid 布局做好准备。这本书很详尽明确的的介绍了Grid,是整篇文章的基础。我强烈鼓励你买它,读它。另外一个很大的灵感来自于 Chris Coyier 的-- Flexbox完整指南,这本书是我了解Flebox的一个很优秀的资源。它帮助了很多人,这是事实,这里,我还想补充一句,当你使用谷歌搜索"flexbox"时,会出现很多类似的资源,但是为什么不直接利用最好的资源呢?
我书写此指南的目的是基于目前最新规范的版本,规范其网格概念。所以我不会再次提及过时的 IE 语法,并且随着规范的成熟,我会尽我们所能定期更新此指南。

基础知识与浏览器支持

Grid 的入门是很容易的。你只需要定义一个容器元素并设置display:grid,使用grid-template-columnsgrid-template-rows属性设置网格的列与行的大小,然后使用grid-columngrid-row属性将其子元素放入网格之中。与flexbox类似,网格项的源顺序并不重要。你的CSS可以按任何顺序放置,这使得你很容易重新布局网格与媒体查询。想象一下你定义的整个页面布局,然后如果想要完全重新布局以适应不同的屏幕宽度,这时仅仅使用几行 CSS 代码就可以实现。Grid是有史以来最强大 CSS 模块之一。
关于 Grid 一件很重要的事情就是它现在还不适用于项目使用。目前还处于 W3C 的工作草案之中,并且默认情况下,还不被所有的浏览器正确支持。Internet Explorer 10 和 11 已经可以实现支持,但也是利用一种过时的语法实现的。现在出于示例演示,我建议你使用启用了特殊标志的 Chrome, Opera 或者 Firefox 。在 Chrome,导航到chrome://flags并启用" web 实验平台功能"。该方法同样适用于 Opera (opera://flags)。在Firefox中,启用 layout.css.grid.enabled标志。
这里有一张浏览器支持情况的表格(之后我会继续更新):

CSS Grid Layout

除了Microsoft,浏览器厂商似乎想要等到Grid规范完全成熟后再加以推广。这是一件好事,因为这意味着我们就不需要担心学习多个语法。
这只是时间问题,你可以在生产环境中使用Grid。但是现在你需要开始学习它了。

重要术语

在深入研究网格的概念之前,我们需要理解其相关术语概念。 因为这里所涉及的术语在概念上都有点类似,如果你不首先记住Grid规范定义,你就会很容易将其与其他概念相混淆。 但是不需要担心,这里的属性并没有很多。

网格容器(Grid Container)

当一个元素的属性设置为display:grid时, 它是所有网格项(Grid Items)的直接父元素。 在下面示例中container就是网格容器。
HTML:

<div class="container">
  <div class="item item-1"></div>
  <div class="item item-2"></div>
  <div class="item item-3"></div>
</div>
网格项(Grid Item)

网格容器的子节点(例如直接后代)。这里 item元素都是网格项,但是sub-item不包含其中。
HTML:

<div class="container">
  <div class="item"></div> 
  <div class="item">
    <p class="sub-item"></p>
  </div>
  <div class="item"></div>
</div>
网格线(Gird Line)

分界线构成了网格的结构。它们可以是垂直的("列网格线")也可以是水平的("行网格线"),并且位于一行或一列的任一侧。下面图片中的黄线就是列网格线的示例。


列网格线
网格轨道(Grid Track)

两个相邻网格线之间的空间。你可以把它们想象成网格的列或行。下图所示的是第二行和第三行网格线之间的网格轨道。

网格轨道
网格单元格(Grid Cell)

两个相邻的行和两个相邻的列之间的网格线空间。它是网格的一个"单位"。下面图片所示的是行网格线line 1
line 2与列网格线line 2line 3之间的网格单元格。

网格轨道

网格区域(Grid Area)

网格区域为四条网格线所包围的总空间。 网格区域可以由任何数量的网格单元组成。下面图片所示的是行网格线line 1line3和列网格线line 1line 3之间的网格区域。

网格区域

网格属性目录(Grid Properties Table of Contents)

网格容器属性 网格项目属性
display grid-column-start
grid-template-columns grid-column-end
grid-template-rows grid-row-start
grid-template-areas grid-row-end
grid-column-gap grid-column
grid-row-gap grid-row
grid-gap grid-area
justify-items justify-self
align-items align-self
justify-content
align-content
grid-auto-columns
grid-auto-rows
grid-auto-flow
grid

网格容器的属性(Properties for the Grid Container)

display

将元素定义为网格容器,并为其内容建立新的网格格式上下文。
属性值:
grid : 声明一个块级的网格
inline-grid : 声明一个内联级的网格
subgrid:如果你的网格容器本身是一个网格项(即嵌套网格),你可以使用此属性来表示你希望其行/列的大小从其父项继承,而不是自定义属性。

.container{
   display: grid | inline-grid | subgrid;
}

column, float, clear, 和 vertical-align 元素对网格容器不起作用。

grid-template-columns 和 grid-template-rows

使用以空格分隔的值定义网格的列和行。 这些值的大小表示轨道大小,它们之间的空间表示网格线。
属性值:
<track-size> :可以是一个长度、百分比或者是网格中自由空间的一小部分(使用fr单位)
<line-name> :你选择的任意名称

.container{
    grid-template-columns: <track-size> ... | <line-name> <track-size> ...;
    grid-template-rows: <track-size> ... | <line-name> <track-size> ...;
}

示例:
当你在轨道值之间留有空格时,网络线就会自动分配数值名称:

.container{
    grid-template-columns: 40px 50px auto 50px 40px;
    grid-template-rows: 25% 100px auto;
}
grid-numbers

但是你也可以显示命名,请参考括号语法中的行名称命名方式:

.container{
    grid-template-columns: [first] 40px [line2] 50px [line3] auto [col4-start] 50px [five] 40px [end];
    grid-template-rows: [row1-start] 25% [row1-end] 100px [third-line] auto [last-line];
}

grid-names

请注意,一条网格线可以具有有多个名称。例如,这里的第二行将有两个名字: row1-endrow2-start:

.container{
  grid-template-rows: [row1-start] 25% [row1-end row2-start] 25% [row2-end];
}

如果你的定义中包含重复的部分,你可以使用 repeat()标识进行精简:

.container{
  grid-template-columns: repeat(3, 20px [col-start]) 5%;
}

等同于:

.container{
  grid-template-columns: 20px [col-start] 20px [col-start] 20px [col-start] 5%;
}

fr单位允许你将轨道的大小设置为网格容器的可用空间的一小部分。 例如,如下所示把每个项目设置为网格容器宽度的三分之一:

.container{
  grid-template-columns: 1fr 1fr 1fr;
}

这里可用空间表示除去非弹性项后剩余的空间。在此示例中的fr单位的可用空间表示减去50px以后的空间大小:

.container{
  grid-template-columns: 1fr 50px 1fr 1fr;
}
grid-template-areas

通过使用grid-area属性来定义网格区域名称,从而定义网格模板。网格区域重复的名称就会导致内容跨越这些单元格。句点表示一个空单元格。语法本身提供了一种可视化的网格结构。
属性值:
<grid-area-name> -:使用grid-area属性定义网格区域名称
. :句点表示一个空的单元格
none - 表示无网格区域被定义

.container{
  grid-template-areas: "<grid-area-name> | . | none | ..."
                       "..."
}

示例:

.item-a{
  grid-area: header;
}
.item-b{
  grid-area: main;
}
.item-c{
  grid-area: sidebar;
}
.item-d{
  grid-area: footer;
}
.container{
  grid-template-columns: 50px 50px 50px 50px;
  grid-template-rows: auto;
  grid-template-areas: "header header header header"
                       "main main . sidebar"
                       "footer footer footer footer"
}

这将创建一个四列三行的网格。最上面的一行为header区域。中间一行由两个main区域,一个空单元格和一个sidebar区域。最后一行是footer区域。

grid-template-areas

你所声明的每一行都需要具有相同数目的单元格。
你可以使用任意数量的句点(.)声明单个空单元格。只要句点之间没有空格它们就表示一个空单元格。
注意,你只是使用此语法进行网格区域命名,而不是网格线命名。当你使用此语法时,区域两边的线就会得到自动命名。如果网格区域名称为foo,则其行线和列线的名称就将为foo-start,最后一行线及其最后一列线的名字就会为foo-end。这意味着一些线就可能具有多个名称,如上面示例中所示,拥有三个名称:header-start,main-start, 以及footer-start

grid-column-gap 和 grid-row-gap

指定网格线的大小。你可以把它想像成在行/列之间设置间距宽度。
属性值:
<line-size> : 一个长度值

.container{
  grid-column-gap: <line-size>;
  grid-row-gap: <line-size>;
}

示例:

.container{
  grid-template-columns: 100px 50px 100px;
  grid-template-rows: 80px auto 80px;   
  grid-column-gap: 10px;
  grid-row-gap: 15px;
}
grid-column-row-gap

间距仅仅在列/行之间产生,而不会在边缘区。

grid-gap

grid-column-gapgrid-row-gap的简写值。
属性值:
<grid-column-gap> 和<grid-row-gap> : 长度值

.container{
  grid-gap: <grid-column-gap> <grid-row-gap>;
}

示例:

.container{
  grid-template-columns: 100px 50px 100px;
  grid-template-rows: 80px auto 80px;   
  grid-gap: 10px 15px;
}

如果没有指定grid-row-gap属性的值,默认与grid-column-gap属性值相同

justify-items

沿着列轴对齐网格项中的内容(相反于align-items属性定义的沿行轴对齐)。此值适用于容器内所有的网格项。
属性值:
start : 内容在网格区域中左端对齐
end :内容在网格区域中右端对齐
center :内容在网格区域居中对齐
stretch :内容宽度占满整个网格区域(默认值)

.container{
  justify-items: start | end | center | stretch;
}

示例:

.container{
  justify-items: start;
}
grid-justify-items-start
.container{
  justify-items: end;
}
grid-justify-items-end
.container{
  justify-items: center;
}
grid-justify-items-center
.container{
  justify-items: stretch;
}

grid-justify-items-stretch

以上特性也可以使用justify-self属性对各个网格项进行设置。

align-items

沿行轴对齐网格项中的内容(相反于justify-items属性定义的沿列轴对齐)。此值适用于容器内所有的网格项。
属性值:
start : 内容在网格区域中顶端对齐
end :内容在网格区域中底部对齐
center :内容在网格区域居中对齐
stretch :内容宽度占满整个网格区域(默认值)

.container{
  align-items: start | end | center | stretch;
}

示例:

.container{
  align-items: start;
}
grid-align-items-start
.container{
  align-items: end;
}
grid-align-items-end
.container{
  align-items: center;
}
grid-align-items-center
.container{
  align-items: stretch;
}

grid-align-items-stretch

以上特性也可以使用align-self属性对各个网格项进行设置。

justify-content

如果你的网格项目都是使用像px这样的非响应式单位来计算的,就有可能出现一种情况--网格的总大小可能小于其网格容器的大小。 在这种情况下,您可以设置网格容器内的网格的对齐方式。 此属性沿着列轴对齐网格(相反于align-content属性定义的沿行轴对齐)。
属性值:
start -网格在网格容器中左端对齐
end - 网格在网格容器中右端对齐
center - 网格在网格容器中居中对齐
stretch - 调整网格项的大小,使其宽度填充整个网格容器
space-around -在网格项之间设置偶数个空格间隙,其最边缘间隙大小为中间空格间隙大小的一半
space-between - 在网格项之间设置偶数个空格间隙,其最边缘没有间隙
space-evenly - 在网格项之间设置偶数个空格间隙,其最边缘间隙与其相同

.container{
  justify-content: start | end | center | stretch | space-around | space-between | space-evenly;    
}
.container{
  justify-content: start;   
}
grid-justify-content-start
.container{
  justify-content: end; 
}

![Uploading grid-justify-content-center]
](http://upload-images.jianshu.io/upload_images/1673685-51053776bcc7111a.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

.container{
  justify-content: center;  
}
grid-justify-content-center
.container{
  justify-content: stretch; 
}
grid-justify-content-stretch
.container{
  justify-content: space-around;    
}
grid-justify-content-space-around
.container{
  justify-content: space-between;   
}
grid-justify-content-space-between
.container{
  justify-content: space-evenly;    
}
grid-justify-content-space-evenly
align-content

如果你的网格项目都是使用像px这样的非响应式单位来计算的,就有可能出现一种情况--网格的总大小可能小于其网格容器的大小。 在这种情况下,您可以设置网格容器内的网格的对齐方式。 此属性沿着行轴对齐网格(相反于justify-content属性定义的沿列轴对齐)。
属性值:
start -网格在网格容器中顶端对齐
end - 网格在网格容器中底端对齐
center - 网格在网格容器中居中对齐
stretch - 调整网格项的大小,使其宽度填充整个网格容器
space-around -在网格项之间设置偶数个空格间隙,其最边缘间隙大小为中间空格间隙大小的一半
space-between - 在网格项之间设置偶数个空格间隙,其最边缘没有间隙
space-evenly - 在网格项之间设置偶数个空格间隙,其最边缘间隙与其相同

.container{
  align-content: start | end | center | stretch | space-around | space-between | space-evenly;  
}

示例:

.container{
  align-content: start; 
}
grid-align-content-start
.container{
  align-content: end;   
}
grid-align-content-end
.container{
  align-content: center;    
}
grid-align-content-center
.container{
  align-content: stretch;   
}
grid-align-content-stretch
.container{
  align-content: space-around;  
}
grid-align-content-space-around
.container{
  align-content: space-between; 
}
grid-align-content-space-between
.container{
  align-content: space-evenly;  
}
grid-align-content-space-evenly
grid-auto-columns和 grid-auto-rows

指定任何自动生成的网格轨道(也称为隐式网格轨道)的大小。 当显式定位超出定义网格范围的行或列(通过grid-template-rows / grid-template-columns)时,将创建隐式网格轨道。
属性值:
<track-size> :可以是一个长度、百分比或者是网格中自由空间的一小部分(使用fr单位)

.container{
  grid-auto-columns: <track-size> ...;
  grid-auto-rows: <track-size> ...;
}

为了说明隐式网格轨道是如何创建的,请思考一下:

.container{
  grid-template-columns: 60px 60px;
  grid-template-rows: 90px 90px
}

grid-auto

这里创建了2x2的网格。
但现在试想一下你使用grid-columngrid-row来定位你的网格项如下:

.item-a{
  grid-column: 1 / 2;
  grid-row: 2 / 3;
}
.item-b{
  grid-column: 5 / 6;
  grid-row: 2 / 3;
}

implicit-tracks

我们告诉.item-b在第列线 5开始,在列线6结束,但是我们从未定义过列线 5或6。因为我们引用了不存在的列,所以创建宽度为0的隐式轨道来填充这个间隙。 我们可以使用grid-auto-columnsgrid-auto-rows来指定这些隐式轨道的宽度:

.container{
  grid-auto-columns: 60px;
}
implicit-tracks-with-widths
grid-auto-flow

如果您有未明确放置在网格上的网格项,则自动布局算法会启动,以自动放置项。 此属性用来控制自动布局算法的工作原理。
属性值:
row : 告诉自动布局算法依次填充每一行,并根据需要添加新行
column :告诉自动布局算法依次填充每一列,并根据需要添加新列
dense : 告诉自动布局算法尝试在网格更早的时候填充接下来出现较小的项目留有的空白

.container{
  grid-auto-flow: row | column | row dense | column dense
}

请注意,dense可能会导致您的项目无序显示。
示例:
思考下面的HTML:

<section class="container">
    <div class="item-a">item-a</div>
    <div class="item-b">item-b</div>
    <div class="item-c">item-c</div>
    <div class="item-d">item-d</div>
    <div class="item-e">item-e</div>
</section>

这里定义了一个两列五行的网格,并将 grid-auto-flow属性设置为row(即默认值):

.container{
    display: grid;
    grid-template-columns: 60px 60px 60px 60px 60px;
    grid-template-rows: 30px 30px;
    grid-auto-flow: row;
}

当在网格上放置项目时,您只需要指定其中两个的网格项

.item-a{
    grid-column: 1;
    grid-row: 1 / 3;
}
.item-e{
    grid-column: 5;
    grid-row: 1 / 3;

因为我们将grid-auto-flow属性设置为了row,所以我们的网格看起来会像这个样子。注意我们没有进行设置的三个网格项(item-b, item-c and item-d),会沿行轴进行布局。

grid-auto-flow-row

如果我们将grid-auto-flow属性设置为 column,item-b, item-citem-d 就会沿列轴进行布局。

.container{
    display: grid;
    grid-template-columns: 60px 60px 60px 60px 60px;
    grid-template-rows: 30px 30px;
    grid-auto-flow: column;
}
grid-auto-flow-column
grid

在一行声明中设置一下所有属性的简写形式:grid-template-rows, grid-template-column, grid-template-areas, grid-auto-rows,grid-auto-columns, 以及 grid-auto-flow。它将grid-column-gapgrid-row-gap
属性设置为初始值,即使它们不能由此属性显式去设置。
属性值:
none: 将所有的子属性设置为初始值
subgrid: 将grid-template-rowsgrid-template-columns属性值设置为subgrid其余子属性设置为初始值
<grid-template-rows> / <grid-template-columns>: 将grid-template-rowsgrid-template-columns
分别设置为指定值,其余子属性设置为初始值
<grid-auto-flow>[<grid-auto-rows> [ / <grid-auto-columns>] ] : grid-auto-flow, grid-auto-rowsgrid-auto-columns属性分别接受相同的值,如果省略了grid-auto-columns属性,它将设置为grid-auto-rows属性的值。如果两者均被忽略,那么都将被设置为初始值。

.container{
    grid: none | subgrid | <grid-template-rows> / <grid-template-columns> | <grid-auto-flow> [<grid-auto-rows> [/ <grid-auto-columns>]];
}

示例:
以下两个代码块是等效的:

.container{
    grid: 200px auto / 1fr auto 1fr;
}
.container{
    grid-template-rows: 200px auto;
    grid-template-columns: 1fr auto 1fr;
    grid-template-areas: none;
}

以下两个代码块同样也是等效的:

.container{
    grid: column 1fr / auto;
}
.container{
    grid-auto-flow: column;
    grid-auto-rows: 1fr;
    grid-auto-columns: auto;        
}

它还接受一次性设置所有属性,更复杂但相当方便的语法。指定 grid-template-areas
, grid-auto-rowsgrid-auto-columns属性,其他所有子属性都将设置为其初始值。你现在所做的是在其网格区域内,指定网格线名称和内联轨道大小。这里最容易用一个例子来描述:

.container{
  grid: [row1-start] "header header header" 1fr [row1-end]
        [row2-start] "footer footer footer" 25px [row2-end]
        / auto 50px auto;
}

等同于:

.container{  
  grid-template-areas: "header header header"
                       "footer footer footer";
  grid-template-rows: [row1-start] 1fr [row1-end row2-start] 25px [row2-end];
  grid-template-columns: auto 50px auto; 
}

网格项的属性(Properties for the Grid Items)

grid-column-start
grid-column-end
grid-row-start
grid-row-end
通过使用特定的网格线确定网格项在网格内的位置。grid-column-start/grid-row-start属性表示网格项的网格线的起始位置,grid-column-end/grid-row-end属性表示网格项的网格线的终止位置。
属性值:
**<line>
**: 可以是一个数字来指代相应编号的网格线,或者使用名称指代相应命名的网格线
span <number>: 网格项包含指定数量的网格轨道
span <name>: 网格项包含指定名称网格项的网格线之前的网格轨道
auto: 表明自动定位,自动跨度或者默认跨度为一

.item{
  grid-column-start: <number> | <name> | span <number> | span <name> | auto
  grid-column-end: <number> | <name> | span <number> | span <name> | auto
  grid-row-start: <number> | <name> | span <number> | span <name> | auto
  grid-row-end: <number> | <name> | span <number> | span <name> | auto
}

示例:

.item-a{
  grid-column-start: 2;
  grid-column-end: five;
  grid-row-start: row1-start
  grid-row-end: 3
}
grid-start-end-a
.item-b{
  grid-column-start: 1;
  grid-column-end: span col4-start;
  grid-row-start: 2
  grid-row-end: span 2
}

grid-start-end-b

如果没有声明grid-column-end/grid-row-end属性,默认情况下网格项的跨度为1。
网格项可以互相重叠。可以使用z-index属性控制堆叠顺序。
grid-column
grid-row
grid-column-start+grid-column-end, 和grid-row-start+grid-row-end属性分别的简写形式。
属性值:
<start-line> / <end-line>: 每一个属性均接收自定义的一个相同值,包括跨度。

.item{
  grid-column: <start-line> / <end-line> | <start-line> / span <value>;
  grid-row: <start-line> / <end-line> | <start-line> / span <value>;
}

示例:


grid-start-end-c.png
.item-c{
  grid-column: 3 / span 2;
  grid-row: third-line / 4;
}

如果没有声明结束网格线值,默认网格轨道跨度为1.
grid-area
属性值:
<name> - 你定义的名字
<row-start> / <column-start> / <row-end> / <column-end> - 可以是数字或者命名行
示例:
为网格项命名的一种方式:

.item-d{
  grid-area: header
}

grid-row-start + grid-column-start+ grid-row-end+ grid-column-end属性的一种简写方式:

.item-d{
  grid-area: 1 / col4-start / last-line / 6
}

grid-start-end-d

justify-self
沿列轴对齐网格项中的内容(相反于align-item属性定义的沿行轴对齐)。此值适用于单一网格项中的内容。
属性值:
start: 内容与网格区域的左端对齐
end: 内容与网格区域的右端对齐
center: 内容处于网格区域的中间位置
stretch: 内容宽度占据整个网格区域空间(默认值)

.item{ justify-self: start | end | center | stretch;}

示例

.item-a{
  justify-self: start;
}
![grid-justify-self-start](http://upload-images.jianshu.io/upload_images/1673685-7852d1a5d23c8293.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

.item-a{
  justify-self: end;
}
grid-justify-self-end
.item-a{
  justify-self: center;
}
grid-justify-self-center
.item-a{
  justify-self: stretch;
}

grid-justify-self-stretch

设置网格中所有网格项的对齐方式,可以使用网格容器上的justify-items属性。

align-self
沿行轴对齐网格项中的内容(相反于justify-item属性定义的沿列轴对齐)。此值适用于单一网格项中的内容。
属性值:
start: 内容与网格区域的顶端对齐
end: 内容与网格区域的底部对齐
center: 内容处于网格区域的中间位置
stretch: 内容高度占据整个网格区域空间(默认值)

.item{
  align-self: start | end | center | stretch;
}

示例:

.item-a{
  align-self: start;
}
grid-align-self-start
.item-a{
  align-self: end;
}
grid-align-self-end
.item-a{
  align-self: center;
}
grid-align-self-center
.item-a{
  align-self: stretch;
}
grid-align-self-stretch

本文翻译自 http://chris.house/blog/a-complete-guide-css-grid-layout/#prop-grid-template-areas
转载请注明英文原版出处

推荐阅读更多精彩内容

  • 简介CSS网格布局(又称“网格”),是一种二维网格布局系统。CSS在处理网页布局方面一直做的不是很好。一开始我们用...
    _leonlee阅读 43,032评论 29 157
  • 前言 温馨提示:本文较长,图片较多,本来是想写一篇 CSS 布局方式的,但是奈何 CSS 布局方式种类太多并且实现...
    sunshine小小倩阅读 1,429评论 0 60
  • 原文地址:Getting to know CSS Grid Layout 原文作者:Chris Wright 译者...
    iKcamp阅读 2,281评论 0 13
  • 选择qi:是表达式 标签选择器 类选择器 属性选择器 继承属性: color,font,text-align,li...
    love2013阅读 614评论 0 9
  • 原文地址 注:此文是我翻译的第一篇技术文章。适合有一定CSS原生网格布局使用经验的开发者(读前需要先去了解一下原生...
    我不叫沒耐性阅读 177评论 0 2