Look at the effect
Please click here for a preview
Here’s the code
Ever seen? Don’t go. This is the difference
- Optimized experience for mobile
- Support animation skip
- Support for multiple animations
- Punctuation characters are treated specially and stay slightly longer than the character time
- Typescript write
- The function of the package processing, can be directly introduced to use
The basic preparation
Character by character pop-up effect implementation
The principle is very simple, a closure, one string at a time, setTimeout render on the page
/** * @param {HTMLElement} container - Container for rendering characters * @param {string} text - String to render */
function loadItem(container, text) {
let num = 0
let sum = text.length
let interval = 16
const startLoad = (a)= > {
setTimeout((a)= > {
num += 1
if (num <= sum) {
let str = text.substr(0, num)
container.scrollTop = 100000
container.innerHTML = str
setTimeout((a)= > {
startLoad()
}, interval)
}
}, interval)
}
startLoad()
}
Copy the code
html
On theCSS
Automatic character implementation
Just add a style tag to the HTML at the beginning of the string rendering, and write the rendered CSS code into the tag
Create a style tag
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]}Copy the code
Write the CSS code
/** ** @param {string} style - CSS code * @param {HTMLElement} el - Created style tag */
function handleStyle(style, el) {
el.innerHTML = style
}
Copy the code
CSS
Code highlighting,markdown
Automatic conversion
Use prismJS and marked code handling libraries (you can use other ones as well)
You need to add a judgment to the loadTtem function above
let code
switch (type) {
case 'css':
handleStyle(str, styleEl)
code = Prism.highlight(str, Prism.languages.css)
break
case 'md':
code = marked(str)
break
}
Copy the code
In order to deal with
Analysis of the
The basic core functions are ready
Now let’s start the analysis process and start writing code
Requirements are as follows:
- Support multiple animation loading
- Support animation skipping (direct loading complete)
- Mobile special processing
Based on the above requirements, we need to define the interface first
Let’s imagine the function being used like this
/** * @param {HTMLElement} container - Container for character rendering * @param {Object} options - Animation parameters ** @param {string} options.content.load - need to be rendered string * @ param {' CSS '|' md} options. The content. type - rendered highlight way, Currently only supports' CSS '|' md 'two parameters * @ param {string} options. The content. id - apply colours to a drawing of the container id * @ param {Boolean} options. The content. rewrite - Do I need to rewrite * * @param {Object}? Options. MobileAnimate - mobile client requires special handling * @ param {string} options. MobileAnimate. StyleID - CSS loading container, Id should be the same as the content of CSS container id * @ param {string} options. MobileAnimate. String - markdown loading container, Id should be the same as the ID of the MD container in content */
let ar = new AnimateResume(container, {
content:[
{
load:' '.type:'css'.id:' '.rewrite:' ',},... ] .mobileAnimate: {styleID:' '.resumeID:' '
}
})
ar.animate()
ar.skip()
Copy the code
Before use, you need to instantiate one and pass in parameters, start the animation with the animate method, and skip the animation
Based on these assumptions, we can write the following typescript interface, which those of you who are not familiar with typescript can skip and just look at the comments of the code above
interface Core {
container: Element
options: CoreOptions
isSkip: boolean
animate: (a)= > void
skip: (a)= > void
}
interface CoreOptions {
content: Array<LoadParams> mobileAnimate? : { styleID:string
resumeID: string}}interface LoadParams {
load: string
type: 'css' | 'md'
id: stringrewrite? :boolean
}
Copy the code
implementation
The basic architecture has been analyzed and can now be implemented
One by one to load
First of all, because the animation is done in multiple segments, we pass in the content parameter as a two-dimensional array, where each item holds the content we want to load and the corresponding requirements. How do we make the animation complete segment by segment? It’s natural to think of the Promise method, implemented through promise.then ().
So we can abstract this requirement as an array of unknown length that needs to load the next item at an unknown time.
The implementation is also very simple, the code is as follows:
function load(contents) {
if (contents.length) {
this.loadItem(contents[0])
.then((a)= > this.load(contents.slice(1)))}}Copy the code
As you can imagine, the loadItem method above should return a new Promise, internally return resolve() when the string is loaded, and then proceed to the next load method
Support to skip
How can I interrupt the current animation and finish loading directly?
I initially tried to force a setTimeout directly by checking the number of loaded words and a global variable on a loadItem, but this was obviously very inelegant and buggy (but I forget what the bug was…). .
Elegant implementation: Declare this.isskip = false (equivalent to a global variable) in a class, change it to true when the skip() method is called, check the variable before setTimeout in loadItem, and throw reject() if true
So the load method above needs to be added as:
function load(contents) {
if (contents.length) {
this.loadItem(contents[0])
.then((a)= > this.load(contents.slice(1)))
.catch((a)= > this.skipAnimate())
}
}
Copy the code
SkipAnimate is the corresponding animation skipping method
Mobile processing
No GIFs… Please click preview to view it on your phone or in Google Debug
Display styles can be customized directly in the rendered CSS code animation, so there is no explanation
I’m just going to talk about the effect of sliding two pages up and down
We need to use the better-Scroll plug-in to help optimization, and set the pull-up refresh event of the upper part of the page and the pull-down refresh event of the lower part of the page respectively. When the corresponding event is triggered, the whole page will slide through transform:translateY(x), the code is as follows
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()
})
Copy the code
It should be noted that if the length of the resume below is not enough, the better Scroll sliding detection will not be triggered, resulting in the failure of the expected sliding effect.
Punctuation handling
The second argument to the setTimeout method determines the delay for the next character based on the character passed in.
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
}
Copy the code
Reference since github.com/STRML/strml… “, sort of picked up the pieces.
The end of the
The basic implementation ideas have finished, the specific code is posted up is too long, please view the source code.
For those of you who aren’t familiar with typescript, this is what I wrote in JS earlier this year, but it’s procedural and doesn’t encapsulate too much.
Write in the last
The first time I saw strml.net/ I was about three or four months in the beginning of the front-end and it was amazing to see it in this format. I was a kid at the time, I didn’t even know about the highlight plugin, let alone the ability to customize things in style. More and more do not know the website below put View Source so a big word, just want to write a, so hard to write their regular, through different special symbols to load the corresponding label processing color, and then through ‘dom.style…. =… ‘Set it up, and then write it up, and then show it to the interviewer the first time I applied for a job [laughs].
At the beginning of the year, I tried to re-write this project. I felt that it was not difficult, but it was also process-oriented and an operation. As a beginner of typescript these days, I wanted to get my hands on something, so I refactored the project into TS and further encapsulated it. I felt I could walk out, so I wrote this article.