九色国产,午夜在线视频,新黄色网址,九九色综合,天天做夜夜做久久做狠狠,天天躁夜夜躁狠狠躁2021a,久久不卡一区二区三区

打開APP
userphoto
未登錄

開通VIP,暢享免費(fèi)電子書等14項(xiàng)超值服

開通VIP
骨架屏技術(shù)講解以及如何在Vue中實(shí)現(xiàn)骨架屏

寫在前面

現(xiàn)在的前端開發(fā)領(lǐng)域,都是前后端分離,前端框架主流的都是 SPA,MPA;這就意味著,頁面渲染以及等待的白屏?xí)r間,成為我們需要解決的問題點(diǎn);而且大項(xiàng)目,這個(gè)問題尤為突出。

webpack 可以實(shí)現(xiàn)按需加載,減小我們首屏需要加載的代碼體積;再配合上 CDN 以及一些靜態(tài)代碼(框架,組件庫等等…)緩存技術(shù),可以很好的緩解這個(gè)加載渲染的時(shí)間過長(zhǎng)的問題。

但即便如此,首屏的加載依然還是存在這個(gè)加載以及渲染的等待時(shí)間問題;

骨架屏是什么

目前主流,常見的解決方案是使用骨架屏技術(shù),包括很多原生的APP,在頁面渲染時(shí),也會(huì)使用骨架屏。(下圖中,紅圈中的部分,即為骨架屏在內(nèi)容還沒有出現(xiàn)之前的頁面骨架填充,以免留白

如何實(shí)現(xiàn)(原理分析)

在 Vue 中,我們是通過 $mount 實(shí)例方法去掛載 vm 的;我們來簡(jiǎn)單看一下 Vue 代碼里面關(guān)于 $mount 方法的實(shí)現(xiàn):

const mount = Vue.prototype.$mountVue.prototype.$mount = function (  el?: string | Element,  hydrating?: boolean): Component {  el = el && query(el)  /* istanbul ignore if */  if (el === document.body || el === document.documentElement) {    process.env.NODE_ENV !== 'production' && warn(      `Do not mount Vue to <html> or <body> - mount to normal elements instead.`    )    return this  }  const options = this.$options  // resolve template/el and convert to render function  if (!options.render) {  	...  }  return mount.call(this, el, hydrating)}

我們可以看到:這段代碼首先緩存了原型上的 $mount 方法,再重新定義該方法,我們先來分析這段代碼。首先,它對(duì) el 做了限制,Vue 不能掛載在 body、html 這樣的根節(jié)點(diǎn)上。為什么??

因?yàn)閞ender生成的vNode,通過 $mount 方法,掛載在我們的定義的 DOM 元素上;這里的掛載是【替換】的意思。

默認(rèn)情況下我們的模版 index.html 里面有一個(gè) id 為 app 的 div 元素。我們最終的應(yīng)用程序代碼會(huì)替換掉這個(gè)元素,也就是 <div id="app"></div>;對(duì),我們 Vue 渲染出來的內(nèi)容是替換掉它,而不是插入在這個(gè)節(jié)點(diǎn)中。

這也就是 Vue 不能掛載在 body、html 這樣的根節(jié)點(diǎn)的原因。你總不能把 body、html 這樣的元素節(jié)點(diǎn)替換掉把。

知識(shí)點(diǎn)補(bǔ)充:
如果沒有定義 render 方法,則會(huì)把 el 或者 template 字符串轉(zhuǎn)換成 render 方法。這里我們要牢記,在 Vue 2.0 版本中,所有 Vue 的組件的渲染最終都需要 render 方法,無論我們是用單文件 .vue 方式開發(fā)組件,還是寫了 el 或者 template 屬性,最終都會(huì)轉(zhuǎn)換成 render 方法,那么這個(gè)過程是 Vue 的一個(gè)“在線編譯”的過程,它是調(diào)用 compileToFunctions 方法實(shí)現(xiàn)的。最后,調(diào)用原先原型上的 $mount 方法掛載。

參考: Vue 實(shí)例掛載的實(shí)現(xiàn)

一個(gè)生動(dòng)的例子

我們模版(index.html)里面的內(nèi)容是這樣的:

<body>  <div id="app">    <span style="color: red;font-size: 34px;">你好</span>  </div>  <!-- built files will be auto injected --></body>

模版里面的掛載點(diǎn)是 div#app,App.vue 里面的根節(jié)點(diǎn)是 div#app-two,渲染完成以后,頁面上的 div#app 就變成了 div#app-two。

那么,這里分析總結(jié)出來的最重要的一點(diǎn)就是:Vue 的 $mount 方法掛載元素,采用的是【替換】模版中的掛載點(diǎn) 這樣的方法,知道了這個(gè)知識(shí)點(diǎn)以后,我們要實(shí)現(xiàn)骨架屏,就有了很好的實(shí)現(xiàn)思路了。

實(shí)現(xiàn)方式(具體實(shí)現(xiàn))

方案一、在模版中來實(shí)現(xiàn)骨架屏

思路:在 index.html 中的 div#app 中來實(shí)現(xiàn)骨架屏,程序渲染后就會(huì)替換掉 index.html 里面的 div#app 骨架屏內(nèi)容;


ok,做完了;你覺得我這個(gè)骨架屏做的怎么樣。

方案二、使用一個(gè)Base64的圖片來作為骨架屏

使用圖片作為骨架屏; 簡(jiǎn)單暴力,讓UI同學(xué)花點(diǎn)功夫吧;小米商城的移動(dòng)端頁面采用的就是這個(gè)方法,它是使用了一個(gè)Base64的圖片來作為骨架屏。

按照方案一的方案,將這個(gè) Base64 的圖片寫在我們的 index.html 模塊中的 div#app 里面。

方案三、使用 .vue 文件來完成骨架屏

我們可能不希望在默認(rèn)的模版(index.html)上來進(jìn)行代碼的coding;想在方案一的基礎(chǔ)上,將骨架屏的代碼抽離出來,使用一個(gè) .vue 文件來 coding,易于維護(hù)。

1、我們?cè)?src 下建一個(gè) skeleton 目錄,在里面創(chuàng)建兩個(gè)文件(skeleton.vueskeleton.entry.js);skeleton.vue 就是我們的骨架屏頁面的代碼,skeleton.entry.js 是編譯 skeleton.vue 的入口文件,類似于我們 Vue 項(xiàng)目中的 main.js 文件;

// skeleton.entry.jsimport Vue from 'vue'import Skeleton from './skeleton.vue'export default new Vue({  // 根實(shí)例簡(jiǎn)單的渲染應(yīng)用程序組件  render: h => h(Skeleton)})
<!-- skeleton.vue --><template>  <div class="skeleton page">    <span>骨架屏</span>  </div></template><style scoped></style>

2、我們還需要在新建一個(gè) webpack.skeleton.conf.js 文件,以專門用來進(jìn)行骨架屏的構(gòu)建(這個(gè)文件放在哪里無所謂,可以放在根目錄下,也可以放在 build 目錄中)。這是一個(gè) webpack 的配置文件,配合使用 vue-server-renderer 將我們的 skeleton.vue 文件內(nèi)容構(gòu)建為單個(gè)的 json 格式的文件(這是 Vue SSR 渲染的策略)

// webpack.skeleton.conf.js'use strict'const path = require('path')const nodeExternals = require('webpack-node-externals')const VueSSRServerPlugin = require('vue-server-renderer/server-plugin')module.exports = {  target: 'node',  devtool: '#source-map',  entry: './src/skeleton/skeleton.entry.js',  output: {    path: path.resolve(__dirname, '../dist'),    publicPath: '/dist/',    filename: '[name].js',    libraryTarget: 'commonjs2'  },  module: {    noParse: /es6-promise\.js$/,  // avoid webpack shimming process    rules: [      {        test: /\.vue$/,        loader: 'vue-loader',        options: {          compilerOptions: {            preserveWhitespace: false          }        }      },      {        test: /\.css$/,        use: ['vue-style-loader', 'css-loader']      }    ]  },  performance: {    hints: false  },  externals: nodeExternals({    // do not externalize CSS files in case we need to import it from a dep    whitelist: /\.css$/  }),  plugins: [    // 這是將服務(wù)器的整個(gè)輸出構(gòu)建為單個(gè) JSON 文件的插件。    // 默認(rèn)文件名為 `vue-ssr-server-bundle.json`    new VueSSRServerPlugin({      filename: 'skeleton.json'    })  ]}

3、寫完 skeleton.vue 的內(nèi)容以后,使用 webpack-cli 運(yùn)行這個(gè) webpack.skeleton.conf.js 配置文件。

// package.json"skeleton": "webpack --progress --config build/webpack.skeleton.conf.js"

然后運(yùn)行:

npm i webpack-cli@3.3.10 -Dnpm run skeleton

就會(huì)在 dist 文件夾中生成一個(gè)skeleton.json 文件。

4、將 skeleton.json 內(nèi)容插入到模版文件 index.html 中。(在根目錄下創(chuàng)建一個(gè) skeleton.js 文件)

// skeleton.jsconst fs = require('fs')const { resolve } = require('path')const { createBundleRenderer } = require('vue-server-renderer')function createRenderer(bundle, options) {  return createBundleRenderer(bundle, Object.assign(options, {    // recommended for performance    // runInNewContext: false  }))}const handleError = err => {  console.error(`error during render : ${req.url}`)  console.error(err.stack)}const bundle = require('./dist/skeleton.json')const templatePath = resolve('./index.html')const template = fs.readFileSync(templatePath, 'utf-8')const renderer = createRenderer(bundle, {  template})// console.log(renderer)/** * 說明: * 默認(rèn)的index.html中包含<%= BASE_URL %>的插值語法 * 我們不在生成骨架屏這一步改變模板中的這個(gè)插值 * 因?yàn)檫@個(gè)插值會(huì)在項(xiàng)目構(gòu)建時(shí)完成 * 但是如果模板中有這個(gè)插值語法,而我們?cè)趘ue-server-renderder中使用這個(gè)模板,而不傳值的話,是會(huì)報(bào)錯(cuò)的 * 所以,我們?nèi)サ裟0逯械牟逯?,而使用這個(gè)傳參的方式,再將這兩個(gè)插值原模原樣返回到模板中 *  * 文檔: https://cli.vuejs.org/zh/guide/html-and-static-assets.html#%E6%8F%92%E5%80%BC */const context = {  title: '',  // default title  meta: `<meta name="theme-color" content="#4285f4">    <link rel="icon" href="<%= BASE_URL %>favicon.ico">    <link rel="stylesheet" href="<%= BASE_URL %>css/reset.css">`}renderer.renderToString(context, (err, html) => {  if(err) {    return handleError(err)  }  fs.writeFileSync(resolve(__dirname, './index.html'), html, 'utf-8')})

5、模版 index.html 加上插槽注解
這里需要注意的是:index.html 中的 div#app 中要加一個(gè)注解插槽,<!--vue-ssr-outlet--> 這個(gè)是必須的,Vue SSR 文檔中有說這個(gè)。這個(gè)注解是必須的,請(qǐng)注意!

<!DOCTYPE html><html>  <head>    <meta charset="utf-8">    <meta name="viewport" content="width=device-width,initial-scale=1.0">    <title>vue-for-test</title>  </head>  <body>    <div id="app">      <!--vue-ssr-outlet-->    </div>    <!-- built files will be auto injected -->  </body></html>

參考連接:https://ssr.vuejs.org/zh/guide/#%E4%BD%BF%E7%94%A8%E4%B8%80%E4%B8%AA%E9%A1%B5%E9%9D%A2%E6%A8%A1%E6%9D%BF

6、執(zhí)行

node skeleton.js

執(zhí)行成功后,模版 index.html 中的 div#app 中的內(nèi)容就會(huì)變成我們的骨架屏代碼;

7、看一下效果


這個(gè)骨架屏,你覺得效果如何?

線上可以看到效果的例子也是有的: map-chart;記得選擇,瀏覽器 -> network -> slow 3G 模式來預(yù)覽 骨架屏效果。

在方案三中,還涉及到了 Vue SSR 的內(nèi)容,關(guān)于 SSR 的知識(shí)的學(xué)習(xí),可以參考我之前寫的一個(gè)教程: https://github.com/Neveryu/vue-ssr-lessons

方案四、自動(dòng)生成并自動(dòng)插入靜態(tài)骨架屏

餓了么開源的插件 page-skeleton-webpack-plugin ,它根據(jù)項(xiàng)目中不同的路由頁面生成相應(yīng)的骨架屏頁面,并將骨架屏頁面通過 webpack 打包到對(duì)應(yīng)的靜態(tài)路由頁面中,不過要注意的是這個(gè)插件目前只支持 history 方式的路由,不支持 hash 方式,且目前只支持首頁的骨架屏,并沒有組件級(jí)的局部骨架屏實(shí)現(xiàn),作者說以后會(huì)有計(jì)劃實(shí)現(xiàn)(issue9)。

另外還有個(gè)插件 vue-skeleton-webpack-plugin,它將插入骨架屏的方式由手動(dòng)改為自動(dòng),原理在構(gòu)建時(shí)使用 Vue 預(yù)渲染功能,將骨架屏組件的渲染結(jié)果 HTML 片段插入 HTML 頁面模版的掛載點(diǎn)中,將樣式內(nèi)聯(lián)到 head 標(biāo)簽中。這個(gè)插件可以給單頁面的不同路由設(shè)置不同的骨架屏,也可以給多頁面設(shè)置,同時(shí)為了開發(fā)時(shí)調(diào)試方便,會(huì)將骨架屏作為路由寫入 router 中,可謂是相當(dāng)體貼了。

本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊舉報(bào)
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
Vue 服務(wù)端渲染實(shí)踐 ——Web應(yīng)用首屏耗時(shí)最優(yōu)化方案
vue中使用骨架 vue-skeleton-webpack-plugin
ssr服務(wù)器端渲染
入職第一天:前端leader手把手教我入門Vue服務(wù)器端渲染
模塊化和webpack
15個(gè)具有收藏意義的webpack插件
更多類似文章 >>
生活服務(wù)
熱點(diǎn)新聞
分享 收藏 導(dǎo)長(zhǎng)圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服