学习CSS Grid布局
一. 重要术语:
CSS Grid(网格) 布局(又称为 “Grid(网格)” ),是一个二维的基于网格的布局系统,它的目标是完全改变我们基于网格的用户界面的布局方式。
FlexBox:一维布局;
Grid: 二维布局;
Flexbox 和 Grid 能协同工作,而且配合得非常好
网格容器(Grid Container)
应用 display: grid 的元素。这是所有 网格项(grid item)的直接父级元素。在这个例子中,container 就是 网格容器(Grid Container)。
<div class="container">
<div class="item item-1"></div>
<div class="item item-2"></div>
<div class="item item-3"></div>
</div>
网格项(Grid item)
网格容器(Grid Container)的子元素(例如直接子元素)。这里 item 元素就是网格项(Grid Item),但是 sub-item 不是。
<div class="container">
<div class="item"></div>
<div class="item">
<p class="sub-item"></p>
</div>
<div class="item"></div>
</div>
网格线(Grid Line)
构成网格结构的分界线。它们既可以是垂直的(“列网格线(column grid lines)”),也可以是水平的(“行网格线(row grid lines)”),并位于行或列的任一侧。例如,这里的黄线就是一条列网格线。
网格轨道(Grid Track)
两条相邻网格线之间的空间。你可以把它们想象成网格的列或行。下图是第二条和第三条 行网格线 之间的 网格轨道(Grid Track)。
网格单元格(Grid Cell)
两个相邻的行和两个相邻的列网格线之间的空间。这是 Grid(网格) 系统的一个“单元”。下图是第 1 至第 2 条 行网格线 和第 2 至第 3 条 列网格线 交汇构成的 网格单元格(Grid Cell)。
网格区域(Grid Area)
4条网格线包围的总空间。一个 网格区域(Grid Area) 可以由任意数量的 网格单元格(Grid Cell) 组成。下图是 行网格线1和3,以及列网格线1和3 之间的网格区域。
Grid(网格)属性目录
网格容器(Grid Container)属性
- display
- grid-template-columns
- grid-template-rows
- grid-template-areas
- grid-template
- grid-column-gap
- grid-row-gap
- grid-gap
- justify-items
- align-items
- place-items
- justify-content
- align-items
- place-items
- justify-content
- align-content
- place-content
- grid-auto-columns
- grid-auto-rows
- grid
网格项(Grid Items)属性
- grid-column-start
- grid-column-end
- grid-row-start
- grid-row-end
- grid-column
- grid-row
- grid-area
- justify-self
- align-self
- place-self
网格容器(Grid Container)属性详解
display
将元素定义为网格容器,并为其内容建立新的网格格式上下文
值:
- grid: 生成一个块级网格
- inline-grid: 生成一个内联网格
.container{
display:grid | inline-grid;
}
grid-template-columns/grid-template-rows
使用空格分隔的值列表,用来定义网格的列和行。这些值表示 网格轨道(Grid Track) 大小,它们之间的空格表示网格线。
值:
- track-size:可以是长度值,百分比,或者等份网格容器中可用空间(使用 fr 单位)
- line-name: 网格线名称
.container {
grid-template-columns: <track-size> ... | <line-name> <track-size> ...;
grid-template-rows: <track-size> ... | <line-name> <track-size> ...;
}
示例:
当你在 网格轨道(Grid Track) 值之间留出空格时,网格线会自动分配正数和负数名称:
.container {
grid-template-columns: 40px 50px auto 50px 40px;
grid-template-rows: 25% 100px auto;
}
但是你可以明确的指定网格线(Grid Line)名称,例如 line-name 值。请注意网格线名称的括号语法:
.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 Line)可以有多个名称。例如,这里的第二条 行网格线(row grid lines) 将有两个名字:row1-end 和 row2-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]);
}
上面的代码等价于:
.container {
grid-template-columns: 20px [col-start] 20px [col-start] 20px [col-start];
}
如果多行共享相同的名称,则可以通过其网格线名称和计数来引用它们。
.item {
grid-column-start: col-start 2;
}
fr 单元允许你用等分网格容器剩余可用空间来设置 网格轨道(Grid Track) 的大小 。例如,下面的代码会将每个网格项设置为网格容器宽度的三分之一:
.container {
grid-template-columns: 1fr 1fr 1fr;
}
剩余可用空间是除去所有非灵活网格项 之后 计算得到的。在这个例子中,可用空间总量减去 50px 后,再给 fr 单元的值 3 等分:
.container {
grid-template-columns: 1fr 50px 1fr 1fr;
}
grid-template-areas
通过引用 grid-area 属性指定的 网格区域(Grid Area) 名称来定义网格模板。重复网格区域的名称导致内容跨越这些单元格。一个点号(.)代表一个空单元格。这个语法本身可视作网格的可视化结构
值:
- grid-area-name:由网格项的grid-area指定的网格区域名称
- .(点号): 代表一个空的网格单元
- 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";
}
上面的代码将创建一个 4 列宽 3 行高的网格。整个顶行将由 header 区域组成。中间一排将由两个 main 区域,一个是空单元格,一个 sidebar 区域组成。最后一行全是 footer 区域组成。
注意: 你的声明中的每一行都需要有相同数量的单元格。
你可以使用任意数量的相邻的 点. 来声明单个空单元格。 只要这些点.之间没有空隙隔开,他们就代表一个单独的单元格。
注意你 不能 用这个语法来命名网格线,只是命名 网格区域 。当你使用这种语法时,区域两端的网格线实际上会自动命名。如果你的网格区域的名字是 foo,该区域的起始行网格线 和 起始列网格线 的名称将为 foo-start,而最后一条行网格线 和 最后一条列网格线 的名称将为 foo-end。这意味着某些网格线可能有多个名字,如上例中最左边的网格线,它将有三个名称:header-start,main-start 和 footer-start 。
grid-template
用于定义grid-template-rows,grid-template-columns,grid-template-areas的一种简写属性
值:
- none: 将三个属性都设置为初始值
- /: 将grid-template-columns和grid-template-rows设置为相应特定的值,并且设置grid-template-template-areas为none
.container {
grid-template:
[row1-start] "header header header" 25px [row1-end]
[row2-start] "footer footer footer" 25px [row2-end]
/ auto 50px auto;
}
等价于:
.container {
grid-template-rows: [row1-start] 25px [row1-end row2-start] 25px [row2-end];
grid-template-columns: auto 50px auto;
grid-template-areas:
"header header header"
"footer footer footer";
}
由于 grid-template 不会重置 隐式 网格属性(grid-auto-columns, grid-auto-rows, 和 grid-auto-flow),
这可能是你想在大多数情况下做的,建议使用 grid 属性而不是 grid-template。
grid-column-gap / grid-row-gap
指定网格线(grid lines)的大小。你可以把它想象为设置列/行之间间距的宽度。
值: :长度值
.container {
grid-template-columns: 100px 50px 100px;
grid-template-rows: 80px auto 80px;
grid-column-gap: 10px;
grid-row-gap: 15px;
}
只能在 列/行 之间创建间距,网格外部边缘不会有这个间距。
注意:这两个属性将删除 grid- 前缀,就是将 grid-column-gap 和 grid-row-gap重命名为 column-gap 和 row-gap。 Chrome 68+,Safari 11.2 Release 50+ 和Opera 54+ 已经支持无前缀的属性。
grid-gap
grid-column-gap和grid-row-gap的简写语法
先定义列间距后定义行间距,巧记:大写的L,先竖后横
.container {
grid-template-columns: 100px 50px 100px;
grid-template-rows: 80px auto 80px;
grid-gap: 15px 10px;
}
等价于:
.container{
/* 设置 grid-column-gap 和 grid-row-gap */
grid-column-gap: 10px;
grid-row-gap: 10px;
/* 等价于 */
grid-gap: 10px 10px;
/* 等价于 */
grid-gap: 10px;
}
justify-items
沿着 inline(行)轴线对齐网格项(grid items)(相反的属性是 align-items 沿着 block(列)轴线对齐)。此值适用于容器内的所有网格项
值:
- start:将网格项对齐到其单元格的左侧起始边缘(左侧对齐)
- end:将网格项对齐到其单元格的右侧结束边缘(右侧对齐)
- center:将网格项对齐到其单元格的水平中间位置(水平居中对齐)
- stretch:填满单元格的宽度(默认值)
.container {
justify-items: start | end | center | stretch;
}
示例:
.container {
justify-items: start;
}
.container{
justify-items: end;
}
.container{
justify-items: center;
}
.container{
justify-items: stretch;
}
这些行为也可以通过每个单独网格项(grid items) 的 justify-self 属性设置。
align-items
沿着 block(列)轴线对齐网格项(grid items)(相反的属性是 justify-items 沿着 inline(行)轴线对齐)。此值适用于容器内的所有网格项。
值:
- start:将网格项对齐到其单元格的顶部起始边缘(顶部对齐)
- end:将网格项对齐到其单元格的底部结束边缘(底部对齐)
- center:将网格项对齐到其单元格的垂直中间位置(垂直居中对齐)
- stretch:填满单元格的高度(默认值)
place-items
place-items 是设置 align-items 和 justify-items 的简写形式。
值:
:第一个值设置 align-items 属性,第二个值设置 justify-items 属性。如果省略第二个值,则将第一个值同时分配给这两个属性。
justify-content
有时,你的网格合计大小可能小于其 网格容器(grid container) 大小。 如果你的所有 网格项(grid items) 都使用像 px 这样的非灵活单位设置大小,就可能出现这种情况。在这种情况下,您可以设置网格容器内的网格的对齐方式。 此属性沿着 inline(行)轴线对齐网格(相反的属性是 align-content ,沿着 block(列)轴线对齐网格)。
值:
- start:将网格对齐到 网格容器(grid container) 的左侧起始边缘(左侧对齐)
- end:将网格对齐到 网格容器 的右侧结束边缘(右侧对齐)
- center:将网格对齐到 网格容器 的水平中间位置(水平居中对齐)
- stretch:调整 网格项(grid items) 的宽度,允许该网格填充满整个 网格容器 的宽度
- space-around:在每个网格项之间放置一个均匀的空间,左右两端放置一半的空间
- space-between:在每个网格项之间放置一个均匀的空间,左右两端没有空间
- space-evenly:在每个网格项目之间放置一个均匀的空间,左右两端放置一个均匀的空间
.container {
justify-content: start | end | center | stretch | space-around | space-between | space-evenly;
}
示例:
左对齐
.container {
justify-content: start;
}
右对齐
.container {
justify-content: end;
}
居中对齐:
.container {
justify-content: center;
}
平铺:
.container {
justify-content: stretch;
}
space-around:在每个网格项之间放置一个均匀的空间,左右两端放置一半的空间
.container {
justify-content: space-around;
}
space-between: 在每个网格项之间放置一个均匀的空间,左右两端没有空间
.container {
justify-content: space-between;
}
space-evenly:在每个网格项目之间放置一个均匀的空间,左右两端放置一个均匀的空间
.container {
justify-content: space-evenly;
}
align-content
有时,你的网格合计大小可能小于其 网格容器(grid container) 大小。 如果你的所有 网格项(grid items) 都使用像 px 这样的非灵活单位设置大小,就可能出现这种情况。在这种情况下,您可以设置网格容器内的网格的对齐方式。 此属性沿着 block(列)轴线对齐网格(相反的属性是 justify-content ,沿着 inline(行)轴线对齐网格)。
值:
- start:将网格对齐到 网格容器(grid container) 的顶部起始边缘(顶部对齐)
- end:将网格对齐到 网格容器 的底部结束边缘(底部对齐)
- center:将网格对齐到 网格容器 的垂直中间位置(垂直居中对齐)
- stretch:调整 网格项(grid items) 的高度,允许该网格填充满整个 网格容器 的高度
- space-around:在每个网格项之间放置一个均匀的空间,上下两端放置一半的空间
- space-between:在每个网格项之间放置一个均匀的空间,上下两端没有空间
-space-evenly:在每个网格项目之间放置一个均匀的空间,上下两端放置一个均匀的空间
place-content
place-content 是设置 align-content 和 justify-content 的简写形式。
值:
:第一个值设置 align-content 属性,第二个值设置 justify-content 属性。如果省略第二个值,则将第一个值同时分配给这两个属性。
除 Edge 之外的所有主要浏览器都支持 place-content 简写属性。
grid-auto-columns / grid-auto-rows
指定任何自动生成的网格轨道(grid tracks)(又名隐式网格轨道)的大小。当网格中的网格项多于单元格时,或者当网格项位于显式网格之外时,就会创建隐式轨道。
值:
:可以是长度值,百分比,或者等份网格容器中可用空间的分数(使用 fr 单位)
.container {
grid-template-columns: 60px 60px;
grid-template-rows: 90px 90px
}
.item-a {
grid-column: 1 / 2;
grid-row: 2 / 3;
}
.item-b {
grid-column: 5 / 6;
grid-row: 2 / 3;
}
我们告诉 .item-b 从第 5 条列网格线开始到第 6 条列网格线结束,但我们从来没有定义过 第5 或 第6 列网格线。
因为我们引用的网格线不存在,所以创建宽度为 0 的隐式网格轨道以填补空缺。我们可以使用 grid-auto-columns 和 grid-auto-rows 来指定这些隐式轨道的大小:
.container {
grid-auto-columns: 60px;
}
grid-auto-flow
如果你有一些没有明确放置在网格上的网格项(grid items),自动放置算法 会自动放置这些网格项。该属性控制自动布局算法如何工作。
值:
- row:告诉自动布局算法依次填充每行,根据需要添加新行 (默认)
- column:告诉自动布局算法依次填入每列,根据需要添加新列
- dense:告诉自动布局算法在稍后出现较小的网格项时,尝试填充网格中较早的空缺
.container {
grid-auto-flow: row | column | row dense | column dense
}
示例:
<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>
.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,item-d)会这样排列在可用的行中:
相反地,如果我们把 grid-auto-flow 设成了 column ,那么 item-b,item-c,item-d 会沿着列向下排列:
.container {
display: grid;
grid-template-columns: 60px 60px 60px 60px 60px;
grid-template-rows: 30px 30px;
grid-auto-flow: column;
}
grid
在一个声明中设置所有以下属性的简写: grid-template-rows, grid-template-columns, grid-template-areas, grid-auto-rows, grid-auto-columns, 和 grid-auto-flow 。(注意:您只能在单个网格声明中指定显式或隐式网格属性)。
值:
- none:将所有子属性设置为其初始值。
- :与grid-template 简写的工作方式相同。
- / [ auto-flow && dense? ] ? :将grid-template-rows 设置为指定的值。 如果 auto-flow 关键字位于斜杠的右侧,则会将 grid-auto-flow 设置为 column。 如果另外指定了 dense 关键字,则自动放置算法使用 “dense” 算法。 如果省略 grid-auto-columns ,则将其设置为 auto。
- [ auto-flow && dense? ] ? / :将 grid-template-columns 设置为指定值。 如果 auto-flow 关键字位于斜杠的左侧,则会将grid-auto-flow 设置为 row 。 如果另外指定了 dense 关键字,则自动放置算法使用 “dense” 打包算法。 如果省略 grid-auto-rows ,则将其设置为 auto。
网格项(Grid Items)属性
注意:float,display: inline-block,display: table-cell,vertical-align 和 column-* 属性对网格项无效。
grid-column-start / grid-column-end / grid-row-start / grid-row-end
通过引用特定网格线(grid lines) 来确定 网格项(grid item) 在网格内的位置。 grid-column-start / grid-row-start 是网格项开始的网格线,grid-column-end / grid-row-end 是网格项结束的网格线。
值:
- :可以是一个数字引用一个编号的网格线,或者一个名字来引用一个命名的网格线
- span :该网格项将跨越所提供的网格轨道数量
- span :该网格项将跨越到它与提供的名称位置
- 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;
}
.item-b {
grid-column-start: 1;
grid-column-end: span col4-start;
grid-row-start: 2
grid-row-end: span 2
}
如果没有声明指定 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 的简写形式。
值:
- / :每个网格项都接受所有相同的值,作为普通书写的版本,包括跨度
示例:
.item-c {
grid-column: 3 / span 2;
grid-row: third-line / 4;
}
grid-area
为网格项提供一个名称,以便可以 被使用网格容器 grid-template-areas 属性创建的模板进行引用。 另外,这个属性可以用作grid-row-start + grid-column-start + grid-row-end + grid-column-end 的简写。
值:
- :你所选的名称
- / / / :数字或分隔线名称
.item-d {
grid-area: header
}
.item-d {
grid-area: 1 / col4-start / last-line / 6
}
justify-self
沿着 inline(行)轴线对齐网格项( 相反的属性是 align-self ,沿着 block(列)轴线对齐)。此值适用于单个网格项内的内容。
值:
- start:将网格项对齐到其单元格的左侧起始边缘(左侧对齐)
- end:将网格项对齐到其单元格的右侧结束边缘(右侧对齐)
- center:将网格项对齐到其单元格的水平中间位置(水平居中对齐)
- stretch:填满单元格的宽度(默认值)
.item {
justify-self: start | end | center | stretch;
}
要为网格中的所有网格项设置 行轴线(row axis) 线上对齐方式,也可以在 网格容器 上设置 justify-items 属性。
align-self
沿着 block(列)轴线对齐网格项(grid items)( 相反的属性是 justify-self ,沿着 inline(行)轴线对齐)。此值适用于单个网格项内的内容。
值:
- start:将网格项对齐到其单元格的顶部起始边缘(顶部对齐)
- end:将网格项对齐到其单元格的底部结束边缘(底部对齐)
- center:将网格项对齐到其单元格的垂直中间位置(垂直居中对齐)
- stretch:填满单元格的高度(默认值)
place-self
place-self 是设置 align-self 和 justify-self 的简写形式。
值:
- auto – 布局模式的 “默认” 对齐方式。
- :第一个值设置 align-self 属性,第二个值设置 justify-self 属性。如果省略第二个值,则将第一个值同时分配给这两个属性。
学习CSS Grid布局的更多相关文章
- 用 CSS Grid 布局制作一个响应式柱状图
最新一段时间比较喜欢玩弄图表,出于好奇,我想找出比较好的用 CSS 制作图表的方案.开始学习网上开源图表库,它对我学习新的和不熟悉的前端技术很有帮助,比如这个:CSS Grid. 今天和大家分享我学到 ...
- CSS Grid 布局学习笔记
CSS Grid 布局学习笔记 好久没有写博客了, MDN 上关于 Grid 布局的知识比较零散, 正好根据我这几个月的实践对 CSS Grid 布局做一个总结, 以备查阅. 1. 基础用法 Grid ...
- CSS Grid 布局完全指南(图解 Grid 详细教程)
CSS Grid 布局是 CSS 中最强大的布局系统.与 flexbox 的一维布局系统不同,CSS Grid 布局是一个二维布局系统,也就意味着它可以同时处理列和行.通过将 CSS 规则应用于 父元 ...
- CSS Grid布局指南
简介 CSS Grid布局 (又名"网格"),是一个基于二维网格布局的系统,主要目的是改变我们基于网格设计的用户接口方式.如我们所知,CSS 总是用于网页的样式设置,但它并没有起到 ...
- 5分钟学会 CSS Grid 布局
欢迎加入前端交流群交流知识&&获取视频资料:749539640 这是一篇快速介绍网站未来布局的文章. Grid 布局是网站设计的基础,CSS Grid 是创建网格布局最强大和最简单的工 ...
- 带你入门 CSS Grid 布局
前言 三月中旬的时候,有一个对于 CSS 开发者来说很重要的消息,最新版的 Firefox 和 Chrome 已经正式支 CSS Grid 这一新特性啦.没错:我们现在就可以在最流行的两大浏览器上玩转 ...
- 快速使用CSS Grid布局,实现响应式设计
常用Grid布局属性介绍 下面从一个简单Grid布局例子说起. CSS Grid 布局由两个核心组成部分是 wrapper(父元素)和 items(子元素). wrapper 是实际的 grid(网格 ...
- CSS Grid 布局
CSS Grid 布局是 CSS 中最强大的布局系统.与 flexbox 的一维布局系统不同,CSS Grid 布局是一个二维布局系统,也就意味着它可以同时处理列和行.通过将 CSS 规则应用于 父元 ...
- css Grid布局
CSS Grid 布局完全指南(图解 Grid 详细教程)https://www.html.cn/archives/8510#prop-grid-gap 5分钟学会 CSS Grid 布局https: ...
随机推荐
- Django框架(二十三)-- Django rest_framework-视图组件
一.基本视图 class PublishView(APIView): def get(self, request): publish_list = Publish.objects.all() bs = ...
- 通过premake生成vs工程文件
visual studio的工程视图,在引用外部目录时非常麻烦,这时候可以使用premake一键生成工程文件,自动配置好工程的各种属性,还有目录的组织结构. 示例:如下是一个c++的外部目录结构,我们 ...
- 浅析struct device结构体
device结构体:设备驱动模型中的基础结构体之一 struct device { /*设备所依附的父设备 大多数情况下,这样的设备是某种总线或主控制器 如果该成员变量的值为NULL,表示当前设备是一 ...
- 201871010123-吴丽丽 《面向对象程序设计(Java)》第十周学习总结
项目 内容 这个作业属于哪个课程 https://www.cnblogs.com/nwnu-daizh/ 这个作业要求在哪里 https://www.cnblogs.com/nwnu-daizh/p/ ...
- 201871020225-牟星源《面向对象程序设计(java)》第十二周学习总结
201871020225-牟星源<面向对象程序设计(java)>第十二周学习总结 项目 内容 这个作业属于哪个课程 https://www.cnblogs.com/nwnu-daizh/ ...
- hdfs.server.datanode.DataNode: Block pool ID needed, but service not yet registered with NN
启动hadoop 发现 50070 的 livenode 数量是 0 查看日志, hdfs.server.datanode.DataNode: Block pool ID needed, but se ...
- apktool android studio 调试 smali code, 重新打包
虽然有些菜单的位置跟新版的Android Stuido 3.4 有些不同,但是能用. https://crosp.net/blog/software-development/mobile/androi ...
- flask 搭建简单restful接口,moco基础
from flask import Flask, jsonify, abort, make_response app = Flask(__name__)app.config['JSON_AS_ASCI ...
- 数据结构——顺序栈(sequence stack)
/* sequenceStack.c */ /* 栈 先进后出(First In Last Out,FILO)*/ #include <stdio.h> #include <stdl ...
- Xamarin.Forms移动开发系列1:介绍和安装
摘要 Xamarin成立于2011年5月16日.Xamarin 是一套基于C#语言的跨平台移动应用开发工具,2016年2月24日被微软正式收购. 前言 很早就已经听说强大的.NET生态中有一个移动开发 ...