Element Plus SSR 服务端渲染支持与配置 
学习目标 
- 理解 SSR 在 Element Plus 中的应用场景
- 掌握 Element Plus SSR 配置方法
- 解决 SSR 中的常见问题
- 学习水合错误的避免方法
学习内容 
1. SSR 基础概念 
1.1 什么是 SSR 
- 服务端渲染:在服务器端生成完整的 HTML
- 客户端激活:在浏览器端激活交互功能
- 同构应用:同一套代码在服务端和客户端运行
1.2 SSR 的优势 
- SEO 友好:搜索引擎可以直接抓取内容
- 首屏加载快:减少白屏时间
- 更好的用户体验:快速显示内容
2. Element Plus SSR 配置 
2.1 基础配置 
typescript
// nuxt.config.ts
export default defineNuxtConfig({
  modules: ['@element-plus/nuxt'],
  elementPlus: {
    /** Options */
  }
})2.2 手动配置 
typescript
// plugins/element-plus.client.ts
import { ID_INJECTION_KEY } from '@element-plus/tokens'
import { ElMessage } from 'element-plus'
export default defineNuxtPlugin({
  name: 'element-plus',
  parallel: true,
  setup(nuxtApp) {
    if (process.client) {
      nuxtApp.vueApp.provide(ID_INJECTION_KEY, {
        prefix: Math.floor(Math.random() * 10000),
        current: 0,
      })
    }
  },
})3. 解决 SSR 常见问题 
3.1 ID 不一致问题 
typescript
// 服务端和客户端 ID 同步
import { ID_INJECTION_KEY } from '@element-plus/tokens'
// 在应用入口提供 ID 注入
app.provide(ID_INJECTION_KEY, {
  prefix: 1024,
  current: 0,
})3.2 ZIndex 管理 
typescript
// 统一 ZIndex 管理
import { ZINDEX_INJECTION_KEY } from '@element-plus/tokens'
app.provide(ZINDEX_INJECTION_KEY, {
  current: 2000
})3.3 Teleport 处理 
vue
<!-- 确保 Teleport 目标存在 -->
<template>
  <div>
    <!-- 页面内容 -->
    <div id="teleport-target"></div>
    
    <!-- 使用 Teleport 的组件 -->
    <el-dialog v-model="visible" teleported>
      <p>Dialog content</p>
    </el-dialog>
  </div>
</template>
<script setup>
// 确保在客户端渲染时 Teleport 目标已存在
onMounted(() => {
  if (!document.getElementById('teleport-target')) {
    const target = document.createElement('div')
    target.id = 'teleport-target'
    document.body.appendChild(target)
  }
})
</script>4. 水合错误避免 
4.1 条件渲染处理 
vue
<template>
  <div>
    <!-- 避免服务端和客户端渲染不一致 -->
    <ClientOnly>
      <el-date-picker v-model="date" />
      <template #fallback>
        <div>Loading...</div>
      </template>
    </ClientOnly>
  </div>
</template>4.2 动态内容处理 
vue
<template>
  <div>
    <!-- 使用 key 强制重新渲染 -->
    <el-table :data="tableData" :key="tableKey">
      <el-table-column prop="name" label="Name" />
    </el-table>
  </div>
</template>
<script setup>
const tableKey = ref(0)
const tableData = ref([])
onMounted(() => {
  // 客户端数据加载完成后更新 key
  loadTableData().then(() => {
    tableKey.value++
  })
})
</script>5. Nuxt 3 集成 
5.1 安装和配置 
bash
# 安装 Element Plus Nuxt 模块
npm install @element-plus/nuxt -Dtypescript
// nuxt.config.ts
export default defineNuxtConfig({
  modules: [
    '@element-plus/nuxt'
  ],
  elementPlus: {
    /** 配置选项 */
    importStyle: 'scss',
    themes: ['dark']
  }
})5.2 组件使用 
vue
<!-- pages/index.vue -->
<template>
  <div>
    <el-button @click="handleClick">Click me</el-button>
    <el-message-box v-model="visible" title="Title">
      Content
    </el-message-box>
  </div>
</template>
<script setup>
const visible = ref(false)
const handleClick = () => {
  ElMessage.success('Hello from SSR!')
}
</script>6. Next.js 集成 
6.1 配置 Next.js 
javascript
// next.config.js
const withTM = require('next-transpile-modules')([
  'element-plus'
])
module.exports = withTM({
  // 其他配置
})6.2 动态导入 
typescript
// components/ElementPlusComponents.tsx
import dynamic from 'next/dynamic'
const ElButton = dynamic(
  () => import('element-plus').then(mod => mod.ElButton),
  { ssr: false }
)
export { ElButton }7. 性能优化 
7.1 按需加载 
typescript
// 只在需要时加载组件
const LazyDialog = defineAsyncComponent(() => 
  import('element-plus').then(mod => mod.ElDialog)
)7.2 预加载关键组件 
typescript
// 预加载常用组件
const preloadComponents = () => {
  import('element-plus/es/components/button')
  import('element-plus/es/components/input')
  import('element-plus/es/components/form')
}
if (process.client) {
  preloadComponents()
}8. 实践练习 
练习1:Nuxt 3 项目搭建 
bash
# 创建 Nuxt 3 项目
npx nuxi@latest init element-plus-ssr
cd element-plus-ssr
# 安装 Element Plus
npm install @element-plus/nuxt -D
# 配置和运行
npm run dev练习2:解决水合错误 
vue
<!-- 创建一个避免水合错误的组件 -->
<template>
  <div>
    <ClientOnly>
      <el-date-picker 
        v-model="selectedDate"
        type="datetime"
        placeholder="Select date and time"
      />
    </ClientOnly>
  </div>
</template>
<script setup>
const selectedDate = ref(new Date())
</script>练习3:SSR 性能测试 
typescript
// 测试 SSR 性能
const measureSSRPerformance = () => {
  const start = performance.now()
  
  // 渲染组件
  const app = createSSRApp(App)
  const html = renderToString(app)
  
  const end = performance.now()
  console.log(`SSR rendering took ${end - start} milliseconds`)
  
  return html
}学习资源 
作业 
- 搭建一个 Element Plus + Nuxt 3 的 SSR 项目
- 解决项目中的水合错误问题
- 优化 SSR 性能和首屏加载时间
下一步 
明天我们将学习 Element Plus 的 Teleport 机制与弹出层处理。