This is the fourth day of my participation in the August More text Challenge. For details, see: August More Text Challenge
0 x00 profile
This article will in-depth analysis of Backtop component source code, analysis of its implementation principle, patience to read, I believe it will be helpful to you. Component document Backtop
Packages/backtop/SRC/main. Vue file is component source code to achieve. Making the source code. The main vue
0 x01 dom structure
The template content shows that the component is a div that uses the built-in transition animation component Transition and supports slot functionality. The default value is an icon named El-icon-Caret-top.
<template>
<transition name='el-fade-in'>
<div
v-if='visible'
@click.stop='handleClick'
:style='{ right: styleRight, bottom: styleBottom, }'
class='el-backtop'
>
<slot>
<el-icon name='caret-top'></el-icon>
</slot>
</div>
</transition>
</template>
Copy the code
The transition component implements the fade in effect, and the name component automatically generates the CSS transition class name, which automatically expands to.el-fade-in-enter,.el-Fade -in-enter, and so on.
The project defines different entry and exit animations in Packages \ theme-Chalk \ SRC \common\transition. SCSS, and sets duration and animation functions.
Div element class value is el-Backtop, whose visibility is controlled by the property visible, defines the click event (the event modifier stop is used to prevent the click event from continuing to spread), uses the computed property to build the inline style, and controls how far the component is displayed from the right margin and the bottom of the page.
0 x02 attributes attribute
The component Prop provides four properties that specify validation requirements, default values, and other Settings.
props: {
visibilityHeight: {
type: Number.default: 200
},
target: [String]./ / string
right: {
type: Number.default: 40
},
bottom: {
type: Number.default: 40}},Copy the code
Where the target type is a string and the element selector for the object that triggers the scrolling is passed in for object lookup. If the element selector cannot be found, the error target is not existed: ${this.target} is displayed.
The property parameters are described as follows:
parameter | instructions | type | The default value |
---|---|---|---|
target | An object that triggers scrolling | string | |
visibility-height | The scrolling height does not appear until this parameter value is reached | number | 200 |
right | Control its display position, from the right margin of the page | number | 40 |
bottom | Controls its display position, distance from the bottom of the page | number | 40 |
Based on the values of the right and bottom attributes passed in, the computed attributes styleBottom and styleRight return ${number} PX formatted content for inline style building of the component.
computed: {
styleBottom() {
return `The ${this.bottom}px`;
},
styleRight() {
return `The ${this.right}px`; }},Copy the code
0x03 Component life cycle
The lifecycle of the component is analyzed below.
<script>
// Introduce the throttling function
import throttle from 'throttle-debounce/throttle';
const cubic = (value) = > Math.pow(value, 3);
const easeInOutCubic = (value) = >
value < 0.5 ? cubic(value * 2) / 2 : 1 - cubic((1 - value) * 2) / 2;
export default {
name: 'ElBacktop'.// ...
/ / data property
data() {
return {
el: null.// Triggers the scrolling object
container: null.// Triggers the scrolling object
visible: false // Whether the component is visible
};
},
mounted() {
// Component initialization
this.init();
// Check whether the component is visible
this.onScroll();
// Select * from 'throttling' where 'throttling' is used.
this.throttledScrollHandler = throttle(300.this.onScroll);
// Add the scroll event listener
this.container.addEventListener('scroll'.this.throttledScrollHandler);
},
methods: {
// Component initialization
init() {
// ...
},
// Check whether the component is visible
onScroll() {
// ...
},
// Click the button to trigger the event
handleClick(e) {
// ...
},
// Return to the action at the top of the page
scrollToTop() {
// ...}},// Call before instance destruction
beforeDestroy() {
// Delete the Scroll event listener
this.container.removeEventListener('scroll'.this.throttledScrollHandler); }}; </script>Copy the code
mounted()
After the component instance is mounted, init() is called, onScroll() is called, and onScroll event listener is added.
init()
Gets the object that triggers scrolling. By default, document is the object that triggers scrolling.
If the target attribute has a value passed in, it looks for a matching element and updates it to the object that triggers scrolling. If the exception is not found, target is not existed.
init() {
// Load the page DOM tree
this.container = document;
// Get the read-only attribute of the root element of the document object - root element < HTML >
this.el = document.documentElement;
// If target is specified
if (this.target) {
// The referenced querySelector() method looks for a matching HTMLElement object.
// Return null if no match is found.
this.el = document.querySelector(this.target);
// Failed to find a match, throw exception target is not existed
if (!this.el) {
throw new Error(`target is not existed: The ${this.target}`);
}
// Assign the matching element to container
this.container = this.el; }},Copy the code
onScroll()
According to the number of pixels (scrollTop) of the object that triggers scrolling, determine whether the value of the property visibilityHeight is exceeded. If it is exceeded, set the property visible value to true, and then the component is visible on the page.
onScroll() {
// Get the number of pixels that the content of an element should scroll vertically.
const scrollTop = this.el.scrollTop;
// The operation button will not appear until the scrolling height reaches this parameter value
this.visible = scrollTop >= this.visibilityHeight;
}
Copy the code
Event listeners
Add onScoll event listener for the object that triggers scrolling. When the page is scrolling, the triggered event calls onScroll(), which is used to display or hide components.
// Select * from 'throttling' where 'throttling' is used.
this.throttledScrollHandler = throttle(300.this.onScroll);
// Add the scroll event listener
this.container.addEventListener('scroll'.this.throttledScrollHandler);
Copy the code
We added a throttling function to the onScroll() method call, which only executes once for 300 milliseconds. The main thing is that scroll events are fired frequently, but sometimes you don’t want to execute functions that often while the event is firing.
beforeDestroy
Call before instance destruction to delete the scroll event listener on the object that triggers scroll.
beforeDestroy() {
// Delete the Scroll event listener
this.container.removeEventListener('scroll'.this.throttledScrollHandler);
}
Copy the code
0 x04 events event
The component provides the click event. @click.stop=’handleClick’ @click.stop=’handleClick’
handleClick(e)
First call scrollToTop() to return to the top of the page, then call this.$emit(‘click’, e) to trigger the click event on the current instance.
handleClick(e) {
// Return to the top of the page
this.scrollToTop();
// Triggers events on the current instance
this.$emit('click', e);
},
Copy the code
scrollToTop()
This method returns the top of the page by setting the scrollTop value of the target object. Ease functions and requestAnimationFrame are used to make the experience better.
scrollToTop() {
// Specify an object
const el = this.el;
// Click the button to timestamp UTC milliseconds
const beginTime = Date.now();
console.log(beginTime);
// Get the number of pixels that the content of an element should scroll vertically.
const beginValue = el.scrollTop;
const rAF =
window.requestAnimationFrame || ((func) = > setTimeout(func, 16));
const frameFunc = () = > {
const progress = (Date.now() - beginTime) / 500; // Set rate to 500 milliseconds to return to top of page
if (progress < 1) {
el.scrollTop = beginValue * (1 - easeInOutCubic(progress));
rAF(frameFunc);
} else {
// If more than 500 goes directly back to the top of the page
el.scrollTop = 0; }}; rAF(frameFunc); }Copy the code
Slow function
Ease the rate at which a user-defined parameter of a function changes over time. Easing functions allow mathematical formulas to be applied to animations.
In real life, objects don’t start or stop suddenly, and they certainly don’t keep moving at a constant speed. Just like when we open a drawer, the initial pull is quick, but when the drawer is pulled out we unconsciously slow down. Or an object that falls to the floor, it starts off falling very fast, and then it bounces back and forth across the floor until it stops.
const cubic = (value) = > Math.pow(value, 3);
const easeInOutCubic = (value) = >
value < 0.5 ? cubic(value * 2) / 2 : 1 - cubic((1 - value) * 2) / 2;
Copy the code
Equivalent TypeScript code implementation. The variable x represents values in the range 0 (start of animation) to 1 (end of animation).
function easeInOutCubic(x: number) :number {
return x < 0.5 ? 4 * x * x * x : 1 - pow(-2 * x + 2.3) / 2;
}
Copy the code
In CSS, use the Transition and animation properties. The results can be found in cubic-bezier.com.
.block {
transition: transform 0.6 s cubic-bezier(0.65.0.0.35.1);
}
Copy the code
The easing function is used to click on the component to trigger the scrollToTop method, rolling back the rate at the top of the viewport to make it look more realistic.
scrollToTop() {
// ...
el.scrollTop = beginValue * (1 - easeInOutCubic(progress));
// ...
}
Copy the code
requestAnimationFrame()
Tell the browser window. RequestAnimationFrame () – you want to perform an animation, and required the browser until the next redraw calls the specified callback function to update the animation. This method needs to be passed a callback function as an argument, which will be executed before the browser next redraw. Thus achieved through the browser optimization, animation more fluid.
RequestAnimationFrame () is implemented recursively.
const rAF =
window.requestAnimationFrame || ((func) = > setTimeout(func, 16));
const frameFunc = () = > {
// ...
rAF(frameFunc);
// ...
};
rAF(frameFunc);
Copy the code
0x05 Theme – Chalk style implemented
BEM naming conventions
Component styles use BEM naming convention, BEM naming convention [block-name]__[element-name]–[modifier-name], that is, block + element + modifier.
.block{}
.block__element{}
.block--modifier{}
Copy the code
.block
Represents a higher level of abstraction or component..block__element
A descendant of. Block, used to form a whole of. Block..block--modifier
Represents different states or versions of. Blocks.
The BEM name gives it more description and a clearer structure. From its name, you can know the meaning and function of a tag. Make front-end code easier to read and understand, easier to collaborate, easier to control, more robust and unambiguous, and more rigorous.
src/backtop.scss
SCSS generates component styles using the MIXin instructions of SCSS. With the mixin, styles can be easily shared across different parts of the style sheet. Since the DOM structure of the component is relatively simple, only @mixin b($block) is used to generate blocks.
@import "mixins/mixins";
@import "common/var";
@include b(backtop) {
position: fixed;
background-color: $--backtop-background-color;
width: 40px;
height: 40px;
border-radius: 50%;
color: $--backtop-font-color;
display: flex;
align-items: center;
justify-content: center;
font-size: 20px;
box-shadow: 0 0 6px rgba(0.0.0.12);
cursor: pointer;
z-index: 5;
// The identifier of the parent selector &
&:hover {
background-color: $--backtop-hover-background-color}}Copy the code
src/common/var.scss
Packages \ theme-Chalk \ SRC \common\var.scss defines global common style variables.
/* Backtop
--------------------------*/
/// color||Color|0
$--backtop-background-color: $--color-white! default;/// color||Color|0
$--backtop-font-color: $--color-primary! default;/// color||Color|0
$--backtop-hover-background-color: $--border-color-extra-light! default;/* Color
-------------------------- */
/// color|1|Brand Color|0
$--color-primary: #409EFF! default;/// color|1|Background Color|4
$--color-white: #FFFFFF! default;/// color|1|Border Color|3
$--border-color-extra-light: #F2F6FC! default;Copy the code
src/mixins/config.scss
Packages \ theme-Chalk \ SRC \mixins\config. SCSS defines variables for the BEM naming convention.
$namespace: 'el'; // The element namespace abbreviation
$element-separator: '__'; // Define the element separator
$modifier-separator: The '-'; // Define the state separator
$state-prefix: 'is-'; // The status prefix
Copy the code
src/mixins/mixins.scss
Packages \theme-chalk\ SRC \mixins\mixins. Define b, e, m methods in SCSS.
/* BEM -------------------------- */
@mixin b($block) {
// Global parameter declaration component class name
$B: $namespace+The '-'+$block! global; . # {$B} {
@content; }}@mixin e($element) {
// ...
}
@mixin m($modifier) {
// ...
}
Copy the code
$b: $namespace+’-‘+$block! global; =>$B:el-backtop ! global;
Using #{} interpolation directly uses variables.
$B:el-backtop ! global; . # {$B} {
@content} // compile to.el-backtop{//... }Copy the code
Use @Content to import the content into the blend style and compile the final result
.el-backtop {
position: fixed;
background-color: #fff;
width: 40px;
height: 40px;
border-radius: 50%;
color: #409eff;
display: flex;
align-items: center;
justify-content: center;
font-size: 20px;
box-shadow: 0 0 6px rgba(0.0.0.0.12);
cursor: pointer;
z-index: 5;
&:hover {
background-color: #f2f6fc; }}Copy the code
lib/backtop.css
Gulpfile.js is used to compile SCSS files and convert them into CSS. After browser compatibility and format compression, packages\theme-chalk\lib\backtop. CSS are generated.
.el-backtop {
position: fixed;
background-color: #fff;
width: 40px;
height: 40px;
border-radius: 50%;
color: #409eff;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
-webkit-box-pack: center;
-ms-flex-pack: center;
justify-content: center;
font-size: 20px;
-webkit-box-shadow: 0 0 6px rgba(0.0.0.0.12);
box-shadow: 0 0 6px rgba(0.0.0.0.12);
cursor: pointer;
z-index: 5;
}
.el-backtop:hover {
background-color: #f2f6fc;
}
Copy the code
0x06 Example
Component should be aware of the CSS properties of the object that target triggers scrolling.
<template>
<div id="app" class="app">
<div style="min-height:2400px">
<el-backtop target="#app" @click="top"
><div
style="{ height: 100%; width: 100%; background-color: #f2f5f6; Box-shadow: 0 0 6px rgba(0,0,0,.12); text-align: center; line-height: 40px; color: #1989fa; }"
>
UP
</div>
</el-backtop>
</div>
</div>
</template>
<style>
.app {
height: 100vh;
overflow-x: hidden;
}
</style>
Copy the code
0 x07 📚 reference
‘ViewPort ‘,MDN ‘requestAnimationFrame’,MDN’ Easing Function ‘, easings.net ‘BEM’,bemcss.com ‘BEM’, SegmentFault