内容简介:原理很简单,一个闭包,逐一截取字符串,只要在字符串开始渲染时,在创建一个
原理很简单,一个闭包,逐一截取字符串, setTimeout
渲染在页面上即可
/** * @param {HTMLElement} container - 渲染字符的容器 * @param {string} text - 需要渲染的字符串 */ function loadItem(container, text) { let num = 0 let sum = text.length let interval = 16 const startLoad = () => { setTimeout(() => { num += 1 if (num <= sum) { let str = text.substr(0, num) container.scrollTop = 100000 container.innerHTML = str setTimeout(() => { startLoad() }, interval) } }, interval) } startLoad() } 复制代码
html
上的 CSS
字符自动生效
只要在字符串开始渲染时,在 html
中添加一个 style
标签,将渲染的 CSS
代码写入到标签中即可
创建一个 style
标签
function getStyleEl() { let newStyle = document.createElement('style') let head = document.querySelector('head') head.appendChild(newStyle) let allStyle = document.querySelectorAll('style') return allStyle[allStyle.length - 1] } 复制代码
将 CSS
代码写入
/** * * @param {string} style - CSS 代码 * @param {HTMLElement} el - 创建的 style 标签 */ function handleStyle(style, el) { el.innerHTML = style } 复制代码
CSS
代码高亮, markdown
自动转换
这里需要借助 prismjs
和 marked
两个代码处理库(当然也可以用其他的)
需要在上述的 loadTtem
函数中添加判断
let code switch (type) { case 'css': handleStyle(str, styleEl) code = Prism.highlight(str, Prism.languages.css) break case 'md': code = marked(str) break } 复制代码
进阶处理
分析
基本的核心功能已经准备好了
下面我们开始分析过程,开始编写代码
需求如下:
- 支持多段动画加载
- 支持动画跳过(直接加载完成)
- 移动端特殊处理
基于上述需求,我们需要先对接口进行定义
我们设想函数是这样使用的
/** * @param {HTMLElement} container - 字符渲染的容器 * @param {Object} options - 动画参数 * * @param {string} options.content.load - 需要渲染的字符串 * @param {'css' | 'md'} options.content.type - 渲染后高亮的方式,当前仅支持 'css' | 'md' 两个参数 * @param {string} options.content.id - 渲染容器的 id * @param {boolean} options.content.rewrite - 是否需要重写 * * @param {Object}? options.mobileAnimate - 移动端需要特殊处理 * @param {string} options.mobileAnimate.styleID - css 加载的容器 ,id 应与 content 中 css 容器的 id 相同 * @param {string} options.mobileAnimate.string - markdown 加载的容器,id 应与 content 中 md 容器的 id 相同 */ let ar = new AnimateResume(container, { content:[ { load:'', type:'css', id:'', rewrite:'', }, ... ], mobileAnimate:{ styleID:'', resumeID:'' } }) ar.animate() ar.skip() 复制代码
使用前需要实例化一个并传入参数,通过 animate
方法开始动画, skip
方法跳过动画
根据上述参数设想,我们可以写出如下的 typescript
接口,不了解 typescript
的同学可以直接跳过,只看上面代码的注释即可
interface Core { container: Element options: CoreOptions isSkip: boolean animate: () => void skip: () => void } interface CoreOptions { content: Array<LoadParams> mobileAnimate?: { styleID: string resumeID: string } } interface LoadParams { load: string type: 'css' | 'md' id: string rewrite?: boolean } 复制代码
实现
基本的架构已经分析好了,现在可以开始实现了
逐一加载
首先,因为动画是多段完成的,所以我们通过参数 content
传入的是一个二维数组,其中每个 item 存放着我们想要加载的内容和对应要求,如何让动画一段一段的完成呢?很自然的能想到 Promise
方法,通过 Promise.then()
来实现。
所以我们可以将这个需求抽象为:一个未知长度的数组,需要逐一的在未知时间后加载下一项。
实现也很简单,代码如下:
function load(contents) { if (contents.length) { this.loadItem(contents[0]) .then(() => this.load(contents.slice(1))) } } 复制代码
可以想到,上述中的 loadItem
方法应该返回一个 new Promise
,内部当字符串加载完成后返回 resolve()
,然后继续执行下一段 load
方法
支持跳过
如何才能中断当前的动画,直接加载完成呢?
最初我尝试直接暴力的通过在 loadItem
时检查加载字数和一个全局变量来判断是否 setTimeout
,
但很明显这么做及其不优雅,而且有 bug(但我忘了是什么 bug 了...)。
优雅实现:在类中声明 this.isSkip = false
(相当于全局变量),在 skip()
方法调用时,将其改变为 true,在 loadItem
中 setTimeout
前检查该变量,如果为 true 则抛出 reject()
所以上述的 load
方法需要添加变为:
function load(contents) { if (contents.length) { this.loadItem(contents[0]) .then(() => this.load(contents.slice(1))) .catch(() => this.skipAnimate()) } } 复制代码
skipAnimate
即为对应的跳过动画方法
移动端处理
没有动图…… 请点击预览在手机或者谷歌调试中自行查看
展示样式我们可以直接在渲染的 CSS
代码动画中自定义,所以不过多解释
这里只说一下两个页面上下滑动的效果实现
我们需要借助 better-scroll
插件来帮助优化,分别设置上部分页面上拉刷新事件和下部分页面的下拉刷新事件,在对应事件触发时,通过 transform:translateY(x)
来实现页面的整体滑动,代码如下
let styleScroll = new BScroll(styleContainer, { pullUpLoad: { threshold: 20 } }) let mdScroll = new BScroll(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() }) 复制代码
需要注意的是如果下方简历内容长度不够,不会触发 better-scroll
的滑动检测,导致无法出现预想的滑动效果。
标点处理
根据传入的字符来判断下一个字符出现的延迟时间,即 setTimeout
方法的第二个参数。
function getInterval(str: string, interval = 16): number { if (/\D[\,]\s$/.test(str)) return interval * 20 if (/[^\/]\n\n$/.test(str)) return interval * 40 if (/[\.\?\!]\s$/.test(str)) return interval * 60 return 0 } 复制代码
参考自 github.com/STRML/strml… ,算是拾人牙慧了。
结束
基本的实现思路已经说完,具体的代码贴上来实在是篇幅太长,请 查看源码 。
不了解 typescript
的同学可以看 这里
,这是我年初时用 js
写的,不过算是面向过程编写,没有做过多的封装处理。
写在最后
第一次见到strml.net/ 时,是在初学前端大概三四个月的样子,当时看到这样的展现形式着实是被惊艳到了,那时还是个小白,连 highlight
这样的插件都不知道,更不知道还能在 style
里自定义东西,更更更不知道网站下面就放着 View Source
这么个大字,只是一心想的要自己也写一个,就那么硬生生自己写正则,通过不同的特殊符号加载对应的标签处理变色,再通过 `dom.style....=...' 设置样式,然后居然还写的有模有样,第一次找工作时还居然敢拿出来给面试官看了(笑)。
年初的时候试着重写了这个项目,感觉已是没有什么难度了,不过也是面向过程,一顿操作罢了。这些天初学 typescript
想着拿个什么东西练个手,所以又把这个项目用 ts
重构了,并且进一步的进行了封装。感觉可以出来溜溜了,所以写下了这篇文章。
以上所述就是小编给大家介绍的《又双叒叕是一个动态简历》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- 讲讲如何制作一份出彩的个人简历,我就是靠这份简历拿到鹅厂 offer 的
- java高级程序员如何写好简历,一份优秀的程序员简历是什么样的?
- 实战项目之自动简历
- 简历自述
- 2019 面试系列 - 简历
- 简历要怎么写
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。