Linux-磁盘管理小结
这篇博文主要总结了Linux磁盘的一些操作,主要是硬盘的加载,分区(MBR分区和GPT分区),分区的挂载,以及swap分区的加载设置。
基础命令
- df查看磁盘分区使用状况
- -l //仅显示本地磁盘(默认)
- -a //显示所有文件系统的磁盘使用情况,包含比如/proc/
- -h //以1024进制计算最合适的单位显示磁盘容量
- -H //以1000进制计算最合适的单位显示磁盘容量
- -t //显示指定类型文件系统的磁盘分区
- -T //显示磁盘分区类型
- -x //不显示指定类型文件系统的磁盘分区
- du统计磁盘上的文件大小
- -b //以byte为单位统计文件
- -k //以KB为单位统计文件
- -m //以MB为单位统计文件
- -h //以1024进制计算最合适的单位显示磁盘容量
- -H //以1000进制计算最合适的单位显示磁盘容量
- -s //统计指定目标
- 常用命令
- df -lhT
- df -lhT -t ext4(分区类型)
- df -lhT -x ext4
- du -s [指定目录]
- du -sb *.zip //模糊匹配
- du -sm *.zip
- du -sh *.zip
回顾磁盘分区时的注意事项:
- 主分区和扩展分区总数不能超过4个。
- 扩展分区最多只能有一个
- 扩展分区不能直接存取数据
- 小知识:
- Linux系统中硬件设备都是以文件的形式存在于根目录下的Dev目录下。
- 硬件设备都是有Linux系统自动识别的。
- 添加的新硬盘,必须进行分区、格式化、挂载后才能使用。
- MBR分区模式:主分区不超过4个,单个分区容量最大为2TB
- GPT分区模式:主分区个数“几乎”没有限制,单个分区容量“几乎”没有限制。GPT分区中,最多可以支持128个主分区,且每个分区的大小突破了MBR分区的2TB的限制,最大为18EB=18432PB=18874368TB。缺点是GPT的主分区中,不适合安装X86架构的系统。
当硬盘空间消耗殆尽时怎么办?
比较好的做法应该是:在保留原硬盘的基础上,给服务器添加新的硬盘。
为虚拟机添加硬盘
- 将虚拟机关机(poweroff)。(当然,也有服务器的主板支持热插拔的。可以带电连接新硬盘。)
- 虚拟机设置->下面的“添加”->类型选择“硬盘”->下一步->选择硬盘类型(默认的(SCSI)就好)->创建一个新的虚拟机硬盘(下一步)->设置磁盘最大值;(没什么特殊要求,基本都是下一步,最后一步OK)。
- 重启Linux系统,使用fdisk -l//显示每个硬盘的分区列表(新添加的硬盘是没有分区表的)可以看到Disk /dev/sdb:和Disk /dev/sda:2块硬盘,以及sda的分区表,没有sdb的分区表。
- 先使用MBR分区模式为sdb分区。
[root@joe dev]#
fdisk /dev/sdb
//进入分区模式
Device contains neither a valid DOS partition table, nor Sun, SGI or OSF disklabel
Building a new DOS disklabel with disk identifier 0x9ce83f46.
Changes will remain in memory only, until you decide to write them.
After that, of course, the previous content won't be recoverable. Warning: invalid flag 0x0000 of partition table will be corrected by w(rite) WARNING: DOS-compatible mode is deprecated. It's strongly recommended to
switch off the mode (command 'c') and change display units to
sectors (command 'u'). Command (m for help):m
//查看帮助
Command action
a toggle a bootable flag
b edit bsd disklabel
c toggle the dos compatibility flag
d delete a partition //删除一个分区
l list known partition types
m print this menu
n add a new partition //添加新的分区
o create a new empty DOS partition table
p print the partition table //打印分区表
q quit without saving changes //取消保存并退出
s create a new empty Sun disklabel
t change a partition's system id //修改分区的系统ID
u change display/entry units
v verify the partition table
w write table to disk and exit //写分区表并退出
x extra functionality (experts only) Command (m for help): n
Command action
e extended //扩展分区
p primary partition (-)//主分区
p
Partition number (-):First cylinder (-, default ): //扇区的范围(1-2610),默认开始1,直接回车则使用默认数值
Using default value
Last cylinder, +cylinders or +size{K,M,G} (-, default ): 500M Command (m for help): p Disk /dev/sdb: 21.5 GB, bytes
heads, sectors/track, cylinders
Units = cylinders of * = bytes
Sector size (logical/physical): bytes / bytes
I/O size (minimum/optimal): bytes / bytes
Disk identifier: 0x9ce83f46 Device Boot Start End Blocks Id System
/dev/sdb1 + Linux //分配好的主分区1
//添加第二个分区
Command (m for help): n
Command action
e extended
p primary partition (-)
p
Partition number (-):
Value out of range.
Partition number (-): 2
First cylinder (-, default ):
Using default value
Last cylinder, +cylinders or +size{K,M,G} (-, default ): 500M
Value out of range.
Last cylinder, +cylinders or +size{K,M,G} (-, default ):
Using default value Command (m for help): p Disk /dev/sdb: 21.5 GB, bytes
heads, sectors/track, cylinders
Units = cylinders of * = bytes
Sector size (logical/physical): bytes / bytes
I/O size (minimum/optimal): bytes / bytes
Disk identifier: 0x9ce83f46 Device Boot Start End Blocks Id System
/dev/sdb1 + Linux
/dev/sdb2 Linux //第二个分区
//由于分配不合适主观意愿,想删除分区
Command (m for help): d
Partition number (-):2
//分区编号 Command (m for help): p Disk /dev/sdb: 21.5 GB, bytes
heads, sectors/track, cylinders
Units = cylinders of * = bytes
Sector size (logical/physical): bytes / bytes
I/O size (minimum/optimal): bytes / bytes
Disk identifier: 0x9ce83f46 Device Boot Start End Blocks Id System
/dev/sdb1 + Linux //第二个分区已经删除 Command (m for help): n
Command action
e extended
p primary partition (-)
p
Partition number (-):2
First cylinder (-, default ):
Using default value
Last cylinder, +cylinders or +size{K,M,G} (-, default ): 1000 Command (m for help): p Disk /dev/sdb: 21.5 GB, bytes
heads, sectors/track, cylinders
Units = cylinders of * = bytes
Sector size (logical/physical): bytes / bytes
I/O size (minimum/optimal): bytes / bytes
Disk identifier: 0x9ce83f46 Device Boot Start End Blocks Id System
/dev/sdb1 + Linux
/dev/sdb2 Linux Command (m for help): n
Command action
e extended
p primary partition (-)
e //建立扩展分区
Partition number (-):3
First cylinder (-, default ):
Using default value
Last cylinder, +cylinders or +size{K,M,G} (-, default ):
Using default value Command (m for help): p Disk /dev/sdb: 21.5 GB, bytes
heads, sectors/track, cylinders
Units = cylinders of * = bytes
Sector size (logical/physical): bytes / bytes
I/O size (minimum/optimal): bytes / bytes
Disk identifier: 0x9ce83f46 Device Boot Start End Blocks Id System
/dev/sdb1 + Linux
/dev/sdb2 Linux
/dev/sdb3 Extended Command (m for help): n
Command action
l logical (or over)
//此时扩展分区e没有了,说明MBR只能有一个扩展分区,接下来是逻辑分区
p primary partition (-)
l
First cylinder (-, default ):
Using default value
Last cylinder, +cylinders or +size{K,M,G} (-, default ): Command (m for help): p Disk /dev/sdb: 21.5 GB, bytes
heads, sectors/track, cylinders
Units = cylinders of * = bytes
Sector size (logical/physical): bytes / bytes
I/O size (minimum/optimal): bytes / bytes
Disk identifier: 0x9ce83f46 Device Boot Start End Blocks Id System
/dev/sdb1 + Linux
/dev/sdb2 Linux
/dev/sdb3 Extended
/dev/sdb5 + Linux //逻辑分区是从5开始的,1-4只能是主分区和扩展分区的编号 Command (m for help): n
Command action
l logical ( or over)
p primary partition (-)
l
First cylinder (-, default ):
Using default value
Last cylinder, +cylinders or +size{K,M,G} (-, default ):
Using default value Command (m for help): p Disk /dev/sdb: 21.5 GB, bytes
heads, sectors/track, cylinders
Units = cylinders of * = bytes
Sector size (logical/physical): bytes / bytes
I/O size (minimum/optimal): bytes / bytes
Disk identifier: 0x9ce83f46 Device Boot Start End Blocks Id System
/dev/sdb1 + Linux
/dev/sdb2 Linux
/dev/sdb3 Extended
/dev/sdb5 + Linux
/dev/sdb6 + Linux Command (m for help):w //保存写
The partition table has been altered! Calling ioctl() to re-read partition table.
Syncing disks.
[root@joe dev]# fdisk-
l Disk
/dev/sdb
: 21.5 GB, bytes
heads, sectors/track, cylinders
Units = cylinders of * = bytes
Sector size (logical/physical): bytes / bytes
I/O size (minimum/optimal): bytes / bytes
Disk identifier: 0x9ce83f46 Device Boot Start End Blocks Id System
/dev/sdb1 + Linux
/dev/sdb2 Linux
/dev/sdb3 Extended
/dev/sdb5 + Linux
/dev/sdb6 + Linux Disk/dev/sda
: 21.5 GB, bytes
heads, sectors/track, cylinders
Units = cylinders of * = bytes
Sector size (logical/physical): bytes / bytes
I/O size (minimum/optimal): bytes / bytes
Disk identifier: 0x000a030a Device Boot Start End Blocks Id System
/dev/sda1 * Linux
Partition does not end on cylinder boundary.
/dev/sda2 Linux swap / Solaris
Partition does not end on cylinder boundary.
/dev/sda3 Linux
Partition does not end on cylinder boundary.
/dev/sda4 Extended
/dev/sda5 Linux - 使用GPT分区模式分区(同时GPT的分区工具parted也可以MBR分区)
[root@joe dev]# parted
GNU Parted 2.1
使用/dev/sda
//注意正在使用的是sda
Welcome to GNU Parted! Type 'help' to view a list of commands.
(parted) print all
Model: VMware, VMware Virtual S (scsi)
Disk /dev/sda: .5GB
Sector size (logical/physical): 512B/512B
Partition Table: msdos Number Start End Size Type File system 标志
1049kB 211MB 210MB primary ext4 启动
211MB 2308MB 2097MB primary linux-swap(v1)
2308MB 4405MB 2097MB primary ext4
4405MB .5GB .1GB extended
4406MB .5GB .1GB logical ext4 Model: VMware, VMware Virtual S (scsi)
Disk/dev/sdb:
.5GB
Sector size (logical/physical): 512B/512B
Partition Table: msdos //sdb的应该是我们需要的gpt Number Start End Size Type File system 标志 警告: 无法以读写方式打开 /dev/sr0 (只读文件系统)。/dev/sr0 已按照只读方式打开。
错误: /dev/sr0: unrecognised disk label (parted)select /dev/sdb
//选择sdb
使用 /dev/sdb
(parted) mkpart //如果不进行gpt的选择设置,直接mkpart那么我们还是使用的MBR模式
分区类型? primary/主分区/extended/扩展分区? primary
文件系统类型? [ext2]? ^Z
--------------------------------------------------------------------------------------------------
(parted)select /dev/
sdb
使用 /dev/sdb
(parted) mklabel gpt
警告: The existing disk label on /dev/sdb will be destroyed and all data on this disk will be lost. Do you
want to continue?
是/Yes/否/No? yes
(parted) print all
Model: VMware, VMware Virtual S (scsi)
Disk/dev/sda:
.5GB
Sector size (logical/physical): 512B/512B
Partition Table: msdos Number Start End Size Type File system 标志
1049kB 211MB 210MB primary ext4 启动
211MB 2308MB 2097MB primary linux-swap(v1)
2308MB 4405MB 2097MB primary ext4
4405MB .5GB .1GB extended
4406MB .5GB .1GB logical ext4 Model: VMware, VMware Virtual S (scsi)
Disk/dev/sdb:
.5GB
Sector size (logical/physical): 512B/512B
Partition Table: gpt Number Start End Size File system Name 标志 警告: 无法以读写方式打开 /dev/sr0 (只读文件系统)。/dev/sr0 已按照只读方式打开。
错误: /dev/sr0: unrecognised disk label (parted) mkpart
分区名称? []? test1
文件系统类型? [ext2]? ext4
起始点?1
//以1开始,默认单位是M unit GB 指定为GB为单位
结束点? 1000M
(parted) print
Model: VMware, VMware Virtual S (scsi)
Disk /dev/sdb: .5GB
Sector size (logical/physical): 512B/512B
Partition Table: gpt Number Start End Size File system Name 标志
1049kB 1000MB 999MB test1 (parted)rm
//删除分区
(parted) print
Model: VMware, VMware Virtual S (scsi)
Disk /dev/sdb: .5GB
Sector size (logical/physical): 512B/512B
Partition Table: gpt Number Start End Size File system Name 标志 (parted) mkpart
分区名称? []? test1
文件系统类型? [ext2]? ext4
起始点?0 //以0开始,出现了警告,这里是字节对齐的原因造成的,所以一般为了避免警告,我们不以0开始。
结束点? 1000M
警告: The resulting partition is not properly aligned for best performance.
忽略/Ignore/放弃/Cancel? cancel
(parted) mkpart
分区名称? []? test1
文件系统类型? [ext2]? ext4
起始点?1
结束点?1000M
(parted) print
Model: VMware, VMware Virtual S (scsi)
Disk /dev/sdb: .5GB
Sector size (logical/physical): 512B/512B
Partition Table: gpt Number Start End Size File system Name 标志
1049kB 1000MB 999MB test1 (parted) mkpart
分区名称? []? test2
文件系统类型? [ext2]? ext4
起始点? 1000M
结束点? 1500M
(parted) print
Model: VMware, VMware Virtual S (scsi)
Disk /dev/sdb: .5GB
Sector size (logical/physical): 512B/512B
Partition Table: gpt Number Start End Size File system Name 标志
1049kB 1000MB 999MB test1
1000MB 1500MB 500MB test2
//上面是交互模式,下面是命令模式
(parted) mkpart test3//使用一条命令直接搞定 分区名 起始位 结束位
警告: The resulting partition is not properly aligned for best performance. //出现分区的原因是起始的1500和上次结束的1500重叠了。
忽略/Ignore/放弃/Cancel? cancel
(parted) mkpart test3 1501M 1700M
(parted) mkpart test4 1701M 1800M
(parted) mkpart test5 1801M 1900M
(parted) print
Model: VMware, VMware Virtual S (scsi)
Disk /dev/sdb: .5GB
Sector size (logical/physical): 512B/512B
Partition Table: gpt Number Start End Size File system Name 标志
1049kB 1000MB 999MB test1
1000MB 1500MB 500MB test2
1501MB 1700MB 199MB test3
1701MB 1800MB .6MB test4
1801MB 1900MB .6MB test5 (parted)rm
(parted) quit
- 分区完以后,就是格式化和挂载分区了。也就是设置文件系统。在这里需要注意以下内容:MBR分区只能格式化主分区和扩展分区,逻辑分无不能格式化 GPT分区,在格式化以后,只能使用parted 的print查看格式结果 挂载分区:分区默认的挂载目录/mnt目录挂载点必须存在。
[root@joe dev]#
ls -l /dev/sdb*
brw-rw----. root disk , 5月 : /dev/sdb
brw-rw----. root disk , 5月 : /dev/sdb1
brw-rw----. root disk , 5月 : /dev/sdb2
brw-rw----. root disk , 5月 : /dev/sdb3
brw-rw----. root disk , 5月 : /dev/sdb5
brw-rw----. root disk , 5月 : /dev/sdb6
[root@joe dev]# mkfs.ext3/dev/sdb1
//第一种设置方式
mke2fs 1.41. (-May-)
文件系统标签=
操作系统:Linux
块大小= (log=)
分块大小= (log=)
Stride= blocks, Stripe width= blocks
inodes, blocks
blocks (5.00%) reserved for the super user
第一个数据块=
Maximum filesystem blocks=
block groups
blocks per group, fragments per group
inodes per group
Superblock backups stored on blocks:
, , , , , , , 正在写入inode表: 完成
Creating journal ( blocks): 完成
Writing superblocks and filesystem accounting information: 完成 This filesystem will be automatically checked every mounts or
days, whichever comes first. Use tune2fs -c or -i to override.
[root@joe dev]# mkfs-t ext4 /dev/sdb2
//第二种方法
mke2fs 1.41. (-May-)
文件系统标签=
操作系统:Linux
块大小= (log=)
分块大小= (log=)
Stride= blocks, Stripe width= blocks
inodes, blocks
blocks (5.00%) reserved for the super user
第一个数据块=
Maximum filesystem blocks=
block groups
blocks per group, fragments per group
inodes per group
Superblock backups stored on blocks:
, , 正在写入inode表: 完成
Creating journal ( blocks): 完成
Writing superblocks and filesystem accounting information: 完成 This filesystem will be automatically checked every mounts or
days, whichever comes first. Use tune2fs -c or -i to override.
[root@joe dev]#mkdir -p /mnt/joetest
//首先建立挂载点
[root@joe dev]#mount /dev/sdb1 /mnt/joetest/
//挂载分区
[root@joe dev]#umount /mnt/joetest/
//卸载挂载点 上面这中挂载方式是临时的,永久性的应该如下:
vim+ /etc/
fstab
在末尾插入一行/dev/sdb1 /mnt/imooc ext3 default
设备名称 挂载点 文件系统类型
保存退出即可 - swap交换分区(步骤为:建立一个普通的Linux分区,修改分区类型的16进制编码,格式化交换分区,启用交换分区。
[root@joe dev]#
fdisk /dev/
sdb WARNING: GPT (GUID Partition Table) detected on '/dev/sdb'! The util fdisk doesn't support GPT. Use GNU Parted.
WARNING: DOS-compatible mode is deprecated. It's strongly recommended to
switch off the mode (command 'c') and change display units to
sectors (command 'u'). Command (m for help): p Disk /dev/sdb: 21.5 GB, bytes
heads, sectors/track, cylinders
Units = cylinders of * = bytes
Sector size (logical/physical): bytes / bytes
I/O size (minimum/optimal): bytes / bytes
Disk identifier: 0x00000000 Device Boot Start End Blocks Id System
/dev/sdb1 + Linux
/dev/sdb2 Linux
/dev/sdb3 Extended
/dev/sdb5 + Linux
/dev/sdb6 + Linux Command (m for help): t
Partition number (-)://修改ID
Hex code (type L to list codes): L Empty NEC DOS Minix / old Lin bf Solaris
FAT12 PlanLinux swap
/ So c1 DRDOS/sec (FAT-
XENIX root 3c PartitionMagicLinux
c4 DRDOS/sec (FAT-
XENIX usr Venix OS/ hidden C: c6 DRDOS/sec (FAT- Hex code (type L to list codes): 82
Changed system type of partition to (Linux swap / Solaris) Command (m for help): w
The partition table has been altered! Calling ioctl() to re-read partition table.
Syncing disks.
[root@joe dev]# fdisk/dev/
sdb WARNING: GPT (GUID Partition Table) detected on '/dev/sdb'! The util fdisk doesn't support GPT. Use GNU Parted.
WARNING: DOS-compatible mode is deprecated. It's strongly recommended to
switch off the mode (command 'c') and change display units to
sectors (command 'u'). Command (m for help): p Disk /dev/sdb: 21.5 GB, bytes
heads, sectors/track, cylinders
Units = cylinders of * = bytes
Sector size (logical/physical): bytes / bytes
I/O size (minimum/optimal): bytes / bytes
Disk identifier: 0x00000000 Device Boot Start End Blocks Id System
/dev/sdb1 + Linux
/dev/sdb2Linux swap /
Solaris
/dev/sdb3 Extended
/dev/sdb5 + Linux
/dev/sdb6 + Linux Command (m for help): q [root@joe dev]# mkswap/dev/sdb2
//设置交换区
Setting up swapspace version , size = KiB
no label, UUID=c7d31434--4bbb-b68e-29b501934377
[root@joe dev]# swapon/dev/sdb2
//开启交换区
[root@joe dev]# free
total used free shared buffers cached
Mem:
-/+ buffers/cache:
Swap:[root@joe dev]# swapoff
/dev/sdb2
//关闭交换区
[root@joe dev]#
Linux-磁盘管理小结的更多相关文章
- Linux 磁盘管理
Linux磁盘管理好坏管理直接关系到整个系统的性能问题. Linux磁盘管理常用三个命令为df.du和fdisk. df:列出文件系统的整体磁盘使用量 du:检查磁盘空间使用量 fdisk:用于磁盘分 ...
- df、du、fdisk:Linux磁盘管理三板斧的使用心得(转载)
From:http://os.51cto.com/art/201012/240726_all.htm 作者介绍:李洋(博客),博士毕业于中科院计算所.10多年来一直从事计算机网络信息安全研发工作,曾主 ...
- linux 磁盘管理学习笔记
磁盘管理命令:fdisk df du fdisk #查看硬盘分区表 df #查看分区使用情况 du #查看文件占用空间情况lvdisplay #逻辑分区 [1] 李洋.df.du.fdisk:Linu ...
- linux磁盘管理系列-软RAID的实现
1 什么是RAID RAID全称是独立磁盘冗余阵列(Redundant Array of Independent Disks),基本思想是把多个磁盘组合起来,组合一个磁盘阵列组,使得性能大幅提高. R ...
- linux磁盘管理系列-LVM的使用
LVM是什么 LVM是Linux操作系统的逻辑卷管理器. 现在有两个Linux版本的LVM,分别是 LVM1,LVM2.LVM1是一种已经被认为稳定了几年的成熟产品,LVM2 是最新最好的LVM版本. ...
- linux磁盘管理系列三:LVM的使用
磁盘管理系列 linux磁盘管理系列一:磁盘配额管理 http://www.cnblogs.com/zhaojiedi1992/p/zhaojiedi_linux_040_quota.html l ...
- linux磁盘管理系列二:软RAID的实现
磁盘管理系列 linux磁盘管理系列一:磁盘配额管理 http://www.cnblogs.com/zhaojiedi1992/p/zhaojiedi_linux_040_quota.html l ...
- linux磁盘管理系列一:磁盘配额管理
磁盘管理系列 linux磁盘管理系列一:磁盘配额管理 http://www.cnblogs.com/zhaojiedi1992/p/zhaojiedi_linux_040_quota.html l ...
- Linux磁盘管理,vi编辑器以及包管理器
一.Linux磁盘管理 Linux磁盘管理常用的三个命令为df,du,fdisk df:列出文件系统的整体磁盘使用量,利用这个命令来获取磁盘被占用了多少空间,,目前还剩下多少空间用法:df [-ahi ...
- Linux 磁盘管理的命令
Linux 磁盘管理 磁盘分区及挂载: 先查询系统的使用情况: 使用fdisk -l语句 查询结果: 进行磁盘的新建:***添加磁盘时系统必须处于关机状态** 在进行对系统磁盘的使用情况的查询 查 ...
随机推荐
- .net走向设计2—设计工具
1.思维导图 2.项目管理工具 3.常用UML工具 4.数据库设计工具
- js 正则验证输入框只允许输入正实数和正整数和负整数
<input onkeyup="this.value=this.value.replace(/[^0-9.]/g,'')"> (正实数) <input onke ...
- typename
typename关键字是C++在标准化过程中被引入的,目的在于向编译器说明template内的某个标识符是个类型. 如:template <typename T> class MyClas ...
- 【Android UI】Android开发之View的几种布局方式及实践
引言 通过前面两篇: Android 开发之旅:又见Hello World! Android 开发之旅:深入分析布局文件&又是“Hello World!” 我们对Android应用程序运行原理 ...
- 我对C#的理解
C#里面所有东西都可以看作对象.接口,类,枚举等等. 类是最常用的,可以继承别的接口,类等,就会自动拥有别人的功能. 接口是类的概要.给别人看的协议,好像一个人对外做出的承诺. 抽象类是实现了部分承诺 ...
- ubuntu上搭建review board代码评审站点
Reviewboard是一个开源个人可以免费使用的代码评审框架,貌似现在有越来越多的公司也开始使用reviewboard作为公司的代码评审工具. 今天早上试了一下,搭建过程非常方便简单,按照网页提示即 ...
- install openvpn and openvpn manager in ubuntu
sudo apt-get install openvpn sudo apt-get install network-manager-openvpn
- java异常处理机制
本文从Java异常最基本的概念.语法开始讲述了Java异常处理的基本知识,分析了Java异常体系结构,对比Spring的异常处理框 架,阐述了异常处理的基本原则.并且作者提出了自己处理一个大型应用系统 ...
- js php json
js端生成json函数 function json_encode_js(aaa){ function je(str){ var a=[],i=0; var pcs="abcdefghijkl ...
- 使用css3制作蚂蚁线
涉及知识点:background-clip.animation; 代码请查看codepen:https://codepen.io/guoxianqiang/pen/jVXPbm