组件属性
组件属性(props)是父组件向子组件传递数据的主要方式。在 Vitarx 中,props 通过函数参数接收,且是只读的。
声明组件 Props
使用 TypeScript 接口或类型别名来声明组件的 props:
tsx
import { ref } from 'vitarx'
// 用接口声明 props 类型
interface GreetingProps {
name: string
age?: number // 可选属性
}
function Greeting(props: GreetingProps) {
return (
<div>
<p>你好,{props.name}!</p>
{props.age && <p>年龄:{props.age}</p>}
</div>
)
}
// 使用组件
function App() {
return <Greeting name="小明" age={18} />
}也可以直接在参数中声明类型:
tsx
function Greeting(props: { name: string; age?: number }) {
return <div>你好,{props.name}!</div>
}Props 是只读的
组件接收到的 props 对象是只读的,不要直接修改它。在开发模式下,尝试修改 props 会抛出错误。
tsx
// ❌ 错误:不要修改 props
function BadComponent(props: { count: number }) {
props.count = 10 // 开发模式下会报错
return <div>{props.count}</div>
}
// ✅ 正确:用 ref 管理本地状态
import { ref } from 'vitarx'
function GoodComponent(props: { count: number }) {
const localCount = ref(props.count)
return (
<div>
<span>{localCount}</span>
<button
onClick={() => {
localCount.value++
}}
>
增加
</button>
</div>
)
}内置特殊属性
Vitarx 为所有元素和组件提供了一些内置的特殊属性:
ref — 引用元素或组件实例
通过 ref 属性可以获取 DOM 元素或组件实例的引用:
tsx
import { useRef, onMounted } from 'vitarx'
function App() {
const elRef = useRef<HTMLDivElement>()
onMounted(() => {
// 挂载后可以访问 DOM 元素
console.log(elRef.value?.textContent)
})
return <div ref={elRef}>Hello</div>
}详细的 ref 用法请参考 组件引用。
children — 子节点
组件标签内的内容会通过 children 属性传递给组件:
tsx
function Card(props: { title: string; children?: any }) {
return (
<div class="card">
<h2>{props.title}</h2>
<div class="card-body">{props.children}</div>
</div>
)
}
// 使用
function App() {
return (
<Card title="用户信息">
<p>这是卡片的内容</p>
</Card>
)
}详细的 children 用法请参考 子节点与插槽。
v-bind — 属性透传绑定
v-bind 用于将一个对象的所有属性绑定到元素上,常用于属性透传场景:
tsx
// v-bind 接受一个对象,将所有属性绑定到元素
function MyButton(props: { class?: string; onClick?: () => void }) {
return <button v-bind={props}>按钮</button>
}
// 也可以排除某些属性
function MyInput(props: { class?: string; value?: string; onChange?: () => void }) {
return (
<input
v-bind={[props, ['onChange']]} // 透传 props,但排除 onChange
onInput={(e) => {
/* 自定义处理 */
}}
/>
)
}v-bind 的两种形式:
- 对象形式:
v-bind={obj}— 将 obj 的所有属性绑定到元素 - 数组形式:
v-bind={[obj, exclude]}— 绑定 obj 的属性,但排除 exclude 数组中指定的属性
注意:
v-bind不能用于绑定全局属性(如 ref、children)。
v-html — 绑定 HTML 内容
v-html 用于设置元素的 innerHTML,可以传入字符串或 ref:
tsx
import { ref } from 'vitarx'
function RichText() {
const html = ref('<strong>加粗文本</strong>')
return <div v-html={html} />
}
v-html仅支持用于<div>、<p>、<span>等块级 HTML 元素。注意防范 XSS 攻击,不要将用户输入直接作为 HTML 渲染。
v-show — 显示/隐藏元素
v-show 通过设置 display: none 来控制元素的显示与隐藏:
tsx
import { ref } from 'vitarx'
function TogglePanel() {
const visible = ref(true)
return (
<div>
<button
onClick={() => {
visible.value = !visible.value
}}
>
切换
</button>
<div v-show={visible}>这段内容可以显示或隐藏</div>
</div>
)
}v-text — 绑定文本内容
v-text 用于设置元素的文本内容:
tsx
import { ref } from 'vitarx'
function Message() {
const text = ref('Hello World')
return <div v-text={text} />
}默认值 — defaultProps
当外部未传入某个属性时,可以通过组件的 defaultProps 静态属性提供默认值:
tsx
import { ref } from 'vitarx'
interface ButtonProps {
type?: 'primary' | 'default'
size?: 'small' | 'medium' | 'large'
disabled?: boolean
children?: any
}
function Button(props: ButtonProps) {
// props.type、props.size、props.disabled 都会有默认值
const classList = `btn btn-#123;props.type} btn-#123;props.size}`
return (
<button class={classList} disabled={props.disabled}>
{props.children}
</button>
)
}
// 设置默认属性
Button.defaultProps = {
type: 'default',
size: 'medium',
disabled: false
}
// 使用 — 不传 type 和 size 时使用默认值
function App() {
return (
<div>
<Button>默认按钮</Button>
<Button type="primary" size="large">
主要按钮
</Button>
</div>
)
}属性验证 — defineValidate
defineValidate 用于在开发模式下校验传入的 props 是否符合预期。校验只在开发模式下生效,生产模式下不会执行。
校验函数的返回值:
false:打印默认的校验失败错误信息string:打印该字符串作为警告信息- 抛出异常:阻止组件继续渲染
- 其他值 / void:校验通过
tsx
import { defineValidate } from 'vitarx'
interface UserProps {
name: string
age: number
email?: string
}
function UserCard(props: UserProps) {
return (
<div>
<p>姓名:{props.name}</p>
<p>年龄:{props.age}</p>
{props.email && <p>邮箱:{props.email}</p>}
</div>
)
}
// 定义属性验证
defineValidate(UserCard, (props) => {
if (!props.name) {
return 'name 属性不能为空'
}
if (props.age < 0) {
return 'age 不能为负数'
}
if (props.age > 150) {
return 'age 不合理,请检查'
}
// 返回 void 表示校验通过
})完整示例
下面是一个综合运用 props 各项特性的完整示例:
tsx
import { ref, defineValidate } from 'vitarx'
// 声明 props 类型
interface AlertProps {
type?: 'info' | 'success' | 'warning' | 'error'
title: string
closable?: boolean
children?: any
}
function Alert(props: AlertProps) {
const visible = ref(true)
const handleClose = () => {
visible.value = false
}
// 根据 type 选择样式类名
const alertClass = `alert alert-#123;props.type}`
return (
<div class={alertClass} v-show={visible}>
<div class="alert-header">
<span class="alert-title">{props.title}</span>
{props.closable && (
<button class="alert-close" onClick={handleClose}>
×
</button>
)}
</div>
<div class="alert-body">{props.children}</div>
</div>
)
}
// 设置默认值
Alert.defaultProps = {
type: 'info',
closable: false
}
// 属性验证
defineValidate(Alert, (props) => {
if (!props.title) {
return 'Alert 组件的 title 属性是必填的'
}
})
// 使用
function App() {
return (
<div>
<Alert title="提示">这是一条普通提示信息</Alert>
<Alert type="success" title="成功" closable>
操作已完成!
</Alert>
<Alert type="error" title="错误" closable>
操作失败,请重试。
</Alert>
</div>
)
}