首先使用项目实例,介绍需求和遇到的问题
使用Nuxt的时候常常会遇到潜在的闪烁 / 布局不一致
平台:Nuxt
包文件: Splitpanes
xml
<script setup lang="ts">
// @ts-expect-error missing type
import { Pane, Splitpanes } from 'splitpanes'
const ui = useUiState()
const play = usePlaygroundStore()
</script>
<template>
<Splitpanes
>
<Pane :size="ui.panelDocs" min-size="10">
<PanelDocs />
</Pane>
<Pane :size="100 - ui.panelDocs">
<Splitpanes
horizontal
>
<Pane :size="ui.panelEditor" min-size="10">
<PanelEditor :files="play?.files" />
</Pane>
<Pane :size="ui.panelPreview" min-size="10">
<PanelPreview />
</Pane>
<Pane :size="100 - ui.panelEditor - ui.panelPreview">
<PanelTerminal />
</Pane>
</Splitpanes>
</Pane>
</Splitpanes>
</template>
ui
为设置的页面size
, 在nuxt
平台, 如果包含client.vue
文件, 需要等待这些文件 JS 内容执行完成才会从初始状态到达我们的预设。 通过使用计算属性并将它们绑定到 style
属性,修改后的代码可确保服务器呈现的 HTML 反映基于 ui
状态的预期初始布局。这消除了 SSR 期间潜在的布局闪烁或不一致。
在Nuxt
平台, 要充分利用SSR
渲染的优势, 就要先给布局设置固定的style。
xml
<script setup lang="ts">
// @ts-expect-error missing type
import { Pane, Splitpanes } from 'splitpanes'
const ui = useUiState()
const play = usePlaygroundStore()
const isMounted = useMounted()
const panelInitDocs = computed(() => isMounted.value || {
width: `${ui.panelDocs}%`,
})
const panelInitRight = computed(() => isMounted.value || {
width: `${100 - ui.panelDocs}%`,
})
const panelInitEditor = computed(() => isMounted.value || {
height: `${ui.panelEditor}%`,
})
const panelInitPreview = computed(() => isMounted.value || {
height: `${ui.panelPreview}%`,
})
const panelInitTerminal = computed(() => isMounted.value || {
height: `${100 - ui.panelEditor - ui.panelPreview}%`,
})
</script>
<template>
<splitpanes>
<pane :size="ui.panelDocs" min-size="10" :style="panelInitDocs">
<PanelGuide />
</pane>
<PanelSplitter />
<pane :style="panelInitRight">
<splitpanes horizontal>
<Pane min-size="10" :size="ui.panelEditor" :style="panelInitEditor">
<PanelEditor :files="play.files" />
</Pane>
<PanelSplitter />
<Pane min-size="10" :size="ui.panelPreview" :style="panelInitPreview">
<PanelPreview />
</Pane>
<PanelSplitter />
<Pane min-size="10" :size="100 - ui.panelEditor - ui.panelPreview" :style="panelInitTerminal">
<PanelTerminal />
</Pane>
</splitpanes>
</pane>
</splitpanes>
</template>
PanelSplitter.vue
该文件防止布局拖动的布局消失
xml
<script setup lang='ts'>
</script>
<template>
<div class="splitpanes__splitter">
</div>
</template>
这样随着 dom 被 mount
之后, 就会立即更新需要的布局。