如何用Vue.js制作动态简历,并实现底部导航与编辑功能?
- 内容介绍
- 文章标签
- 相关推荐
本文共计2385个文字,预计阅读时间需要10分钟。
在网上看到一个这样的网站,STRML,它的效果看着挺有意思,如图所示:这个网站是用react.js来写的。既然如此,我就想用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; oveflow: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 eveningwater.com/',title:'个人网站'}, {url:'github.com/eveningwater',title:'github'} ], paused:false,//暂停 playing:false,//播放图标动画 autoPlaying:false,//播放音频 audio:'' } }, mounted(){ }, methods:{ // 播放音乐 playMusic(){ this.playing = true; this.autoPlaying = true; // 创建audio标签 this.audio = new Audio(); this.audio.src = "eveningwater.com/project/newReact-music-player/audio/%E9%BB%84%E5%9B%BD%E4%BF%8A%20-%20%E7%9C%9F%E7%88%B1%E4%BD%A0%E7%9A%84%E4%BA%91.mp3"; this.audio.loop = 'loop'; this.audio.autoplay = 'autoplay'; this.$refs.music.appendChild(this.audio); }, // 跳过动画 skipAnimationFun(e){ e.preventDefault(); this.$emit('on-skip'); }, // 暂停动画 pauseFun(e){ e.preventDefault(); this.paused = !this.paused; this.$emit('on-pause',this.paused); }, // 暂停音乐 musicPause(){ this.playing = !this.playing; if(!this.playing){ this.audio.pause(); }else{ this.audio.play(); } } } } </script> <style scoped> #bottom{ position:fixed; bottom:5px; left:0; right:0; } #bottom p{ float:right; } #bottom a{ text-decoration: none; color: #999; cursor:pointer; margin-left:5px; } #bottom a:hover,#bottom a:active{ color: #010a11; } </style>
接下来是核心 APP.vue 组件代码:
<template> <div id="app"> <div class="main"> <StyleEditor ref="styleEditor" v-bind.sync="currentStyle"></StyleEditor> <ResumeEditor ref="resumeEditor" :markdown = "currentMarkdown" :enableHtml="enableHtml"></ResumeEditor> </div> <BottomNav ref ="bottomNav" @on-pause="pauseAnimation" @on-skip="skipAnimation"></BottomNav> </div> </template> <script> import ResumeEditor from './components/resumeEditor' import StyleEditor from './components/styleEditor' import BottomNav from './components/bottomNav' import './assets/common.css' import fullStyle from './style.js' import my from './my.js' export default { name: 'app', components: { ResumeEditor, StyleEditor, BottomNav }, data() { return { interval: 40,//写入字的速度 currentStyle: { code: '' }, enableHtml: false,//是否打造成HTML网页 fullStyle: fullStyle, currentMarkdown: '', fullMarkdown: my, timer: null } }, created() { this.makeResume(); }, methods: { // 暂停动画 pauseAnimation(bool) { if(bool && this.timer){ clearTimeout(this.timer); }else{ this.makeResume(); } }, // 快速跳过动画 skipAnimation(){ if(this.timer){ clearTimeout(this.timer); } let str = ''; this.fullStyle.map((f) => { str += f; }) setTimeout(() => { this.$set(this.currentStyle,'code',str); },100) this.currentMarkdown = my; this.enableHtml = true; this.$refs.bottomNav.playMusic(); }, // 加载动画 makeResume: async function() { await this.writeShowStyle(0) await this.writeShowResume() await this.writeShowStyle(1) await this.writeShowHtml() await this.writeShowStyle(2) await this.$nextTick(() => {this.$refs.bottomNav.playMusic()}); }, // 打造成HTML网页 writeShowHtml: function() { return new Promise((resolve, reject) => { this.enableHtml = true; resolve(); }) }, // 写入css代码 writeShowStyle(n) { return new Promise((resolve, reject) => { let showStyle = (async function() { let style = this.fullStyle[n]; if (!style) return; //计算出数组每一项的长度 let length = this.fullStyle.filter((f, i) => i <= n).map((it) => it.length).reduce((t, c) => t + c, 0); //当前要写入的长度等于数组每一项的长度减去当前正在写的字符串的长度 let prefixLength = length - style.length; if (this.currentStyle.code.length < length) { let l = this.currentStyle.code.length - prefixLength; let char = style.substring(l, l + 1) || ' '; this.currentStyle.code += char; if (style.substring(l - 1, l) === '\n' && this.$refs.styleEditor) { this.$nextTick(() => { this.$refs.styleEditor.goBottom(); }) } this.timer = setTimeout(showStyle, this.interval); } else { resolve(); } }).bind(this) showStyle(); }) }, // 写入简历 writeShowResume() { return new Promise((resolve, reject) => { let length = this.fullMarkdown.length; let showResume = () => { if (this.currentMarkdown.length < length) { this.currentMarkdown = this.fullMarkdown.substring(0, this.currentMarkdown.length + 1); let lastChar = this.currentMarkdown[this.currentMarkdown.length - 1]; let prevChar = this.currentMarkdown[this.currentMarkdown.length - 2]; if (prevChar === '\n' && this.$refs.resumeEditor) { this.$nextTick(() => { this.$refs.resumeEditor.goBottom() }); } this.timer = setTimeout(showResume, this.interval); } else { resolve() } } showResume(); }) } } } </script> <style scoped> #app { font-family: 'Avenir', Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } .main { position: relative; } html { min-height: 100vh; } * { transition: all 1.3s; } </style>
到此为止,一个可以快速跳过动画,可以暂停动画,还有音乐播放,还能自由编辑代码的会动的简历已经完成,代码已上传至 git源码 ,欢迎 fork ,也望不吝啬 star 。
在线预览
总结
以上所述是小编给大家介绍的vue.js实现会动的简历(包含底部导航功能,编辑功能),希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对自由互联网站的支持!
本文共计2385个文字,预计阅读时间需要10分钟。
在网上看到一个这样的网站,STRML,它的效果看着挺有意思,如图所示:这个网站是用react.js来写的。既然如此,我就想用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; oveflow: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 eveningwater.com/',title:'个人网站'}, {url:'github.com/eveningwater',title:'github'} ], paused:false,//暂停 playing:false,//播放图标动画 autoPlaying:false,//播放音频 audio:'' } }, mounted(){ }, methods:{ // 播放音乐 playMusic(){ this.playing = true; this.autoPlaying = true; // 创建audio标签 this.audio = new Audio(); this.audio.src = "eveningwater.com/project/newReact-music-player/audio/%E9%BB%84%E5%9B%BD%E4%BF%8A%20-%20%E7%9C%9F%E7%88%B1%E4%BD%A0%E7%9A%84%E4%BA%91.mp3"; this.audio.loop = 'loop'; this.audio.autoplay = 'autoplay'; this.$refs.music.appendChild(this.audio); }, // 跳过动画 skipAnimationFun(e){ e.preventDefault(); this.$emit('on-skip'); }, // 暂停动画 pauseFun(e){ e.preventDefault(); this.paused = !this.paused; this.$emit('on-pause',this.paused); }, // 暂停音乐 musicPause(){ this.playing = !this.playing; if(!this.playing){ this.audio.pause(); }else{ this.audio.play(); } } } } </script> <style scoped> #bottom{ position:fixed; bottom:5px; left:0; right:0; } #bottom p{ float:right; } #bottom a{ text-decoration: none; color: #999; cursor:pointer; margin-left:5px; } #bottom a:hover,#bottom a:active{ color: #010a11; } </style>
接下来是核心 APP.vue 组件代码:
<template> <div id="app"> <div class="main"> <StyleEditor ref="styleEditor" v-bind.sync="currentStyle"></StyleEditor> <ResumeEditor ref="resumeEditor" :markdown = "currentMarkdown" :enableHtml="enableHtml"></ResumeEditor> </div> <BottomNav ref ="bottomNav" @on-pause="pauseAnimation" @on-skip="skipAnimation"></BottomNav> </div> </template> <script> import ResumeEditor from './components/resumeEditor' import StyleEditor from './components/styleEditor' import BottomNav from './components/bottomNav' import './assets/common.css' import fullStyle from './style.js' import my from './my.js' export default { name: 'app', components: { ResumeEditor, StyleEditor, BottomNav }, data() { return { interval: 40,//写入字的速度 currentStyle: { code: '' }, enableHtml: false,//是否打造成HTML网页 fullStyle: fullStyle, currentMarkdown: '', fullMarkdown: my, timer: null } }, created() { this.makeResume(); }, methods: { // 暂停动画 pauseAnimation(bool) { if(bool && this.timer){ clearTimeout(this.timer); }else{ this.makeResume(); } }, // 快速跳过动画 skipAnimation(){ if(this.timer){ clearTimeout(this.timer); } let str = ''; this.fullStyle.map((f) => { str += f; }) setTimeout(() => { this.$set(this.currentStyle,'code',str); },100) this.currentMarkdown = my; this.enableHtml = true; this.$refs.bottomNav.playMusic(); }, // 加载动画 makeResume: async function() { await this.writeShowStyle(0) await this.writeShowResume() await this.writeShowStyle(1) await this.writeShowHtml() await this.writeShowStyle(2) await this.$nextTick(() => {this.$refs.bottomNav.playMusic()}); }, // 打造成HTML网页 writeShowHtml: function() { return new Promise((resolve, reject) => { this.enableHtml = true; resolve(); }) }, // 写入css代码 writeShowStyle(n) { return new Promise((resolve, reject) => { let showStyle = (async function() { let style = this.fullStyle[n]; if (!style) return; //计算出数组每一项的长度 let length = this.fullStyle.filter((f, i) => i <= n).map((it) => it.length).reduce((t, c) => t + c, 0); //当前要写入的长度等于数组每一项的长度减去当前正在写的字符串的长度 let prefixLength = length - style.length; if (this.currentStyle.code.length < length) { let l = this.currentStyle.code.length - prefixLength; let char = style.substring(l, l + 1) || ' '; this.currentStyle.code += char; if (style.substring(l - 1, l) === '\n' && this.$refs.styleEditor) { this.$nextTick(() => { this.$refs.styleEditor.goBottom(); }) } this.timer = setTimeout(showStyle, this.interval); } else { resolve(); } }).bind(this) showStyle(); }) }, // 写入简历 writeShowResume() { return new Promise((resolve, reject) => { let length = this.fullMarkdown.length; let showResume = () => { if (this.currentMarkdown.length < length) { this.currentMarkdown = this.fullMarkdown.substring(0, this.currentMarkdown.length + 1); let lastChar = this.currentMarkdown[this.currentMarkdown.length - 1]; let prevChar = this.currentMarkdown[this.currentMarkdown.length - 2]; if (prevChar === '\n' && this.$refs.resumeEditor) { this.$nextTick(() => { this.$refs.resumeEditor.goBottom() }); } this.timer = setTimeout(showResume, this.interval); } else { resolve() } } showResume(); }) } } } </script> <style scoped> #app { font-family: 'Avenir', Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } .main { position: relative; } html { min-height: 100vh; } * { transition: all 1.3s; } </style>
到此为止,一个可以快速跳过动画,可以暂停动画,还有音乐播放,还能自由编辑代码的会动的简历已经完成,代码已上传至 git源码 ,欢迎 fork ,也望不吝啬 star 。
在线预览
总结
以上所述是小编给大家介绍的vue.js实现会动的简历(包含底部导航功能,编辑功能),希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对自由互联网站的支持!

