[JavaScript]编写一份会动的简历

编写会动的简历

今天跟着方老师做了一个会动的简历,思路就是通过 JavaScript 代码,利用定时器每次同时在 HTML 和 CSS 中输入固定的字符达到实时代码预览的效果,其中用到了 prism.js 库给代码添加高亮,用了 marked.js 库把 markdown 转换成 HTML ,并在页面中展示出来。

效果预览:Git Pages

代码链接:GitHub

是不是看上去觉得效果挺炫的~下面我就来整理一下这个项目的流程,思路以及踩过的坑。感觉好长好多涉及的点要记...应该分几篇写还是合成一篇?...算了先写着先吧。


分别设置 HTML 和 CSS

先写个 demo,可以让代码出现在页面上:

输出

可以看到,我们指定的字符串已经出现在页面上了,但是,出现了两个问题:

1.页面背景色并没有发生变化

2.输出字符串中的空格被压缩了

解决方法:

1.当然没有啊,我们只是把字符串写进 HTML 中,CSS 中还是没有这些设置

2.我们使用 pre 包裹住字符串,让他的空格得以保留

修改一下:把字符串写入 HTML 中的同时,把字符串也写进 CSS 中;使用 pre 标签。

输出正确


使用 setInterval 和 substring 进行逐个字符输出

思路:使用 substring 获取字符串的某个部分,使用 setInterval 每次输入固定字符,并做判断,当获取的字符串下标超过字符串长度时,setInterval 停止。

输出成功


使用 prism.js 设置 CSS 高亮

由于 JSbin 不能上传文件,所以这里往下就不用 JSbin 演示了。

使用 prism.js 库给字体做高亮(没错,还是使用 CRM 大法~):

1.下载 prism.js 的 CSS 和 JS 文件

2.引入文件到项目中

3.copy.run.modify

var result = `
body{
    background-color: red;
}
`
var n = 0
var timer = setInterval(()=>{
  n+=1
  code.innerHTML =  Prism.highlight(result.substring(0,n), Prism.languages.css)
  styleTag.innerHTML = result.substring(0,n)
  if(n>=result.length){
    window.clearInterval(timer)
  }
},100)

more style

给代码设置更多的样式,包括通过使用 animation 营造呼吸效果,调整代码框大小等等:

var result = `
/*
 * 面试官你好,我是XXX
 * 只用文字作做我介绍太单调了
 * 我就用代码来介绍吧
 * 首先准备一些样式
 *
*/
* {
    transition: all 1s;
}
html {
    font-size: 16px;
}
.code-wrapper {
    width: 50%;
    left: 0;
    position: fixed;
    height: 100%;
}
/* 调整一下代码框大小 */
#code {
    border:1px solid transparent;
    padding: 16px;
    overflow: hidden;
}
#code {
    left: 0;
    width: 100%;
    height:100%;
}
/* 让代码呼吸起来 */
#code{
  animation: breathe 1s infinite alternate-reverse;
}
/* 给代码加上一点点高亮 */
.token.comment {
    color: slategray;
}
.token.property {
    color: #f92672;
}
.token.selector {
    color: #a6e22e;
}
`

另外,设置代码高亮有一个小窍门,即我们先设置一个 default.css,把高亮的 CSS 隐藏起来(放到 prism.css 后面),然后再通过 setInterval 把高亮代码设置回来,起到更好的视觉效果。


创建白板

左边是负责代码输出展示,右边是我们最后要写入 Markdown 的地方,所以我们要创建一个函数,创建一块白板出来:

function createPaper(fn){
    var paper = document.createElement('div')
    paper.id = "paper"
    var content = document.createElement('pre')
    content.className = "content"
    paper.appendChild(content)
    document.body.appendChild(paper)
    fn.call()
}

回调初现

在创建白板的时候,输入字符串的任务要停下来,之后再继续输入字符串的任务。

现在封装一下之前的函数:

function writeCode(prefix,code){
    let domCode = document.querySelector('#code')
    domCode.innerHTML = prefix || ''
    let n = 0
    let timer = setInterval(()=>{
        n = n+1
        domCode.innerHTML = Prism.highlight(prefix + code.substring(0,n), Prism.languages.css)

        //这句话的作用是:当代码在被输入到HTML中时,代码框的滚动条能一直保持在最下方
        domCode.scrollTop = domCode.scrollHeight
        styleTag.innerHTML = prefix + code.substring(0,n)
        if(n >= code.length){
            window.clearInterval(timer)
        }
    },20)
}

prefix 和 code 分别对应第一次需要输入的字符串和本次需要输入的字符串,如果没有 prefix,则之前的 innerHTML 则会被新的字符串取代,而不是连起来。

所以我们这里的流程应该是:writeCode('',result) -> 添加白板 createPaper() -> 设置白板样式 -> 在白板添加 Markdown

那我们这样写行不行呢:

writeCode('',result)
createPaper()
writeMarkdown()

很遗憾,这样是不行的,因为 writeCode() 中有 setInterval 计时器,所以他是一个异步函数,实际上流程就变成了这样:

添加白板 createPaper() ? writeCode('',result) ? 设置白板样式 ? 在白板添加 Markdown

下面先插播一下我对于 异步与回调 的理解。


异步与回调

  • 异步就是不等待结果的函数/事件

如:

function setTime(fn){
    setTimeout(()=>{
        console.log(2)
        fn.call()
    },1000)
}
function cb(){
    console.log(3)
}
setTime(cb)
console.log(1)

按照代码顺序本来是先执行 setTime(cb),再执行 console.log(1),但由于 setTime(cb) 是异步事件,不用等待他执行完成之后才执行后续代码,所以 console.log(1) 就先执行了,1S 后才执行setTime(cb) 的内容。

  • 回调是拿到异步结果的一种方式。
function setTime(fn){
    setTimeout(()=>{
        console.log(2)
        fn.call()
    },1000)
}
function cb(){
    console.log(‘异步任务执行完成,回调结束’)
}
setTime(cb)

如这段代码中,函数 cb() 就被当做 回调函数 传入 setTime() 中,当 setTime() 中的内容执行完之后,就执行函数 cb() 。

注意
同步事件/函数 也可以使用回调


回到正题

所以我们应该使用回调函数,在writeCode() 结束的时候执行 createPaper()

function writeCode(prefix,code,fn){
    let domCode = document.querySelector('#code')
    domCode.innerHTML = prefix || ''
    let n = 0
    let timer = setInterval(()=>{
        n = n+1
        domCode.innerHTML = Prism.highlight(prefix + code.substring(0,n), Prism.languages.css)
        domCode.scrollTop = domCode.scrollHeight
        styleTag.innerHTML = prefix + code.substring(0,n)
        if(n >= code.length){
            window.clearInterval(timer)
            fn.call()
        }
    },20)
}
writeCode('',result,()=>{
    createPaper()
})

输入 Markdown

因为所要输入的地方不同,所以另写一个函数,输入 markdown:

function writeMarkdown(markdown,fn){
    let domMarkdown = document.querySelector('#paper .content')
    let n = 0
    let timer = setInterval(()=>{
        n = n+1
        domMarkdown.innerHTML = markdown.substring(0,n)
        domMarkdown.scrollTop = domMarkdown.scrollHeight
        if(n >= markdown.length){
            window.clearInterval(timer)
            fn.call()
        }
    },20)
}
var result4 = `
/* 还差一点点 */
.markdown-body {
    padding: 16px;
    background-color: white;
    overflow: auto;
}

/* Done~ 简历完成啦~ */
`
var md = `
# 简历
个人简历

...

`
// 实际上就变成了:
writeCode('',result,()=>{
    createPaper(()=>{
        writeMarkdown(md)
    })
})

最后把 Markdown 转换成 HTML

我们选用了比较讨巧的方法:新建一个 div,然后把 div 的样式设置好(主要用了github-markdown-css),div 内容设置成经过 marked.js 库(怎么使用在此不赘述了)处理后的 HTML,最后用这个 div 替换掉之前的白板。

function convertMarkdownToHtml(fn){
    var div = document.createElement('div')  
    div.className = 'html markdown-body'
    div.innerHTML = marked(md)
    let markdownContainer = document.querySelector('#paper > .content')
    markdownContainer.style = 'background-color:white'
    markdownContainer.replaceWith(div)
    fn && fn.call()
}
// 实际上最后的流程就变成了:
writeCode('',result,()=>{
    createPaper(()=>{
        writeCode(result,result2,()=>{
            writeMarkdown(md,()=>{
                writeCode(result + result2,result3,()=>{
                    convertMarkdownToHtml(()=>{
                        writeCode(result + result2 + result3,result4,()=>{
                            console.log('Done')
                        })
                    })
                })
            })
        })
    })
})
// 哈哈,恐怖吧?传说中的回调地狱

总结

纵观整个项目下来,感觉异步和回调不难,反而在 CSS 方面耗费了点时间...

行文不畅,这个..这个..这个我也在慢慢改进,我之前还在想着,是把做这个东西的整个流程都记录下来,还是只挑其中比较重要的知识点,写着写着,还是写下了含糊不清的这篇东西...不过也算是有所收获,多总结总结还是不亏的~

猜你喜欢

转载自www.cnblogs.com/No-harm/p/9707182.html