骨架屏作为spa中路由切换的加载,结合组件的生命周期和ajax请求返回的时机。(用作加载)。作为与用户关系最密切的前端开发者,用户体验是最值得关注的。关于页面加载状态的展示,主流的主要有加载图和进度条两种。此外,越来越多的APP采用“骨架屏”的方式展示卸载的内容,给用户带来全新的体验。作为首屏渲染,优化Vue架构骨架屏思路大纲定义一个抽象组件,在抽象组件的render函数中获取插槽深度,循环遍历插槽,为每个元素添加gm-skeleton的类名,而预先将vnodetextContent清空后,出现骨架屏时默认不会出现文字。返回slots定义一个抽象组件。什么是抽象组件?它将在渲染过程中被跳过,只执行运行时操作。exportdefault{name:'GmSkeleton',abstract:true//抽象组件的属性}获取插槽并初始化骨架屏render(h){constslots=this.$slots.default||[h('')]this.$nextTick().then(()=>{this.handlerPrefix(slots,this.showSpin?this.addSkeletPrefix:this.removeSkeletPrefix)})returnslots.length>1?h('div',{staticClass:this.showSpin?'g-spinner':''},slots):slots}这里我们将处理槽的方法放在nextTick中,因为需要在handlerPrefix中获取真正的DOM,nextTick用于执行排序更新队列中的所有方法。在执行render之前,GMSkeleton组件的renderWatcher已经被收集到updatequeue中,所以在此时定义的nextTickCallBack函数中可以获取到渲染后对应slot中的所有真实DOM。不了解nextTick原理的请移步不知道的nextTick循环slots操作类.componentInstance||{})._vn颂||{}).componentOptions||{}).childrenconstcompchildren=((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=>{varchildren=slot.children||(slot.componentOptions||{}).children||((slot.componentInstance||{})._vnode||{}).childrenif(slot.data){if(!slot.componentOptions){!init&&handler(slot)}elseif(!this.$hoc_utils.getAbstractComponent(slot)){;(function(slot){consthandlerComponent=this.handlerComponent.bind(this,slot,handler,init)constinsert=(slot.data.hook||{}).insert;(slot.data.hook||{}).insert=()=>{//函数重组,修改原来的组hook,并确保插入仅执行一次insert(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.textContentslot.elm.textContent=''}else{slot.elm.textContent=slot.memorizedtextContent||插槽.elm.textContent||slot.原生HTML元素。只有组件vnode才会有componentOptions属性来判断是否是抽象组件。我们知道,抽象的组件不会在真实的DOMTree上渲染,比如keep-alive、transition,每个组件vnode都有唯一的hooks。周期:init(初始化)、insert(插入)、prepatch(更新)、destroy(销毁),每个生命周期会在不同阶段触发,劫持insert,保留原有的insert方法,然后重构vnode中的insert方法调用handlerComponent方法添加类名,这里是上面mounted的nextTick用法的概念类似。由于handlerComponent需要知道子组件的实例,所以必须在实例化后调用,而组件的init方法会实例化组件,直接调用watcher.update(watcher.render()),也就是我们在调用insert方法其实是在update(render())之后,所以这里可以拿到实例化后的子组件来判断nodeType是否为文本节点。如果是的话,需要先保存textContent,然后再删除,保证不会出现骨架屏。将显示默认文本。当骨架屏消失时,之前保留的默认文本会返回给vnode,这样你就可以在骨架屏的显示和隐藏之间自由切换。vnode的静态类名addSkeletPrefix(slot){constrootVnode=slot.组件选项?(slot.componentInstance||{})._vnode||{}:投币口;如果(rootVnode.elm){rootVnode.elm.classList.add(this.skeletPrefix)}else{;(rootVnode.data||{}).staticClass+=`${this.skeletPrefix}`}},removeSkeletPrefix(slot){constrootVnode=slot.componentOptions?(slot.componentInstance||{})._vnode||{}:投币口;if(rootVnode.elm){rootVnode.elm.classList&&rootVnode.elm.classList.remove(this.skeletPrefix)}elseif(rootVnode.data.staticClass){rootVnode.data.staticClass=rootVnode.data.staticClass.replace(`${你s.skeletPrefix}`,'')}}addSkeletePrefix用于添加gm-skeleton类名,removeSkeletonPrefix用于删除gm-skeleton类名usingimportVuefrom'vue'importGMSkeletonfrom'path/to/GMSkeleton'Vue.use(GMSkeleton)
