找回密码
 立即注册
首页 业界区 业界 利用Vue元素指令自动合并tailwind类名

利用Vue元素指令自动合并tailwind类名

周冰心 1 小时前
利用Vue元素指令自动合并Tailwind类名

Tailwind CSS是一套将常用的CSS样式封装成类名的工具库。例如p-4表示设置元素的内边距为4,bg-red-500表示设置元素的背景颜色为红色,rounded-md表示将设置元素的边框圆角为中等大小。
在构建时,Tailwind会扫描项目中的HTML文件,提取使用到的类名,并生成对应的CSS样式,如:
  1. .p-4 { padding: 1rem; }
  2. .bg-red-500 { background-color: #EF4444; }
  3. .rounded-md { border-radius: 0.375rem; }
复制代码
当同一个元素设置了多个相同属性的类名时,根据CSS的层叠规则,最后生成的CSS样式表中后出现的类名会覆盖前面出现的类名,而与HTML中类名的顺序无关,如:
  1. 文本是红色的
  2. 文本也是红色的
复制代码
在实际应用中,我们往往希望在实例上覆盖先前设置的默认类,tailwind-merge库提供了twMerge函数,用于实现该功能。
具体来说,twMerge会将传入的类名字符串进行合并,对于同一属性的类名,只有最后一个出现的会被保留。例如:
  1. twMerge("text-blue-500 text-red-500") // 返回 "text-red-500"
  2. twMerge("text-red-500 text-blue-500") // 返回 "text-blue-500"
复制代码
通过使用twMerge,我们可以确保在动态生成类名时,最终应用的样式是我们期望的,而不受CSS样式表类名顺序的影响。
在Vue中使用twMerge

Vue提供了非常方便的类名传透机制,给组件实例指定的类名会自动传递给子组件的根元素,添加到子组件内部定义的类名列表末尾。
然而,对于Tailwind类名,这种简单的合并方式可能会导致样式冲突,如:
  1. <template>
  2. <template>
  3.     <slot></slot>
  4. </template><slot></slot>
  5. </template>
复制代码
  1. <CustomDiv >演示</CustomDiv>
复制代码
在上述示例中,CustomDiv组件内部定义了bg-red-500和rounded-none类,而父组件传递了bg-blue-500和rounded-md类,最终的类名会被合并为bg-red-500 rounded-none bg-blue-500 rounded-md。实际渲染结果为红色背景(bg-red-500覆盖了bg-blue-500)、无圆角(rounded-none覆盖了rounded-md),而不是预期的蓝色背景、有圆角(bg-blue-500 rounded-md)。
为了处理这种情况,我们需要在Vue组件中手动使用twMerge函数来合并类名。
  1. <template>
  2. <template>
  3.     <slot></slot>
  4. </template><slot></slot>
  5. </template>
复制代码
为了一个简单的功能,我们必须给每个组件都添加类似的代码来处理类名合并,这显然不是一个优雅的解决方案。
使用Vue指令自动应用twMerge

指令(Directive)是Vue提供的一种特殊语法,可以施加到HTML元素上,来对元素进行一些底层的操作。我们可以创建一个自定义指令来给元素自动应用twMerge函数,从而简化在组件中合并Tailwind类名的过程。
  1. import { twMerge } from 'tailwind-merge'function mergeClassName(el) {<template>
  2. <template>
  3.     <slot></slot>
  4. </template><slot></slot>
  5. </template>if (!el.getAttribute('class')) return<template>
  6. <template>
  7.     <slot></slot>
  8. </template><slot></slot>
  9. </template>if (el.namespaceURI === 'http://www.w3.org/2000/svg') {<template>
  10. <template>
  11.     <slot></slot>
  12. </template><slot></slot>
  13. </template><template>
  14. <template>
  15.     <slot></slot>
  16. </template><slot></slot>
  17. </template>el.setAttribute('class', twMerge(el.getAttribute('class') || ""))<template>
  18. <template>
  19.     <slot></slot>
  20. </template><slot></slot>
  21. </template>} else {<template>
  22. <template>
  23.     <slot></slot>
  24. </template><slot></slot>
  25. </template><template>
  26. <template>
  27.     <slot></slot>
  28. </template><slot></slot>
  29. </template>el.className = twMerge(el.className)<template>
  30. <template>
  31.     <slot></slot>
  32. </template><slot></slot>
  33. </template>}}const twMergeDirective = { mounted: mergeClassName, updated: mergeClassName }
复制代码
使用方法
  1. // 在Vue app中注册指令
  2. app.directive("twMerge", twMergeDirective)
复制代码
之后就可以在HTML元素上使用v-tw-merge指令来自动应用twMerge函数了:
  1. 红色背景,无圆角
  2. 蓝色背景,有圆角
  3. <CustomDiv >原生: 红色背景,无圆角</CustomDiv>
  4. <CustomDiv  v-tw-merge>v-tw-merge: 蓝色背景,有圆角</CustomDiv>
复制代码
渲染结果为
  1. 原生: 红色背景,无圆角
  2. v-tw-merge: 蓝色背景,有圆角
  3. 原生: 红色背景,无圆角
  4. v-tw-merge: 蓝色背景,有圆角
复制代码
附:完整的单页html<CustomDiv >演示</CustomDiv>代码

完整示例代码(点击展开)
  1. <template>
  2. <template>
  3.     <slot></slot>
  4. </template><slot></slot>
  5. </template><template>
  6. <template>
  7.     <slot></slot>
  8. </template><slot></slot>
  9. </template><template>
  10. <template>
  11.     <slot></slot>
  12. </template><slot></slot>
  13. </template><template>
  14. <template>
  15.     <slot></slot>
  16. </template><slot></slot>
  17. </template><template>
  18. <template>
  19.     <slot></slot>
  20. </template><slot></slot>
  21. </template><template>
  22. <template>
  23.     <slot></slot>
  24. </template><slot></slot>
  25. </template>原生: 红色背景,无圆角<template>
  26. <template>
  27.     <slot></slot>
  28. </template><slot></slot>
  29. </template><template>
  30. <template>
  31.     <slot></slot>
  32. </template><slot></slot>
  33. </template>v-tw-merge: 蓝色背景,有圆角<template>
  34. <template>
  35.     <slot></slot>
  36. </template><slot></slot>
  37. </template><template>
  38. <template>
  39.     <slot></slot>
  40. </template><slot></slot>
  41. </template>原生: 红色背景,无圆角<template>
  42. <template>
  43.     <slot></slot>
  44. </template><slot></slot>
  45. </template><template>
  46. <template>
  47.     <slot></slot>
  48. </template><slot></slot>
  49. </template>v-tw-merge: 蓝色背景,有圆角<template>
  50. <template>
  51.     <slot></slot>
  52. </template><slot></slot>
  53. </template><template>
  54. <template>
  55.     <slot></slot>
  56. </template><slot></slot>
  57. </template><template>
  58. <template>
  59.     <slot></slot>
  60. </template><slot></slot>
  61. </template>
复制代码
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

相关推荐

您需要登录后才可以回帖 登录 | 立即注册