在 Vue3.5 这个版本中,新增了 useId 这一个 API,它的功能是用来生成一个 唯一的ID,为什么说它生成的 ID 是唯一的呢?我们可以来看看 useID 的源码,你就知道了。
其实原理很简单,就是调用 getCurrentInstance 这个,这个 API 会返回当前 Vue 实例的信息对象,而这个信息对象身上有一个 ids 的数组,而 useId 就是根据这个数组去生成唯一 ID 的。
图片
- appContext.config.idPrefix: 这是可全局配置的 ID 前缀,如果你不配置,那就默认是 v。
- ids[0] + ids[1]++: 由唯一的 ids[0] 和递增的 ids[1] 来实现同实例内与不同实例时间的唯一性。
想要设置 appContext.config.idPrefix 可以在 main.ts 中去设置。
图片
接下来讲一下 useId 都有哪些比较实用且常用的场景吧!
表单对应标识
表单中,我们会使用 label 来做表单项的展示文本,我们想要点击这个展示文本,能自动聚焦到表单项上,那么我们可以同时给 label、表单项标签 设置上一个一样的 ID。
图片
图片
v-for 唯一 key
大家都知道,在 Vue 中使用 v-for 去循环遍历一个列表的时候,需要给每一个遍历项加上一个唯一 key ,确保 DOM 更新的时候能得到一定的性能提升,我们可以使用 useID 来生成一个唯一 key。
图片
图片
服务端渲染保持唯一性
使用 服务端渲染(SSR) 的应用里,页面的 HTML 是由服务器生成的,随后被传送到客户端的浏览器。当浏览器接收到这些 HTML 内容后,会将其转变为一个可交互的页面。然而,倘若服务器端与客户端生成的 HTML 中具有相同的 ID,在客户端进行 激活(hydrate) 操作时,就有可能出现问题。因为客户端可能会试图对一个已经被服务器端渲染好的 DOM元 素进行操作,这样就会引发潜在的冲突或者错误。
可以通过一个小例子来说明这个问题。
服务端代码
图片
客户端代码
图片
在这个案例中,无论是服务端还是客户端,我们都使用了 createSSRApp(App) 来创建应用实例。如果我们在 App.vue 中使用了 useId 来生成 ID,那么这些 ID 将在服务端渲染时生成一次,并在客户端激活时再次使用相同的 ID。
App.vue
图片
在 App.vue 组件里,我们借助 useId为 <input> 元素创建了一个独一无二的 ID。此 ID 在服务端渲染阶段生成,并被纳入发送至客户端的HTML之中。当客户端接收到该HTML并展开激活流程时,鉴于useId所生成的ID在服务端和客户端保持一致,客户端便能准确地把 <label> 元素与 <input> 元素相关联,从而避免出现 ID 冲突的情况。
倘若不使用 useId,而是采用 Math.random() 或者 Date.now() 来生成 ID,那么服务端和客户端有可能生成不一样的ID。这就会致使客户端在激活时无法正确地将 <label> 与 <input> 关联起来,因为二者的 ID 存在差异。这种情况或许会致使表单元素出现行为异常,比如点击 <label> 时,<input> 却不能获取焦点。
组件库中 ID 的生成
在运用 Element Plus 等组件库开展 SSR 开发的过程中,为防止出现 hydration 错误,务必要保证服务器端和客户端所生成的 ID 是一致的。向 Vue 中注入 ID_injection_key 这一操作,能够确保 Element Plus 所生成的 ID 在 SSR 里具备唯一性。
图片