先看结果
见过了?别走,这是异乎寻常的处所
- 针对挪动端优化了体验
- 支撑动画跳过
- 支撑多段动画
- 标点字符特别处置惩罚,停留时刻略善于字符时刻
- typescript 编写
- 对功用举行了封装处置惩罚,能够直接引入运用
基础预备
字符一一弹出结果的完成
道理很简单,一个闭包,一一截取字符串,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
}
参考自 https://github.com/STRML/strm… ,算是拾人涕唾了。
完毕
基础的完成思绪已说完,详细的代码贴上来实在是篇幅太长,请检察源码。
不相识 typescript
的同砚能够看这里,这是我年终时用 js
写的,不过算是面向历程编写,没有做过量的封装处置惩罚。
写在末了
第一次见到http://strml.net/ 时,是在初学前端也许三四个月的模样,当时看到如许的展示情势着实是被冷艳到了,当时照样个小白,连 highlight
如许的插件都不晓得,更不晓得还能在style
里自定义东西,更更更不晓得网站下面就放着View Source
这么个大字,只是一心想的要本身也写一个,就那末硬生生本身写正则,经由过程差别的特别符号加载对应的标签处置惩罚变色,再经由过程 `dom.style….=…’ 设置款式,然后竟然还写的有模有样,第一次找工作时还竟然敢拿出来给面试官看了(笑)。
年终的时刻试着重写了这个项目,觉得已经是没有什么难度了,不过也是面向历程,一顿操纵罢了。这些天初学 typescript
想着拿个什么东西练个手,所以又把这个项目用 ts
重构了,而且进一步的举行了封装。觉得能够出来溜溜了,所以写下了这篇文章。