先看效果请点这里看预览这里是代码你看过了吗?别去,这就是区别。优化移动端体验。支持动画跳过。支持多段动画标点字符。特殊处理,停留时间略长于角色时间。Typescript写函数封装函数,可以直接引入使用基本的准备好的字符。一一弹出效果的实现原理很简单,一个闭包,一一拦截字符串,设置页面渲染超时/***@param{HTMLElement}container-渲染字符的容器*@param{string}text-需要渲染String*/functionloadItem(container,text){letnum=0letsum=text.lengthletinterval=16conststartLoad=()=>{setTimeout(()=>{num+=1if(num<=sum){letstr=text.substr(0,num)container.scrollTop=100000container.innerHTML=strsetTimeout(()=>{startLoad()},interval)}},interval)}startLoad()}html上面的CSS字符会自动生效。只需要在字符串开始渲染的时候在html中添加一个style标签,将渲染后的CSS代码写入标签中,就可以创建一个style标签。functiongetStyleEl(){letnewStyle=document.createElement('style')lethead=document.querySelector('head')head.appendChild(newStyle)letallStyle=document.querySelectorAll('style')返回allStyle[allStylee.length-1]}将CSS代码写入/****@param{string}style-CSS代码*@param{HTMLElement}el-创建的样式标签*/functionhandleStyle(style,el){el.innerHTML=style}CSS代码高亮,markdown自动转换这里需要用到两个代码处理库,prismjs和marked(当然也可以用其他的)。上面的loadTtem函数需要加上判断letcodeswitch(type){case'css':handleStyle(str,styleEl)code=Prism.highlight(str,Prism.languages.css)breakcase'md':code=marked(str)break}高级处理分析基本核心功能准备好了,下面开始分析过程中,开始写代码的要求如下:支持多段动画加载支持动画跳转(直接加载完成)移动端特殊处理基于以上需求,我们需要先定义接口。我们想象函数是这样使用的呈现*@param{'css'|'md'}options.content.type-渲染后高亮的方式,目前只支持'css'|'md'两个参数*@param{string}options.content.id-渲染容器的id*@param{boolean}options.content.rewrite-是否需要重写**@param{Object}?options.mobileAnimate-Mobile需要特殊处理*@param{string}options.mobileAnimate.styleID-由css加载的容器,id应该与con相同tent中css容器的id是一样的*@param{string}options.mobileAnimate.string-markdown加载的容器,id要和content中md容器的id一样*/letar=newAnimateResume(container,{content:[{load:'',type:'css',id:'',rewrite:'',},...],mobileAnimate:{styleID:'',resumeID:''}})ar.animate()ar.skip()使用前需要实例化一个并传入参数,通过animate方法启动动画,根据上面的参数跳过动画,我们可以写出如下typescript接口,不懂typescript的同学可以直接跳过,直接看上面的代码可以注释掉{content:ArraymobileAnimate?:{styleID:stringresumeID:string}}interfaceLoadParams{load:stringtype:'css'|'md'id:stringrewrite?:boolean}基本架构已经分析完了,现在我们可以开始一个一个先加载了,因为动画是分多段完成的,所以我们通过参数内容传入的是一个二维数组,其中每一项存储我们要加载的内容和对应的需求。如何逐段完成动画?很自然的会想到Promise方法,它是通过Promise.then()来实现的,那么我们可以把这个需求抽象为:一个未知长度的数组,在未知的时间之后需要一个一个的加载下一项。实现也很简单,代码如下:functionload(contents){if(contents.length){this.loadItem(contents[0]).then(()=>this.load(contents.slice(1)))}}可以想象,上面的loadItem方法应该返回一个新的Promise,在加载字符串时内部返回resolve(),然后继续执行下一段。load方法支持跳过。如何打断当前动画,直接完成加载?一开始我尝试在loadingItem的时候直接检查加载的字数和一个全局变量来判断是否setTimeout,但是很明显这样不优雅,而且有bug(但是忘记是什么bug了。。。).优雅实现:在类中声明this.isSkip=false(相当于一个全局变量),在调用skip()方法时将其改为true,在loadItem中setTimeout前检查变量,并抛出reject(),所以上面的load方法需要添加到:functionload(contents){if(contents.length){this.loadItem(contents[0]).then(()=>this.load(contents.slice(1))).catch(()=>this.skipAnimate())}}skipAnimate就是对应的跳过动画方法。移动端没有动画...请点击预览在手机或谷歌调试中自行查看显示样式。我们可以直接在渲染出来的CSS代码动画中自定义,这里就不多解释了。这里只讲两个页面上下滑动的效果。我们需要使用better-scroll插件来帮助优化,分别在页面上部和页面下部设置上拉刷新事件。下拉刷新事件,当触发相应事件时,通过transform:translateY(x)实现页面的整体滑动,代码如下letstyleScroll=newBScroll(styleContainer,{pullUpLoad:{threshold:20}})letmdScroll=newBScroll(mdContainer,{pullDownRefresh:{threshold:20,}})styleScroll.on('pullingUp',function(){mdContainer.style.transform='translateY(calc(-100%-4rem)))'styleContainer.style.transform='translateY(calc(-100%-1rem))'styleScroll.finishPullUp()})mdScroll.on('pullingDown',function(){mdContainer.style.transform='translateY(0)'styleContainer.style.transform='translateY(0)'mdScroll.finishPullDown()})需要注意的是如果下面的简历内容不长enough,thebetter不会触发-scroll的滑动检测使得预期的滑动效果无法实现。标点处理根据传入字符判断下一个字符出现的延迟时间,即setTimeout方法的第二个参数。functiongetInterval(str:string,interval=16):number{if(/\D[\,]\s$/.test(str))返回区间*20if(/[^\/]\n\n$/.test(str))returninterval*40if(/[\.\?\!]\s$/.test(str))returninterval*60return0}参考自https://github.com/STRML/strm...,也算是捡人牙吧。结束基本的实现思路说完了,具体代码太长就不贴了,请查看源码。不懂typescript的同学可以看这里。年初的时候用js写的,但是写的是面向过程的,没有过多的封装。写在上次第一次看到http://strml.net/,初学前端大概三四个月吧。当时看到这样的展示形式,着实惊叹不已。那时我还是个菜鸟。更不知道highlight之类的插件,更不知道style里可以自定义东西,更不知道网站下有ViewSource这么大的字眼。只想自己写一个,生生自己写规则好难,通过不同的特殊符号加载对应的标签来处理变色,然后通过`dom.那个时候就敢给面试官看(笑)。今年年初,我尝试重写这个项目。感觉不难,但是也是面向过程的,只是一次性操作。这几天初学typescript想练练手,于是用ts重构了这个项目,进一步封装。感觉可以出来溜溜了,所以写了这篇文章。