Skip to content

自定义指令

回忆 Vue3 中自定义指令:

<template>
<input v-focus />
</template>
<script setup>
const vFocus = {
mounted: (el) => el.focus(),
}
</script>

在 SSR 模式下,由于没有真实的 DOM,Vue 在渲染阶段不会执行大部分直接操作 DOM 的自定义指令逻辑,比如 mounted 钩子中对 DOM 元素的修改(例如设置元素的 id、class 或样式等)。

为了在 SSR 中也能“呈现出”自定义指令想要产生的效果,Vue3 引入了一个特殊的钩子函数:getSSRProps。该钩子函数的作用是在服务器端渲染期间,将自定义指令需要作用于渲染结果上的属性提前返回,然后 Vue 将这些属性合并到最终生成的 HTML 元素中。

例如:

// 自定义指令
const myDirective = {
mounted(el, binding) {
// 这是属于客户端的实现
// 设置元素的 id,相当于直接更新 DOM
el.id = binding.value
},
getSSRProps(binding) {
// 会在服务端执行
// 可以返回一个对象,该对象就是需要渲染的属性的键值对
return {
id: binding.value,
}
},
}

有些时候我们希望指令根据绑定值做一些条件渲染,在 SSR 中也保持一致。举个例子:如果绑定值为真,则添加某个属性,否则不添加。

此时要让 SSR 渲染和客户端渲染保持一致,可以这样做:

const vConditionalDirective = {
mounted(el, binding) {
// 客户端:根据绑定值添加或移除 class
if (binding.value) {
el.classList.add('active')
} else {
el.classList.remove('active')
}
},
getSSRProps(binding) {
// 服务端:如果绑定值为 true,则返回 class 属性
if (binding.value) {
return { class: 'active' }
}
// 返回空对象表示不需要添加任何属性
return {}
},
}

在模板中使用:

<template>
<!-- 当传入 true 时,元素会拥有 active 样式类 -->
<div v-conditional-directive="true">Conditional SSR</div>
</template>

课堂练习

在很多项目中,我们希望在元素上显示一个自定义的提示信息,客户端可以使用 Popper.js、Tippy.js 或自定义代码来实现丰富的交互效果;但在服务端渲染时,由于没有 DOM 操作,无法创建复杂的 tooltip,通常我们希望输出一个标准的 title 属性来提供基本的提示。

Nuxt注册自定义指令

首先拿到 Vue 实例,然后在此基础上进行注册:

export default defineNuxtPlugin((nuxtApp) => {
// 通过 nuxtApp.vueApp 拿到 Vue 的实例,之后的注册方式和原生 Vue 是一样的
nuxtApp.vueApp.directive('focus', {
mounted(el) {
el.focus()
},
getSSRProps(binding, vnode) {
// 你可以在这里提供SSR特定的props
return {}
},
})
})

-EOF-