Skip to main content

Vue 3 With Vite

组件模板要有根节点

虽然 v3 不需要指定一个根节点,开发时很方便,但是会导致外部使用组件时没办法当成一个正常的 vnode 节点去使用。 导致诸如 class 等属性无法穿透至组件内部,因为 vue 无法知道 class 要作用在哪个节点上。 同时,控制台也会抛出提示:

[Vue warn]: Extraneous non-props attributes (calss) were passed to component but could not be automatically inherited because component renders fragment or text root nodes. 官方叫做 Attributes 继承。

Bad

// ComponentA
<template>
<div></div>
<div></div>
...
</template>
// App
<template>
<!-- 该 class 属性无效 -->
<ComponentA class="mt-2" />
</template>

Good

// ComponentA
<template>
<div>
<div></div>
<div></div>
...
</div>
</template>
// App
<template>
<!-- 该 class 属性可生效 -->
<ComponentA class="mt-2" />
</template>

当然,官方也有手动定义属性穿透的方法,可以看看稳定 总结,保持 v2 的良好习惯永远包一层根节点,一定没错。

不要解构 setup() 的传参 props

结构了 props 会失去响应特性。无法接收父组件的 props 更新。

  • Good: setup(props) {}
  • Bad: setup({ a, b, c }) {}

若要结构,则需用 toRefs() 让解构后的对象跟踪原 props.xxx。此为 Vue 内置的机制,该理念在 React 不适用。

  • 解构并跟踪:const { a, b, c } = toRefs(props)
  • 读取响应式的值:a.value

安装 PostCSS 并使用 Tailwindcss

https://tailwindcss.com/docs/installation/using-postcss

在 jsx 中渲染插槽内容

官方将知识点分散在文档多个地方,却没有完整示例,对新手不友好。

/src/components/Page.jsx
import { h } from 'vue'

export default function(props, context) {

return <div>{ h(context.slots.default) }</div>
}
/src/App.vue
<script setup>
import { RouterView } from 'vue-router'
import Page from '@/components/Page'
</script>

<template>
<Page>
<RouterView />
</Page>
</template>

阻止自动透传

Vue 会自动将父组件传入的 class 传入至组件内部,并且跟子组件自己的 class 合并。 官方术语叫样式合并(class-and-style-merging):https://cn.vuejs.org/guide/components/attrs.html#class-and-style-merging

但是,这个机制在 jsx 语法下会有问题:

当子组件内部用 className 去定义样式时: 父组件无法以 class 传入自定义样式到子组件中并触发自动合并,最终效果不如预期。 父组件传入的 class 会直接覆盖掉子组件在 className 定义好的的样式。 如果改为父组件传入 className 则不会有自动合并,要手动合并。

解决方案:最佳方式是永远将 CSS 类都放到 className,并在组件内部手动合并传入的样式

const TheComponent = (props) => 
<div className={`screen ${props.className || ''} ${props.class || ''}`}></div>

// 将传入的 CSS 类声明为 props,阻止 Vue 的自动透传
TheComponent.props = ['className', 'class']

父组件没传 className 或 class 会导致输出 'undefined' 字符串,因此要注意注意给默认值 ${props.class || ''}