background
Recently, I met a requirement in a project, and I need to make an animation effect of amount switching for the trial calculation after selecting coupons, as shown in the figure:
Then I made a few small demos to demonstrate:
technology
This effect uses the cSS3 transition property
The transition property sets the element’s four short properties for transition effects:
value | describe |
---|---|
transition-property | Specify the name and transition effect of the CSS property |
transition-duration | The transition effect takes a specified number of seconds or milliseconds to complete |
transition-timing-function | Specifies the rotation speed curve for the transition effect |
transition-delay | Define when the transition effect starts |
implementation
I list all the numbers from 0 to 9 in a row, and then locate the number column according to the numbers that need to be displayed, and then use the transition effect to achieve the number switching animation. As shown in the figure:
layout
The first is the layout code, which arranges the numbers from 0 to 9
<div className="number-animation-wrap">
<div className="number-animation-wrap-hidden">0</div>
<div className="number-animation" style={style}>
<div className="number">0</div>
<div className="number">1</div>
<div className="number">2</div>
<div className="number">3</div>
<div className="number">4</div>
<div className="number">5</div>
<div className="number">6</div>
<div className="number">7</div>
<div className="number">8</div>
<div className="number">9</div>
</div>
</div>
Copy the code
style
Set style: overflow: Hidden; Out of hiding Transition: Top 0.2s for transition animation
@defaultSize: 16; .number-animation-wrap { position: relative; display: inline-block; overflow: hidden; .number-animation { position: absolute; left: 0; top: 0; height: auto; transform-origin: 0 0; The transition: top 0.2 s; }. Number,. Number-animation-wrap-hidden {line-height: unit((36/ @defaultsize),rem); font-size: unit((36/@defaultSize),rem); font-weight: bold; text-align: center; } .number-animation-wrap-hidden{ visibility: hidden; }}Copy the code
Control positioning
Calculate the offset distance according to the value of the number to be displayed, use top to locate the number list in the layout, and display the corresponding number:
let style = {
top: (-1 * value * this.lineHeight / this.defaultSize) + 'rem'
}
Copy the code
Styles are dynamically generated and set to the number list div as the value changes
<div className="number-animation" style={style}>
Copy the code
call
I’ve packaged it as a component that can be easily called and assembled as needed:
import NumberAnimation from ".. /.. /src/numberAnimation"; <div style={{textAlign:"center",fontSize: "36px",fontWeight: "Bold "}}> <div style={{margin:"2rem 0"}}> countdown <NumberAnimation Value ={this.state.number} /> </div> <div Style = {{margin: "rem 2 0}} > {time. This state. Number2. ToFixed (2). The toString (). The replace (".", ":"). The split (" "). The map ((numberItem, index) => { return ( <NumberAnimation key={index} value={numberItem} /> ) }) } </div> <div style={{margin:"2rem 0"}}> Access number {this. State. Number4. ToString (). The split (" "). The map ((numberItem, index) => { return ( <NumberAnimation key={index} value={numberItem} /> ) }) } </div> <div style={{margin:"2rem 0"}}> { this.state.number.toString().split("").map((numberItem, index) => { return ( <NumberAnimation key={index} value={numberItem} /> ) }) } </div> <div style={{margin:"2rem 0"}}> { this.state.number2.toFixed(2).toString().split("").map((numberItem, index) => { return ( <NumberAnimation key={index} value={numberItem} /> ) }) } </div> <div style={{margin:"2rem 0"}}> { this.state.number3.toFixed(2).toString().split("").map((numberItem, index) => { return ( <NumberAnimation key={index} value={numberItem} /> ) }) } <button onClick={()=>{this.setState({ Number3: Math. The random () * Math. The random () * 100})}} > click switch Numbers < / button > < / div > < / div >Copy the code
All the code
Js file
//numberAnimationPage.js import React, { Component } from 'react'; import './style.less' class NumberAnimation extends Component { constructor(props) { super(props); this.lineHeight = 36; this.defaultSize = 16; } render() { const { value } = this.props; If (isNaN(value)) {// non-numeric return (<div className="number-animation-wrap"> <div className="number-animation-wrap-hidden">.</div> <div className="number-animation"> <div className="number">{value}</div> </div> </div> ) } let style = { top: (-1 * value * this.lineHeight / this.defaultSize) + 'rem' } return ( <div className="number-animation-wrap"> <div className="number-animation-wrap-hidden">0</div> <div className="number-animation" style={style}> <div className="number">0</div> <div className="number">1</div> <div className="number">2</div> <div className="number">3</div> <div className="number">4</div> <div className="number">5</div> <div className="number">6</div> <div className="number">7</div> <div className="number">8</div> <div className="number">9</div> </div> </div> ) } } export default NumberAnimation;Copy the code
The style file
//style.less @defaultSize: 16; .number-animation-wrap { position: relative; display: inline-block; overflow: hidden; .number-animation { position: absolute; left: 0; top: 0; height: auto; transform-origin: 0 0; The transition: top 0.2 s; }. Number,. Number-animation-wrap-hidden {line-height: unit((36/ @defaultsize),rem); font-size: unit((36/@defaultSize),rem); font-weight: bold; text-align: center; } .number-animation-wrap-hidden{ visibility: hidden; }}Copy the code
Invoke sample file
//numberAnimationPage.js import React, { Component } from "react"; import NumberAnimation from ".. /.. /src/numberAnimation"; class NumberAnimationPage extends Component { constructor(props) { super(props); this.state = { number: 0, number2: 0, number3: 0 }; this.number = 0; this.number2 = 0; } componentDidMount() { setInterval(() => { console.log(1) this.setState({ number: this.number++, number2: This.number2 += 0.01})}, 1000) } render() { return ( <div style={{textAlign:"center"}}> <div style={{margin:"2rem 0"}}> <NumberAnimation value={this.state.number} /> </div> <div style={{margin:"2rem 0"}}> { this.state.number.toString().split("").map((numberItem, index) => { return ( <NumberAnimation key={index} value={numberItem} /> ) }) } </div> <div style={{margin:"2rem 0"}}> { this.state.number2.toFixed(2).toString().split("").map((numberItem, index) => { return ( <NumberAnimation key={index} value={numberItem} /> ) }) } </div> <div style={{margin:"2rem 0"}}> { this.state.number3.toFixed(2).toString().split("").map((numberItem, index) => { return ( <NumberAnimation key={index} value={numberItem} /> ) }) } <button onClick={()=>{this.setState({ Number3: Math. The random () * Math. The random () * 100})}} > click switch Numbers < / button > < / div > < / div >). } } module.exports = NumberAnimationPage;Copy the code
conclusion
- This component is presented in the form of a single number and can be flexibly assembled by users
- Component filter the case that the incoming value is not numeric, support to display integer, decimal
If you have any suggestions or other implementation ideas, please share them in the comments section.