预加载 Element Plus 的 Dialog 组件

对于 Element Plus 的 Dialog 组件,浏览器调试发现,正常使用 Dialog 组件时,它的蒙层和模态框元素会随页面初始加载完毕,但模态框内部的元素却只有在首次显示时浏览器再去渲染。

如果 Dialog 组件的内容很多,首次加载比较耗时(3 秒以上),那交互体验必定不好。如果我们在恰当的时机去提前加载该组件,那么用户首次打开时,浏览器就不用才开始渲染 Dialog 组件内容。

分析

最直接的方案就是在页面挂载并拿到数据后,主动触发渲染但不显示 Dialog 组件,然后再关闭隐藏。这样,用户之后点击打开 Dialog 的时候,无需等待太久。

思路

  • Dialog 组件先设置为不可见(display:none !important)
  • 监听 Dialog 组件的绑定变量,首次显示后,标记已预加载过
  • 再次显示后,移除上一步的监听,并将 Dialog 组件设置为可见

尝试过在首次显示后执行第三步,精简流程。但“隐藏组件”与“设置组件可见”的时序不好控制,会导致手动加载的 dialog 闪现。

方案

上代码,演练场试下:preload dialog

vue
<script setup>
import { ref, onMounted, watch, nextTick } from 'vue'

const data = ref('')
const visible = ref(false)

onMounted(async () => {
  data.value = await getData()
  preloadComp()
})

function getData() {
  // fetch data
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve(Math.floor(Math.random()*900000+100000).toString(16))
    }, 500)
  })
}

let preloaded = false
const preloadWatcher = watch(visible, newVal => {
  if (newVal) {
    if (!preloaded) {
      preloaded = true
    } else {
      // 完成预加载任务,不再监听
      resolvedPreload()
      preloadWatcher()
    }
  }
})

// 完成预加载任务
function resolvedPreload() {
  // 移除类
  document.querySelector('.preload-block').classList.remove('preload-block')
}
function preloadComp() {
  visible.value = true
  nextTick(() => {
    visible.value = false
  })
}
</script>
<template>
  <el-button @click="visible = true">Show Prevload Dialog</el-button>
  <!-- Preload Dialog -->
  <el-dialog title="Preload Dialog" v-model="visible" width="550px" modal-class="preload-block">
    <div>Data: {{ data }}</div>
  </el-dialog>
</template>
<style>
.preload-block {
  display: none !important;
}
</style>

通过 modal-class 属性给 Dialog 添加类,设置初始不可见。然后如上一节一样,在页面挂载并获取到数据后,预加载 Dialog,完成后移除类 prevload-block。不影响后续使用。

这种实现方案要求必须执行手动加载方法一次,否则类 prevload-block 永远不会被移除,dialog组件一直不可见。

Last updated: