Use of frame screen
- Loading is used as a route switch in a SPA in combination with the component’s life cycle and the timing of an Ajax request’s return. As the front-end developer with the closest connection to the user, the user experience is the most important concern. There are two main ways to display page loading state: loading chart and progress bar. In addition, more and more apps are using “skeleton screens” to display unloaded content, giving users a completely new experience.
- Optimized as the first screen rendering
Vue framework screen
Outline of thinking
- Define an abstract component and get the slot in the Render function of the abstract component
- Deep loops through the slot, adding the gM-skeleton class name to each element
- Empty the vNode textContent so that the default text does not appear when the skeleton screen appears
- Returns the slots
Define an abstract component
What is an abstract component? Components that are skipped during rendering and only do runtime operations
export default {
name: 'GmSkeleton'.abstract: true // Abstracts the properties of the component
}
Copy the code
Get the slot and initialize the operation skeleton screen
render(h) {
const slots = this.$slots.default || [h(' ')]
this.$nextTick().then(() = > {
this.handlerPrefix(slots, this.showSpin ? this.addSkeletPrefix : this.removeSkeletPrefix)
})
return slots.length > 1 ? h('div', {
staticClass: this.showSpin ? 'g-spinner' : ' '
}, slots) : slots
}
Copy the code
Here we put the method that handles slots inside of nextTick, because handlerPrefix needs to get the real DOM, NextTick is used to execute all the methods in the sorted update queue. The GMSkeleton renderWatcher has been collected before render is executed. Therefore, defining the nextTick CallBack function at this time can fetch all the real DOM in the corresponding slot after rendering. If you do not know the nextTick principle, please move to nextTick which you do not know
Loop the slots operation class name
handlerComponent(slot, handler/* addSkeletPrefix | removeSkeletPrefix */, init) {
const originchildren = (((slot.componentInstance || {})._vnode || {}).componentOptions || {}).children
constcompchildren = ((slot.componentInstance || {})._vnode || {}).children ! init && handler(slot)if (compchildren) this.handlerPrefix(compchildren, handler, false)
if (originchildren) this.handlerPrefix(originchildren, handler, false)},handlerPrefix(slots, handler, init = true) {
slots.forEach(slot= > {
var children = slot.children || (slot.componentOptions || {}).children || ((slot.componentInstance || {})._vnode || {}).children
if (slot.data) {
if(! slot.componentOptions) { ! init && handler(slot) }else if (!this.$hoc_utils.getAbstractComponent(slot)) { ; (function(slot) {
const handlerComponent = this.handlerComponent.bind(this, slot, handler, init)
constinsert = (slot.data.hook || {}).insert ; (slot.data.hook || {}).insert =() = > { // Function refactoring to modify the original component hook and ensure that the insert is executed only onceinsert(slot) handlerComponent() } ; (slot.data.hook || {}).postpatch = handlerComponent }).call(this, slot)
}
}
if (slot && slot.elm && slot.elm.nodeType === 3) {
if (this.showSpin) {
slot.memorizedtextContent = slot.elm.textContent
slot.elm.textContent = ' '
} else {
slot.elm.textContent = slot.memorizedtextContent || slot.elm.textContent || slot.text
}
}
children && this.handlerPrefix(children, handler, false)})},Copy the code
Step by step analysis:
- We walked through the slots
- Gets the children collection under the current vNode for the next loop
- To determine if it is a native HTML element, only the component VNode has the componentOptions attribute
- Abstract components do not render to the real DOMTree, for example keep-alive and Transition. Each component’s VNode has its own hooks life cycle: Init, INSERT, prepatch, destroy, each lifecycle is triggered at a different stage, hijacking insert, preserving the original insert method, / / Mounted nextTick. / / handlerComponent needs to know the instance of its child component, so it must be called after it is instantiated. The component’s init method instantiates the component and calls watcher.update(watcher.render()) directly, which means we call insert after update(render()), so we get the instantiated child component
- Check whether nodeType is a text node. If so, save and delete textContent first to ensure that no default text will be displayed when the skeleton screen appears. When the skeleton screen disappears, return the default text to VNode, so that it can freely switch between the skeleton screen and hidden
The static class name that operates on vNode
addSkeletPrefix(slot) {
const rootVnode = slot.componentOptions ? (slot.componentInstance || {})._vnode || {} : slot;
if (rootVnode.elm) {
rootVnode.elm.classList.add(this.skeletPrefix)
} else {
;(rootVnode.data || {}).staticClass += ` The ${this.skeletPrefix}`}},removeSkeletPrefix(slot) {
const rootVnode = slot.componentOptions ? (slot.componentInstance || {})._vnode || {} : slot;
if (rootVnode.elm) {
rootVnode.elm.classList && rootVnode.elm.classList.remove(this.skeletPrefix)
} else if (rootVnode.data.staticClass) {
rootVnode.data.staticClass = rootVnode.data.staticClass.replace(` The ${this.skeletPrefix}`.' ')}}Copy the code
AddSkeletePrefix is used to add the GM-skeleton name and removeSkeletonPrefix is used to remove the GM-skeleton name
Method of use
import Vue from 'vue'
import GMSkeleton from 'path/to/GMSkeleton'
Vue.use(GMSkeleton)
Copy the code
<gm-skeleton>
<Component />
<div></div>
<div><span>The front-end Martin</span></div>
</gm-skeleton>
Copy the code
The value of
The property name | value | describe |
---|---|---|
showSpin | Boolean | Whether to enable skeleton screen. The default value is true |
skeletPrefix | String | Skeleton screen class name, default is GM-skeleton |
Results the following
The specific styles are generated according to the styles written by the developers themselves, via the GM-skeleton package, as used above, here is a simple example
Complete address
80 lines of code to implement the Vue skeleton screen
conclusion
Hope to click a like, to a concern hee hee
Wechat id: IAmFineThanksMartin