vue.js实现一个会动的简历(包含底部导航功能,编辑功能,添加了用户自定义写字速度功能)
在网上看到一个这样的网站,STRML它的效果看着十分有趣,如下图所示:
这个网站是用`react.js`来写的,于是,我就想着用`vue.js`也来写一版,开始撸代码。
首先要分析打字的原理实现,假设我们定义一个字符串`str`,它等于一长串注释加`CSS`代码,并且我们看到,当`css`代码写完一个分号的时候,它写的样式就会生效。我们知道要想让一段`CSS`代码在页面生效,只需要将其放在一对`<style>`标签对中即可。比如:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
</head>
<body>
红色字体
<style>
body{
color:#f00;
}
</style>
</body>
</html>
你可以狠狠点击此处具体示例查看效果。
当看到打字效果的时候,我们不难想到,这是要使用`间歇调用(定时函数:setInterval())`或`超时调用(延迟函数:setTimeout())`加`递归`去模拟实现`间歇调用`。一个包含一长串代码的字符串,它是一个个截取出来,然后分别写入页面中,在这里,我们需要用到字符串的截取方法,如`slice(),substr(),substring()`等,选择用哪个截取看个人,不过需要注意它们之间的区别。好了,让我们来实现一个简单的这样打字的效果,如下:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
</head>
<body>
<div id="result"></div>
<script>
var r = document.getElementById('result');
var c = 0;
var code = 'body{background-color:#f00;color:#fff};'
var timer = setInterval(function(){
c++;
r.innerHTML = code.substr(0,c);
if(c >= code.length){
clearTimeout(timer);
}
},50)
</script>
</body>
</html>
你可以狠狠点击此处具体示例查看效果。好的,让我们来分析一下以上代码的原理,首先放一个用于包含代码显示的标签,然后定义一个包含代码的字符串,接着定义一个初始值为`0`的变量,为什么要定义这样一个变量呢?我们从实际效果中看到,它是一个字一个字的写入到页面中的。初始值是没有一个字符的,所以,我们就从第`0`个开始写入,`c`一个字一个字的加,然后不停的截取字符串,最后渲染到标签的内容当中去,当`c`的值大于等于了字符串的长度之后,我们需要清除定时器。定时函数看着有些不太好,让我们用超时调用结合递归来实现。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
</head>
<body>
<div id="result"></div>
<script>
var r = document.getElementById('result');
var c = 0;
var code = 'body{background-color:#f00;color:#fff};';
var timer;
function write() {
c++;
r.innerHTML = code.substr(0, c);
if (c >= code.length && timer) {
clearTimeout(timer)
} else {
setTimeout(write, 50);
}
}
write();
</script>
</body>
</html>
你可以狠狠点击此处具体示例查看效果。
好了,到此为止,算是实现了第一步,让我们继续,接下来,我们要让代码保持空白和缩进,这可以使用`<pre>`标签来实现,但其实我们还可以使用css代码的`white-space`属性来让一个普通的`div`标签保持这样的效果,为什么要这样做呢,因为我们还要实现一个功能,就是编辑它里面的代码,可以让它生效。更改一下代码,如下:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
<style>
#result {
white-space: pre-wrap;
overflow: auto;
}
</style>
</head>
<body>
<div id="result"></div>
<script>
var r = document.getElementById('result');
var c = 0;
var code = `
body{
background-color:#f00;
color:#fff;
}`;
var timer;
function write() {
c++;
r.innerHTML = code.substr(0, c);
if (c >= code.length && timer) {
clearTimeout(timer)
} else {
setTimeout(write, 50);
}
}
write();
</script>
</body>
</html>
你可以狠狠点击此处具体示例查看效果。
接下来,我们还要让样式生效,这很简单,将代码在`style`标签中写一次即可,请看:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
<style>
#result {
white-space: pre-wrap;
overflow: auto;
}
</style>
</head>
<body>
<div id="result"></div>
<style id="myStyle"></style>
<script>
var r = document.getElementById('result'),
t = document.getElementById('myStyle');
var c = 0;
var code = `
body{
background-color:#f00;
color:#fff;
}`;
var timer;
function write() {
c++;
r.innerHTML = code.substr(0, c);
t.innerHTML = code.substr(0, c);
if (c >= code.length) {
clearTimeout(timer);
} else {
setTimeout(write, 50);
}
}
write();
</script>
</body>
</html>
你可以狠狠点击此处具体示例查看效果。
我们看到代码还会有高亮效果,这可以用正则表达式来实现,比如以下一个`demo`:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>代码编辑器</title>
<style>
* {
margin: 0;
padding: 0;
}
.ew-code {
tab-size: 4;
-moz-tab-size: 4;
-o-tab-size: 4;
margin-left: .6em;
background-color: #345;
white-space: pre-wrap;
color: #f2f2f2;
text-indent: 0;
margin-right: 1em;
display: block;
overflow: auto;
font-size: 20px;
border-radius: 5px;
font-style: normal;
font-weight: 400;
line-height: 1.4;
font-family: Consolas, Monaco, "宋体";
margin-top: 1em;
}
.ew-code span {
font-weight: bold;
}
</style>
</head>
<body>
<code class="ew-code">
<div id="app">
<p>{{ greeting }} world!</p>
</div>
</code>
<code class="ew-code">
//定义一个javascript对象
var obj = {
greeting: "Hello,"
};
//创建一个实例
var vm = new Vue({
data: obj
});
/*将实例挂载到根元素上*/
vm.$mount(document.getElementById('app'));
</code>
<script>
var lightColorCode = {
importantObj: ['JSON', 'window', 'document', 'function', 'navigator', 'console', 'screen', 'location'],
keywords: ['if', 'else if', 'var', 'this', 'alert', 'return', 'typeof', 'default', 'with', 'class',
'export', 'import', 'new'
],
method: ['Vue', 'React', 'html', 'css', 'js', 'webpack', 'babel', 'angular', 'bootstap', 'jquery',
'gulp', 'dom'
],
// special: ["*", ".", "?", "+", "$", "^", "[", "]", "{", "}", "|", "\\", "(", ")", "/", "%", ":", "=", ';']
}
function setHighLight(el) {
var htmlStr = el.innerHTML;
//匹配单行和多行注释
var regxSpace = /(\/\/\s?[^\s]+\s?)|(\/\*(.|\s)*?\*\/)/gm,
matchStrSpace = htmlStr.match(regxSpace),
spaceLen;
//匹配特殊字符
var regxSpecial = /[`~!@#$%^&.{}()_\-+?|]/gim,
matchStrSpecial = htmlStr.match(regxSpecial),
specialLen;
var flag = false;
if (!!matchStrSpecial) {
specialLen = matchStrSpecial.length;
} else {
specialLen = 0;
return;
}
for (var k = 0; k < specialLen; k++) {
htmlStr = htmlStr.replace(matchStrSpecial[k], '<span style="color:#b9ff01;">' + matchStrSpecial[k] +
'</span>');
}
for (var key in lightColorCode) {
if (key ===