用原生js写一个"多动症"的简历

用原生js写一个”多动症”的简历

预览地点
源码地点

最近在知乎上看到@方应杭用vue写了一个会动的简历,以为挺好玩的,研究一下其完成思绪,决议试试用原生js来完成。

《用原生js写一个

会动的简历完成思绪

这张会的简历,就彷佛一个打字员在不停地录入笔墨,页面显现动态效果。又彷佛一个早已录制好影片,而我们只是坐在放映机前寓目。

道理分两个部份

  1. 页面能看见的不停跳动着的增添的笔墨,由innerHTML掌握

  2. 页面的规划效果由藏在”背地的”style标签完成

设想一下你要往一张网页每间隔0.1秒增添一个字,是不是是开个定时器,中断地往body内里塞,就可以啊!没错,做到这一步就完成了道理的第一部份

再设想一下,在往页面内里塞的时刻,我还想转变啊字的字体色彩以及网页背景色彩,那应当怎么做呢,是不是是实行下面的代码就可以呢,没错,只不过变动字体和背景色不是倏忽转变的,而是也是开个定时器,中断地往style标签中塞入以下代码,如许就完成了道理的第二步,是不是是好简朴 ???, 接下来让我们一步步完成它

.xxx{
  color: blue;
  background: red; 
}

项目搭建

在这个项目中我们

  1. 运用webpack2来完成项目的构建

  2. 运用yarn来处置惩罚依靠包的治理

  3. 运用es6的写法

  4. 运用部份原生dom操纵api

  5. standard.js(代码作风束缚利器)

目次组织以下

《用原生js写一个

最重要的几个模块离别是resumeEditor(简历编辑模块)stylesEditor(简历款式编辑模块)以及vQuery(封装的dom操纵模块)
末了app.js(进口模块)再将几个模块的功用结合起来完成悉数项目。

vQuery(封装的dom操纵模块)

由于背面的几个模块都要依靠这个小模块,所以我们先简朴的看下。

class Vquery {
  constructor (selector, context) {
    this.elements = getEles(selector, context)
  }

  optimizeCb (callback) {
    ...
  }

  get (index) {
    ...
  }

  html (sHtml) {
    ...
  }

  addClass (iClass) {
    ...
  }

  css (styles) {
    ...
  }

  height (h) {
    ...
  }

  scrollTop (top) {
    ...
  }
}

export default (selector, context) => {
  return new Vquery(selector, context)
}

可以看出它做的事就是封装一个组织函数Vquery,它的实例会有一些简朴的dom操纵要领,末了为了可以像jQuery那样运用$().funcName的情势去运用,我们导出了一个匿名函数,在匿名函数中去new Vquery

stylesEditor(简历款式编辑模块)

简历所展现的规划效果都是由这个模块完成的,中心要领是showStyles。

const showStyles = (num, callback) => {
  let style = styles[num]
  let length
  let prevLength

  if (!style) {
    return
  }

  length = styles.filter((item, i) => { // 盘算数组styles前n个元素的长度
    return i <= num
  }).reduce((result, item) => {
    result += item.length
    return result
  }, 0)

  prevLength = length - style.length

  clearInterval(timer)
  timer = setInterval(() => {
    let start = currentStyle.length - prevLength
    let char = style.substring(start, start + 1) || ''
    currentStyle += char
    if (currentStyle.length === length) { // 数组styles前n个元素已悉数塞入,则封闭定时器,而且实行表面传进来的回调,进而实行下一步操纵
      clearInterval(timer)
      callback && callback()
    } else {
      let top = $stylePre.height() - MAX_HEIGHT
      if (top > 0) { // 当塞入的内容已超过了容器的高度,我们须要设置一下转动间隔才轻易演示接下来的内容
        goBottom(top)
      }
      $style.html(currentStyle)
      $stylePre.html(Prism.highlight(currentStyle, Prism.languages.css))
    }
  }, delay)
}

stylesEditor(简历款式编辑模块)

简历编辑模块用来展现简历内容,重要会阅历由markdown花样往html页面情势的转换。

const markdownToHtml = (callback) => {
  $resumeMarkdown.css({
    display: 'none'
  })
  $resumeWrap.addClass(iClass)
  $resumetag.html(marked(resumeMarkdown)) // 借助marked东西将markdown转化为html
  callback && callback() // 实行后续的回调
}

const showResume = (callback) => { // 道理基本上同stylesEditor, 不停地往简历编辑的容器中塞入事前准备好的简历内容,当悉数塞入的时刻再封闭定时器,并实行后续的回调操纵
  clearInterval(timer)
  timer = setInterval(() => {
    currentMarkdown += resumeMarkdown.substring(start, start + 1)
    if (currentMarkdown.length === length) {
      clearInterval(timer)
      callback && callback()
    } else {
      $resumeMarkdown.html(currentMarkdown)
      start++
    }
  }, delay)
}

app(进口模块)

末了由app进口模块将以上几个模块整合完成项目的功用,我们找出个中的中心代码来, ?,你没看错,传说中的回调地狱,亮瞎了我的狗眼啊。想必人人和我一样都是不愿意看到这坨恶心的代码的,但关于处置惩罚异步题目,回调又的确是一直以来的处理方案之一。

由于定时器的操纵是异步行动,而我们的简历天生历程会涉及到多个异步操纵,所以为了看到如首页预览链接的效果,必需等前一个步骤完成以后,才实行下一步步骤,这里起首运用的回调函数的处理方案,人人可以从github上拉取代码,离别切换以下几个分支来检察差别的处理方案

  1. master(运用回调函数处置惩罚)

  2. promise(运用promise处置惩罚)

  3. generator-thunk(运用generator + thunk函数处置惩罚)

  4. generator-promise(运用generator + promise处置惩罚)

  5. async(运用async处置惩罚)

《用原生js写一个

showStyles(0, () => {
  showResume(() => {
    showStyles(1, () => {
      markdownToHtml(() => {
        showStyles(2)
      })
    })
  })
})

处理回调地狱之promise

回调体式格局可以处理异步操纵题目,然则代码写起来异常的不美观,可读性差,代码呈横向生长趋势…巨大的程序员们开疆扩土发清楚明了promise的处理方案。我们来看一下promise分支中app模块终究的写法

showStylesWrap(0)
  .then(showResumeWrap)
  .then(showStylesWrap.bind(null, 1))
  .then(markdownToHtmlWrap)
  .then(showStylesWrap.bind(null, 2))

可以看到,代码清新了许多,纵向生长,运用第一步第二步第三步…一眼就可以看出来,固然完成的逻辑是将本来的相干的模块用Promise包装起来,而且在本往返调函数实行的处所resolve即可,细致完成,迎接检察项目源码

处理回调地狱之generator-thunk,generator-promise

两种体式格局比较相似,都要用到es6中的generator。关于什么是generator,thunk函数,可以检察软大神关于ECMAScript 6 入门,这里简要地报告一下,其怎样处置惩罚异步操纵题目使得可以将异步行动写起来如同步般爽。

function timeOut1 () {
  setTimeout(() => {
    console.log(1111)
  }, 1000)
}

function timeOut2 () {
  setTimeout(() => {
    console.log(2222)
  }, 200)
}

function * gen () {
  yield timeOut1()
  yield timeOut2()
}

let g = gen()
g.next()
g.next()

上面的代码在过了200毫秒会log出2222,过了1秒钟以后log出1111

这,要?了,你不是说generator写起来同步可以处理异步题目吗,为毛这里timeOut2没有在timeOut1以后实行呢,毕竟gen函数中看起来是愿望如许的嘛。

实在不然,timeOut2啥时刻实行取决于

g.next()
g.next()

试想两个函数险些同时实行,那在定时器中固然是200毫秒后的timeOut2先打印出2222来,然则有没有办法,让timeOut2在timeOut1后实行呢?答案是有的

function timeOut1 () {
  setTimeout(() => {
    console.log(1111)
    g.next()
  }, 1000)
}

function timeOut2 () {
  setTimeout(() => {
    console.log(2222)
  }, 200)
}

function * gen () {
  yield timeOut1()
  yield timeOut2()
}

let g = gen()
g.next()

可以看到我们在timeOut1实行完成以后,再将指针指向下一个位置,即timeOut2再去实行,如许的效果就和gen函数中两个yield的写起来同步觉得一样了。然则含有一个题目,假如涉及到许多个异步操纵,我们是很难经由过程上面的体式格局将异步流程治理起来的。因而我们须要做下面一件事

function co (fn) {
  var gen = fn();

  function next(err, data) {
    var result = gen.next(data);
    if (result.done) return;
    result.value(next); // thunk和promise差别处所之一在这里, promise是result.value.then(next)
  }

  next();
}

内部的next函数就是 thunk 的回调函数。next函数先将指针移到 generator 函数的下一步(gen.next要领),然后推断 generator 函数是不是完毕(result.done属性),假如没完毕,就将next函数再传入 thunk 函数(result.value属性),不然就直接退出。

末了我们在看一下经由过程co函数的写法完成上面的例子

function timeOut1() {
  return (callback) => {
    setTimeout(() => {
      console.log(1111)
      callback()
    }, 1000)
  }

}

function timeOut2() {
  return (callback) => {
    setTimeout(() => {
      console.log(2222)
      callback()
    }, 200)
  }
}

function co(fn) {
  var gen = fn();

  function next(err, data) {
    var result = gen.next(data);
    if (result.done) return;
    result.value(next); // thunk和promise差别处所之一在这里, promise是result.value.then(next)
  }

  next();
}

co(function * () {
  yield timeOut1()
  yield timeOut2()
})

处理回调地狱之async

async实在就是generator函数的语法糖。人人假如把generator弄邃晓了,运用它肯定不再话下,关于这个项目的用法,迎接检察async分支源代码,这里不再赘述。

尾述

本文中能够存在论述不当的处所,迎接人人斧正。???,末了点个赞,点个star好不好呀。

源码地点

    原文作者:谦龙
    原文地址: https://segmentfault.com/a/1190000009269321
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞