本文由QQ音乐前端团队发表
前段时间做了一个非常有意思的模拟终端的展示页:http://ursb.me/terminal/(没有做移动端适配,请在PC端访问),这个页面非常有意思,它可以作为个人博客系统或者给 Linux 初学者学习终端命令,现分享给大家~
开源地址:airingursb/terminal
0x01 样式
打开页面效果如下图所示:
其实这里的样式就直接 Copy 了自己 Mac 上 Terminal 的界面,当然界面上的参数都是自己写的,表示穷人没有钱买这么高配的电脑…
注:截图里面的 logo 是通过archey打印出来的,mac直接输入 brew install archey 即可安装。
命令输入其实只用了一个 input
标签实现的:
<span class="prefix">[<span id='usr'>usr</span>@<span class="host">ursb.me</span> <span id="pos">~</span>]% </span>
<input type="text" class="input-text">
当然,原始的样式太丑了,肯定要对 input
标签做美化:
.input-text {
display: inline-block;
background-color: transparent;
border: none;
-moz-appearance: none;
-webkit-appearance: none;
outline: 0;
box-sizing: border-box;
font-size: 17px;
font-family: Monaco, Cutive Mono, Courier New, Consolas, monospace;
font-weight: 700;
color: #fff;
width: 300px;
padding-block-end: 0
}
虽然是在浏览器访问,但毕竟我们要模拟终端的效果,因此对鼠标的样式最好也修改一下:
* {
cursor: text;
}
0x02 渲染逻辑
每次打印新的内容其实是一个在之前 html 的基础上拼接新的内容再重新绘制的过程。渲染时机是用户按下回车键,因此需要监听keydown事件;渲染函数是mainFunc,传入用户输入的内容和用户当前的目录,后者是全局变量,在很多命令中都需要判断用户当前的位置。
e_main.html($('#main').html() + '[<span id="usr">' + usrName + '</span>@<span class="host">ursb.me</span> ' + position + ']% ' + input + '<br/>Nice to Meet U : )<br/>')
e_html.animate({ scrollTop: $(document).height() }, 0)
每次渲染之后记得加个滚动动画,让浏览器尽可能真实地模拟终端的行为。
$(document).bind('keydown', function (b) {
e_input.focus()
if (b.keyCode === 13) {
e_main.html($('#main').html())
e_html.animate({ scrollTop: $(document).height() }, 0)
mainFunc(e_input.val(), nowPosition)
hisCommand.push(e_input.val())
isInHis = 0
e_input.val('')
}
// Ctrl + U 清空输入快捷键
if (b.keyCode === 85 && b.ctrlKey === true) {
e_input.val('')
e_input.focus()
}
})
同时,还实现了一个快捷键 Ctrl + U 清空当前输入,有其他的快捷键读者也可以这样类似去实现。
0x03 help
我们知道,Linix 命令的规范是 command[Options...]
,以防有用户不了解,首先,我实现了一个最简单的 help
命令字。效果如下:
直接看代码,这是直接打印的内容,实现起来非常简单。
switch (command) {
case 'help':
e_main.html($('#main').html() + '[<span id="usr">' + usrName + '</span>@<span class="host">ursb.me</span> ' + position + ']% ' + input + '<br/>' + '[sudo ]command[ Options...]<br/>You can use following commands:<br/><br/>cd<br/>ls<br/>cat<br/>clear<br/>help<br/>exit<br/><br/>Besides, there are some hidden commands, try to find them!<br/>')
e_html.animate({ scrollTop: $(document).height() }, 0)
break
}
其中 command
取 input 标签第一个空格前的元素即可:
command = input.split(' ')[0]
既然知道了怎么取命令字,那各种打印类型的命令字都是可以自己作为小彩蛋实现~ 这里就不一一举例了,读者可以阅读源码自行了解。
0x04 clear
clear
是清空控制台,实现起来非常简单,根据我们的渲染逻辑,直接清空外层div中的内容即可。
case 'clear':
e_main.html('')
e_html.animate({ scrollTop: $(document).height() }, 0)
break
既然是博客系统,总不能全部的内容都放在前端页面的代码上进行渲染,固定的 help
命令或者简单的打印命令是这样做是可以的。但如果我们的目录结构变动了,或者想写一篇新文章,或者修改文件的内容,那则需要我们大幅度去修改静态 html 文件的代码,这显然是不现实的。
本系统还配套实现了相应的后台,服务端的作用是用来读取存放在服务端的目录和文件内容,并提供对应的接口以便将数据返回给前端。
服务器存储的文件层级如下:
接下来,来看几个稍有难度的功能吧。
0x05 ls
ls
命令用来显示目标列表,在 Linux 中是使用率较高的命令。 ls
命令的输出信息可以进行彩色加亮显示,以分区不同类型的文件。
因此,我们的实现该功能的三个重点是:
- 获取用户当前的位置
- 获取当前位置下的所有文件和目录