スケルトン画面はおまけです。理想的には、開発者はスケルトン画面にあまり注意を払う必要はありません。したがって、開発経験の観点から、スケルトン画面を手動で記述することは良い解決策ではありません。したがって、この記事では主に、スケルトン スクリーンを自動生成する別のスキーム、つまり vite プラグインを介してスケルトン スクリーンを自動的に挿入する方法について検討します。
[関連する推奨事項: vuejs ビデオ チュートリアル]
スケルトン画面には、SPA アプリケーションのユーザー エクスペリエンスを大幅に向上させる 2 つの機能があります.機能
- ページをロードするために初期化するときに空白スペースを回避します。エクスペリエンスは、SSR からページの初期化が完了するのを完全に待機するまでの間です。
- ページの初期化が完了するまで空白スペースを回避します。一部のルーティング コンポーネントはレンダリング前にデータをロードする必要があります
スケルトン画面は、コンテンツが返されたようにユーザーに錯覚させます。しばらく待つ限り、完全なコンテンツを見ることができます。したがって、スケルトン画面は、実際のコンテンツが準備される前の代役として配置されます。
私は以前、スケルトン画面をすばやく生成するアイデアを検討しました: Chrome 拡張機能を使用して Web スケルトン画面を生成する. 一般原則は、content.js## を挿入することです。 # Chrome 拡張機能を使用して、ページの DOM インターフェイスを変更し、最後にスケルトン画面スタイルで HTML コードをエクスポートします。
- デザイナーに直接依頼して、ページに対応するスケルトン画面の設計図を提供してもらいます
- エクスポート
- svg
または
base64画像はコードに埋め込まれているため、プロジェクトのサイズに影響します。
手動による記述スタイルを開発します。これには大きな作業負荷が必要です。
コンポーネントによる書き込みスケルトン画面- svg
-
- vue-content-loader や react-content-loader などのコンポーネントにより、スケルトン画面のコンテンツをすばやく書き込むことができますただし、出力結果と実際のページの間には一定のギャップがあり、カスタマイズされたスケルトン画面のニーズを満たすのは容易ではありません。
vant
や varlet - などの一部のコンポーネント ライブラリは、次の形式でスケルトン画面コンテンツの生成を制御する skeleton コンポーネントも提供します。
#スケルトン画面の自動生成
と、カスタマイズの度合いが低いという欠点があります。他の比較的成熟した自動スケルトン スクリーン ソリューションには、さまざまな側でスケルトン スクリーンの生成を制御する特別な UI インターフェイスもあります。欠点は、生成されるスケルトン スクリーン コードが大きくなり、プロジェクト サイズに影響することです。 - vue-content-loader や react-content-loader などのコンポーネントにより、スケルトン画面のコンテンツをすばやく書き込むことができますただし、出力結果と実際のページの間には一定のギャップがあり、カスタマイズされたスケルトン画面のニーズを満たすのは容易ではありません。
- puppeteer
の助けを借りてページをレンダリングします。対応するスケルトン画面コンテンツは
に大きく依存します。Chrome 拡張機能を使用してスケルトン画面コンテンツを生成します。これは本質的にヘッドレス ブラウザの原理と似ています。ブラウザ - スケルトン画面 これはおまけです。理想的には、開発者はあまり注意を払う必要はありません。したがって、開発経験の観点から、手動でスケルトン画面を作成することは良い解決策ではありません。したがって、この記事では主に、スケルトン スクリーンを自動生成する別のスキーム、つまり vite プラグインを介してスケルトン スクリーンを自動的に挿入する方法について検討します。 #最初にエフェクトをプレビューします
クリックしてスケルトン画面を生成します- puppeteer
#最初の画面にアクセスします
vite プラグインによるスケルトン画面の生成
参考
#vite-plugin-vue-inspector
このプラグインの実装では、ソース コードから一部の情報がページに挿入されます- スケルトン画面 - WeChat ミニ プログラム開発ドキュメント、ミニプログラム 開発者ツールは、現在のページのスケルトン画面を迅速に生成するのと同様のソリューションを提供します。
-
まず、デザインを自動的に変換できるソリューションを検討する必要があります。描画または実際のページをスケルトン画面に追加します。おそらく次のようなアイデアがあるでしょう
- コンパイルツールを使用して、コードに記述されたHTMLテンプレートを解析し、スケルトン画面を生成します
- スケッチやfigmaなどの設計図のソースから開始し、エクスポートしますプラグイン経由でスケルトン画面コンテンツを生成
- 実際のページのDOMを直接操作してスケルトン画面コンテンツを生成
既存のスタイルを利用
It 3 番目のアイデアは実装コストが最も低く、最もよく知られているようです。これは Chrome 拡張機能を使用して Web ページのスケルトン画面を生成する で使用したソリューションでもあるため、具体的な実装の詳細についてはここでは繰り返しません。 、手動でスイッチをトリガーすることで、特定のページに対応するスケルトン画面コンテンツの生成を開始します
- ノード タイプに応じてページをさまざまなブロックに分割します
- カスタム ノード タイプをサポートし、ノードを無視または非表示にします
- 最終的なエクスポートは HTML コードの一部であり、元のページの構造と CSS レイアウト コードを再利用します。
- コア API は 1 つだけです。対応するエントリ ノードを渡します。画面コード
const {name, content} = renderSkeleton(sel, defaultConfig)
<div> <div>卡片标题</div> <div>卡片内容卡片内容</div> </div>で生成されるスケルトン画面コードは
<div> <div>卡片标题</div> <div>卡片内容卡片内容</div> </div>となり、その内
sk- block
、sk- text などのスタイル クラスは生成時に追加され、元のレイアウト スタイルを保持したままスケルトン画面の灰色の背景を表示するために元のスタイルを上書きするために使用されます。
renderSkeleton
function createTrigger() { const div: HTMLDivElement = document.createElement('div') div.setAttribute('style', 'position:fixed;right:0;bottom:20px;width:50px;height:50px;background:red;') div.addEventListener('click', function () { renderSkeleton('[data-skeleton-root]') }) document.body.appendChild(div) } if(process.end.NODE_ENV ==='development'){ createTrigger() }
を呼び出すことができます。スケルトン画面のコードを取得した後、ビジネスコード内
loading フラグは、スケルトン画面と実際のコンテンツのどちらを表示するかを制御するために使用されます。
<script> import {ref, onMounted} from "vue"; const loading = ref(true); const list = ref<number>([]); async function fetchList() { await sleep(1000) list.value = [1, 2, 3, 4, 5] loading.value = false } onMounted(() => { fetchList() }) </script> <template> <div> <div> <!--这里的都是骨架屏代码--> <div> <div>卡片标题</div> <div>卡片内容卡片内容</div> </div> </div> <div> <div> <div>卡片标题</div> <div>卡片内容卡片内容</div> </div> </div> </div> </template> <style> // 相关的样式 </style>
v-if= 内のコードが確認できます。 「loading」タグで生成されたスケルトン画面の内容です。スケルトン画面はビジネス コードとともにあるため、Vue の SFC コンパイルにも参加するため、スケルトン画面ラベルの scopeid などのいくつかの動的属性を削除する必要があることに注意してください。スコープ ID によって引き起こされるその他の問題については後で説明しますが、これは
renderSkeleton 全体の実装にも影響します。
renderSkeleton
前述したように、スケルトン画面は主に最初の画面のレンダリングが必要な場合とルーティング ページの切り替え時に使用されます
SPA の最初の画面レンダリングの最適化
- ルーティング コンポーネントを切り替えるときの占有率ビット コンテンツ
- これら 2 つのシナリオでスケルトン スクリーン コードを自動的に挿入する方法を見てみましょう
コンポーネント内でのスケルトン スクリーンのレンダリング
us プレースホルダーを使用して、<div>__SKELETON_APP_CONTENT__</div>
<div>真实业务代码</div>
のように、現在のコンポーネントがスケルトン スクリーン コードに対応する場所を宣言できます。スケルトン スクリーン コードを取得した後、ここのコンテンツを実際のスケルトン スクリーン コードに置き換えることができます。 交換方法は? vite プラグインは、transform フック
const filename = './src/skeleton/content.json' function SkeletonPlaceholderPlugin() { return { name: 'skeleton-placeholder-plugin', enforce: 'pre', transform(src, id) { if (/\.vue$/.test(id)) { const {content} = fs.readJsonSync(filename) // 约定对应的骨架屏占位符 let code = src.replace(/__SKELETON_(.*?)_CONTENT__/igm, function (match) { return content }) return { code, } } return src }, } as Plugin }を提供します。
./skeleton.txt のコンテンツは、
renderSkeleton
transform と
pre を使用すると、vue プラグインが SFC を解析する前に、スケルトン画面のプレースホルダーを実際のコードに置き換えることができ、その後のコンパイル プロセスに参加できます。
ここで解決する必要がある別の問題があります。
renderSkeleton はクライアント上でトリガーされ、
skeleton.txt
vite プラグインは、vite 開発サーバーを構成するための
configureServer フックを提供します。スケルトン画面コードを保存するためのインターフェイスを提供するミドルウェアを追加できます。
function SkeletonApiPlugin() { async function saveSkeletonContent(name, content) { await fs.ensureFile(filename) const file = await fs.readJson(filename) file[name] = { content, } await fs.writeJson(filename, file) } return { name: 'skeleton-api-plugin', configureServer(server) { server.middlewares.use(bodyParser()) server.middlewares.use('/update_skeleton', async (req, res, next) => { const {name, content, pathname} = req.body await saveSkeletonContent(name, content, pathname) // 骨架屏代码更新之后,重启服务 server.restart() res.end('success') }) }, } }その後
renderSkeleton、このインターフェイスを呼び出して、生成されたスケルトン画面コードをアップロードします
async function sendContent(body: any) { const response = await fetch('/update_skeleton', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body) }) const data = await response.text() } const __renderSkeleton = async function () { const {name, content} = renderSkeleton(".card-list", {}) await sendContent({ name, content }) }bingo! これで完了です。プロセスの整理
#開発者がある時点で手動で
を呼び出すと、現在のページのスケルトン画面が自動的に生成されます
スケルトン画面コードを vite インターフェイスに送信し、ローカルの
skeleton/content.json
でスケルトン画面コードを更新し、-
vite 後にリトリガーしますサービスを再起動します
skeleton-content-componentpre
キュー内の プラグインは、スケルトン画面のプレースホルダーを置き換え、スケルトン画面のコードを挿入し、スケルトン画面の挿入プロセス全体を完了します。 プロセス全体で、開発者は次の 2 つの手順を完了するだけで済みます。
ビジネス コードでスケルトン画面のプレースホルダーを宣言します。
- ボタンをクリックしてスケルトン画面コードの生成をトリガーします
- ルーティング切り替え用のスケルトン画面は主にルーティング コンポーネントで使用され、さらにカプセル化と統合が考えられます ローディングとスケルトン画面表示の管理 詳細については、ここで説明しますので、一つ一つ説明しません。
-
首屏渲染骨架屏
骨架屏对于SPA首屏渲染优化,需要在应用初始化之前就开始渲染,即需要在
id="app"
的组件内植入初始化的骨架屏代码如果是服务端预渲染,可以直接返回填充后的代码;如果是客户端处理,可以通过
document.write
处理,我们这里只考虑纯SPA引用,由前端处理骨架屏的插入。我们可以通过vite插件提供的
transformIndexHtml
钩子注入这段逻辑function SkeletonApiPlugin() { return { name: 'skeleton-aip-plugin', transformIndexHtml(html) { let {content} = fs.readJsonSync(filename) const code = ` <script> var map = ${JSON.stringify(content)} var pathname = window.location.pathname var target = Object.values(map).find(function (row){ return row.pathname === pathname }) var content = target && target.content || '' document.write(content) </script> ` return html.replace(/__SKELETON_CONTENT__/, code) } } }
对应的
index.html
代码为<div>__SKELETON_CONTENT__</div>
根据用户当前访问的url,读取该url对应的骨架屏代码,然后通过
document.write
写入骨架屏代码。这里可以看出,在生成骨架屏代码时,我们还需要保留对应页面url的映射,甚至需要考虑动态化路由的匹配问题。这个也比较简单,在提交到服务端保存时,加个当前页面的路径参数就行了const {name, content} = renderSkeleton(sel, defaultConfig) // 如果是hash路由,就替换成fragment const {pathname} = window.location await sendContent({ name, content, pathname // 保存骨架屏代码的时候顺道把pathname也保存了 })
整理一下流程
- 用户访问url
- 根据页面url,加载对应的骨架屏代码,填充在根节点下
- 如果是服务端预渲染,可以直接返回填充后的代码
- 如果是客户端处理,可以通过document.write处理
- 用户看见渲染的骨架屏内容
- 初始化应用,加载页面数据,渲染出真实页面
开发者在点击生成当前页面的骨架屏时,保存的骨架屏代码,既可以用在路由组件切换时的骨架屏,也可以用在首屏渲染时的骨架屏,Nice~
存在的一些问题
利用vite插件注入骨架屏的代码,看起来是可行的,但在方案落地时,发现了一些需要解决的问题。
存在原始样式不生效的场景
由于生成的骨架屏代码是依赖原始样式的,
<div></div>
对应的骨架屏代码
<div></div>
其中的
sk-block
只会添加一些灰色背景和动画,至于整体的尺寸和布局,还是card
这个类来控制的。这么设计的主要原因是:即使
card
的尺寸布局发生了变化,对应的骨架屏样式也会一同更新。但在某些场景下,原始样式类无法生效,最具有代表性的问题就Vue项目的的
scoped css
。我们知道,
vue-loader
、@vitejs/plugin-vue
等工具解析SFC文件时,会为对应组件生成scopeId(参考之前的源码分析:从vue-loader源码分析CSS-Scoped的实现),然后通过postcss
插件,通过组合选择器实现了类似于css作用域的样式表.card[data-v-xxx] {}
我们的生成骨架屏的时机是在开发环境下进行的,这就导致在生产环境下,看到的骨架屏并没有原始样式类对应的尺寸和布局。
下面是vite vue插件的源码
export function createDescriptor( filename: string, source: string, { root, isProduction, sourceMap, compiler }: ResolvedOptions ): SFCParseResult { const { descriptor, errors } = compiler.parse(source, { filename, sourceMap }) const normalizedPath = slash(path.normalize(path.relative(root, filename))) descriptor.id = hash(normalizedPath + (isProduction ? source : '')) cache.set(filename, descriptor) return { descriptor, errors } }
vue-loader
中生成scopeid的方法类似,看了一下貌似并没有提供自定义scopeid的API。因此对于同一个文件而言,生产环境和非生产环境参与生产hash的参数是不一样的,导致最后得到的scopeid 也不一样。
对于组件内渲染骨架屏这种场景,我们也许可以不考虑scopeid,因为在SFC编译之前,我们就已经通过
transform
钩子注入了对应的骨架屏模板,对于SFC编译器而言,骨架屏代码和业务代码都在同一个组件内,也就是说他们最后都会获得相同的scopeid,这也是为什么生成的骨架屏代码,要擦除HTML标签上面的scopeid的原因。但如果骨架屏依赖的外部样式并不在同一个SFC文件内,也会导致原始的骨架屏样式不生效。
<template> <div> <div> <div> <div>卡片标题</div> <div>卡片内容卡片内容</div> </div> </div> <div> <card></card> </div> </div> </template> <style> // card 样式不在这个SFC下面,但是插入的骨架屏代码却在这个SFC文件下 </style>
此外,对于首屏渲染骨架屏这种场景,就不得不考虑scopeid了。如果骨架屏依赖的原始样式是携带作用域的,那就必须要保证骨架屏代码与生产环境的样式表一致
.card[data-v-xxx] {}
<div></div>这样,首屏渲染依赖的骨架屏和组件内渲染的骨架屏就产生了冲突,前者需要携带scopeid,而后者又需要擦除scopeid。
为了解决这个冲突,有两种办法
- 在保存骨架屏代码时,同时保存对应的scopeid,并在首屏渲染时,为每个标签上手动添加scopeid。
- 原始骨架屏代码就携带scopeid,而在替换组件内的骨架屏占位符时再擦除scopeid
但不论通过何种方式保证两个环境下生成的scopeid 一致(甚至是通过修改插件源码的方式),可能也会存在旧版本的骨架屏携带的scopeid和新版本对应的scopeid 不一致的问题,即旧版本的class和新版本的class不一致。
要解决这个问题,除非在每次修改源码之后,都更新一下骨架屏,由于生成骨架屏这一步是手动的,这与自动化的目的背道而驰了。
因此,看起来利用原始类同步真实DOM的布局和尺寸,在
scoped css
中并不是一个十分完善的设计。骨架屏代码质量
第二个不是那么重要的问题是生成的骨架屏代码,相较于手动编写,不够精简。
虽然在源代码中,骨架屏代码被占位符替代,但在编译阶段,骨架屏会编译到render函数中,可能造成代码体积较大,甚至影响页面性能的问题。
这个问题并不是一个阻塞性问题,可以后面考虑如何优化,比如骨架屏仍旧保留v-for等指令,组件可以正常编译,而首屏渲染的骨架屏需要通过自己解析生成完整的HTML代码。
解决方案
上面这两个问题的本质都是因为骨架屏生成方案导致的,跟后续保存骨架屏代码并自动替换并没有多大关系,因此我们只需要优化骨架屏生成方案即可。
既然依赖于原始样式生成的骨架屏代码存在这些缺点,有没有什么解决办法呢?
事实上,我们对于骨架屏是否更真实内容结构的还原程度并没有那么高的要求,也并没有要求骨架屏要跟业务代码一直保持一致,既然导出HTML骨架屏代码比较冗余和繁琐,我们可以换一换思路。
不使用scoped css
其他比较常用的CSS方案如
css moudle
、css-in-js
或者是全局原子类css如tailwind
、windicss
等,如果输出的是纯粹的CSS代码,且生产环境和线上保持一致,理论上是不会出现scopeid这个问题的。但Vue项目中,
scoped css
方案应该占据了半壁江山,加上我自己也比较喜欢scoped css
,因此这是一个绕不过去的问题。将骨架屏页面自动转成图片
第一种思路将骨架屏页面保存为图片,这样就不用再依赖原始样式了。
大概思路就是:在解析当前页面获得骨架屏代码之后,再通过
html2canvas
等工具,将已经渲染的HTML内容转成canvas,再导出base64图片。import html2canvas from 'html2canvas' const __renderSkeleton = async function (sel = 'body') { const {name, content} = renderSkeleton(sel, defaultConfig) const canvas = await html2canvas(document.querySelector(sel)!) document.body.appendChild(canvas); const imgData = canvas.toDataURL() // 保存<img src="/static/imghwm/default1.png" data-src="${imgData}" class="lazy" alt="vite プラグインを使用してスケルトン画面を自動化する方法について話しましょう" >作为骨架屏代码 }
这种通过图片替代HTML骨架屏代码的优点在于兼容性好(对应的页面骨架屏甚至可以用在App或小程序中),容易迁移,不需要依赖项目代码中的样式类。
但是
html2canvas
生成的图片也不是百分百还原UI,需要足够纯净的代码原始结构才能生成符合要求的图片。此外图片也存在分辨率和清晰度等问题。也许又要回到最初的起点,让设计大佬直接导出一张SVG?(开个玩笑,我们还是要走自动化的道路
复制一份独立的样式表
如果能够找到骨架屏代码中每个标签对应的
class
在样式表中定义的样式,类似于Chrome dev tools中的Elements Styles
面板,我们就可以将这些样式复制一份,然后将scopeid替换成其他的选择器开发环境下的样式都是通过style标签引入,因此可以拿到页面上所有的样式表对象,提取符合对应选择器的样式,包括
.className
和.className[scopeId]
这两类写一个Demo
const { getClassStyle } = (() => { const styleNodes = document.querySelectorAll("style"); const allRules = Array.from(styleNodes).reduce( (acc, styleNode) => { const rules = styleNode.sheet.cssRules; acc = acc.concat(Array.from(rules)); return acc; }, [] ); const getClassStyle = (selectorText) => { return allRules.filter( (row) => row.selectorText === selectorText ); }; return { getClassStyle, }; })(); const getNodeAttrByRegex = (node, re) => { const attr = Array.from(node.attributes).find((row) => { return re.test(row.name); }); return attr && attr.name; }; const parseNodeStyle = (node) => { const scopeId = getNodeAttrByRegex(node, /^data-v-/); return Array.from(myBox.classList).reduce((acc, row) => { const rules = getClassStyle(`.${row}`); // 这里没有再考虑两个类.A.B之类的组合样式了,排列组合比较多 return acc .concat(getClassStyle(`.${row}`)) .concat(getClassStyle(`.${row}[${scopeId}]`)); }, []); }; const rules = parseNodeStyle(myBox); console.log(rules);
这样就可以得到每个节点在scoped css的样式,然后替换成骨架屏依赖的样式。
但现在要保存的骨架屏代码的HTML结构之外,还需要保存对应的那份CSS代码,十分繁琐
提取必要的布局信息生成骨架屏
能否像html2canvas的思路一样,重新绘制一份骨架屏页面出来呢
通过
getComputedStyle
可以获取骨架屏每个节点的计算样式const width = getComputedStyle(myBox,null).getPropertyValue('width');
复用页面结构,把所有布局和尺寸相关的属性都枚举出来,一一获取然后转成行内样式,看起来也是可行的。
但这个方案需要逐步尝试完善对应的属性列表,相当于复刻一下浏览器的布局规则,工作量较大,此外还需要考虑rem、postcss等问题,看起来也不是一个明智的选择。
postcss插件
既然scopeid是通过postcss插入的,能不能在对应的样式规则里面加一个分组选择器,额外支持一下骨架屏的呢
比如
.card[data-v-xxx] {}
修改为
.card[data-v-xxx], .sk-wrap .card {}
这样,只要解决生产环境和开发环境scopeid不一致的问题就可以了。
编写postcss插件可以参考官方文档:编写一个postcss 插件。
在
vue/compuler-sfc
源码中发现,scopedPlugin
插件位于传入的postcssPlugins
之后,而我们编写的插件需要位于scopedPlugin
之后才行,如果不能修改源码,只有继续从vite 插件的
transform
钩子入手了,在transform中手动执行postcss进行编译继续编写一个
SkeletonStylePlugin
插件const wrapSelector = '.sk-wrap' export function SkeletonStylePlugin() { return { name: 'skeleton-style-plugin', transform(src: string, id: string) { const {query} = parseVueRequest(id) if (query.type === 'style') { const result = postcss([cssSkeletonGroupPlugin({wrapSelector})]).process(src) return result.css } return src } } }
注意该插件要放在
vue
插件后面执行,因为此时得到的内容才是经过vue-compiler编译后的携带有scopeid 的样式。其中
cssSkeletonGroupPlugin
是一个postcss插件import {Rule} from 'postcss' const processedRules = new WeakSet<rule>() type PluginOptions = { wrapSelector: string } const plugin = (opts: PluginOptions) => { const {wrapSelector} = opts function processRule(rule: Rule) { if (processedRules.has(rule)) { return } processedRules.add(rule) rule.selector = rewriteSelector(rule) } function rewriteSelector(rule: Rule): string { const selector = rule.selector || '' const group: string[] = [] selector.split(',').forEach(sel => { // todo 这里需要排除不在骨架屏中使用的样式 const re = /\[data-v-.*?\]/igm if (re.test(sel)) { group.push(wrapSelector + ' ' + sel.replace(re, '')) } }) if(!group.length) return selector return selector + ', ' + group.join(',') } return { postcssPlugin: 'skeleton-group-selector-plugin', Rule(rule: Rule) { processRule(rule) }, } } plugin.postcss = true export default plugin</rule>
这个插件写的比较粗糙,只考虑了常规的选择器,并依次追加分组选择器。测试一下
.test1[data-v-xxx] {}
成功编译成了
.test1[data-v-xxx], .sk-wrap .test1 {}
这样,只需要将骨架屏代码外边包一层
sk-wrap
,骨架屏中的样式就可以正常生效了!content && document.write('<div>' +content+'</div>')
看起来解决了一个困扰我很久的问题。
小结
至此,一个借助于Vite插件实现自动骨架屏的方案就实现了,总结一下整体流程
首先初始化插件
import {SkeletonPlaceholderPlugin, SkeletonApiPlugin} from '../src/plugins/vitePlugin' export default defineConfig({ plugins: [ SkeletonPlaceholderPlugin(), vue(), SkeletonApiPlugin(), ], build: { cssCodeSplit: false } })
然后填写占位符,对于首屏渲染的骨架屏
<div>__SKELETON_CONTENT__</div>
对于组件内的骨架屏
__SKELETON_APP_CONTENT__<div></div>接着初始化客户端触发器,同时向页面插入一个可以点击生成骨架屏的按钮
import '../../src/style/skeleton.scss' import {initInject} from '../../src/inject' createApp(App).use(router).mount('#app') // 开发环境下才注入 if (import.meta.env.DEV) { setTimeout(initInject) }
点击触发器,自动将当前页面转换成骨架屏
通过HTTP将骨架屏代码发送到插件接口,通过fs写入本地文件
./src/skeleton/content.json
中,然后自动重启vite server页面内组件的占位符会通过
SkeletonPlaceholderPlugin
替换对应占位符的骨架屏代码,loading生效时展示骨架屏首屏渲染页面时,通过location.pathname插入当前路径对应的骨架屏代码,直接看见骨架屏代码
所有骨架屏依赖的当前样式通过
cssSkeletonGroupPlugin
解析,通过分组选择器输出在css文件,不再依赖scopeid。这样,一个基本自动的骨架屏工具就集成到项目中,需要进行的手动工作包括
- 配置插件
- 定义组件的骨架屏占位符,以及骨架屏入口
data-skeleton-root="APP"
- 必要时在标签上声明
data-skeleton-type
,定制骨架屏节点
整个项目比较依赖vite插件开发知识,也参考了
vite
、@vitejs/plugin-vue
、@vue/compile-sfc
等源码的实现细节。所有Demo已经放在github上面了,剩下要解决的就是优化生成骨架屏的效果和质量了,期待后续吧
以上がvite プラグインを使用してスケルトン画面を自動化する方法について話しましょうの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

Vue.jsは使いやすく、スムーズな学習曲線があり、初心者に適しています。 Reactは急な学習曲線を持っていますが、柔軟性が強いため、経験豊富な開発者に適しています。 1.Vue.jsは、単純なデータバインディングとプログレッシブデザインを介して簡単に始められます。 2.反応には、仮想DOMとJSXを理解する必要がありますが、より高い柔軟性とパフォーマンスの利点を提供します。

Vue.JSは、高速開発や小規模プロジェクトに適していますが、Reactは大規模で複雑なプロジェクトにより適しています。 1.Vue.jsは簡単で学習しやすく、迅速な開発や小規模プロジェクトに適しています。 2.反応は強力で、大規模で複雑なプロジェクトに適しています。 3. Vue.jsの進歩的な特徴は、徐々に機能を導入するのに適しています。 4。複雑なUIおよびデータ集約型アプリケーションを扱うとき、Reactのコンポーネントと仮想DOMはうまく機能します。

Vue.jsとReactには、それぞれ独自の利点と短所があります。選択するときは、チームのスキル、プロジェクトの規模、パフォーマンス要件を包括的に検討する必要があります。 1)VUE.JSは、学習曲線が低い高速開発や小規模プロジェクトに適していますが、ネストされたオブジェクトはパフォーマンスの問題を引き起こす可能性があります。 2)Reactは、豊富なエコシステムを備えた大規模で複雑なアプリケーションに適していますが、頻繁に更新するとパフォーマンスのボトルネックにつながる可能性があります。

VUE.JSは中小企業から中規模のプロジェクトに適していますが、Reactは大規模なプロジェクトや複雑なアプリケーションシナリオに適しています。 1)Vue.jsは使いやすく、迅速なプロトタイピングや小規模アプリケーションに適しています。 2)Reactは、複雑な州の管理とパフォーマンスの最適化を処理する上でより多くの利点があり、大規模なプロジェクトに適しています。

Vue.jsとReactにはそれぞれ独自の利点があります。Vue.jsは小さなアプリケーションと迅速な発展に適していますが、Reactは大規模なアプリケーションと複雑な国家管理に適しています。 1.Vue.jsは、小さなアプリケーションに適したレスポンシブシステムを通じて自動更新を実現します。 2.反応は、大規模で複雑なアプリケーションに適した仮想DOMおよびDIFFアルゴリズムを使用します。フレームワークを選択するときは、プロジェクトの要件とチームテクノロジースタックを検討する必要があります。

Vue.jsとReactにはそれぞれ独自の利点があり、選択はプロジェクトの要件とチームテクノロジースタックに基づいている必要があります。 1。Vue.jsはコミュニティに優しいものであり、豊富な学習リソースを提供しており、エコシステムには公式チームとコミュニティによってサポートされているVuerouterなどの公式ツールが含まれています。 2. Reactコミュニティは、強力なエコシステムを備えたエンタープライズアプリケーションに偏っており、Facebookとそのコミュニティが提供するサポートを頻繁に更新しています。

NetflixはReactを使用してユーザーエクスペリエンスを強化します。 1)Reactのコンポーネント機能は、Netflixが複雑なUIを管理可能なモジュールに分割するのに役立ちます。 2)Virtual DomはUIの更新を最適化し、パフォーマンスを向上させます。 3)ReduxとGraphQLを組み合わせて、Netflixはアプリケーションのステータスとデータフローを効率的に管理します。

Vue.jsはフロントエンドフレームワークであり、バックエンドフレームワークはサーバー側のロジックを処理するために使用されます。 1)VUE.JSは、ユーザーインターフェイスの構築に焦点を当て、コンポーネントおよびレスポンシブデータバインディングを介して開発を簡素化します。 2)ExpressやDjangoなどのバックエンドフレームワークは、HTTPリクエスト、データベース操作、ビジネスロジックを処理し、サーバーで実行します。


ホットAIツール

Undresser.AI Undress
リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover
写真から衣服を削除するオンライン AI ツール。

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

Video Face Swap
完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

人気の記事

ホットツール

SublimeText3 中国語版
中国語版、とても使いやすい

VSCode Windows 64 ビットのダウンロード
Microsoft によって発売された無料で強力な IDE エディター

ドリームウィーバー CS6
ビジュアル Web 開発ツール

Dreamweaver Mac版
ビジュアル Web 開発ツール

SublimeText3 Linux 新バージョン
SublimeText3 Linux 最新バージョン

ホットトピック









