Vue3 tsx中插槽的使用
在 Vue 3 中使用 TSX 时,插槽(slots)依然是一个重要的功能。以下是如何在 Vue 3 + TSX 中使用插槽的详细说明和示例。
基本使用
假设你有一个 Button 组件,希望它能够接受插槽内容:
Button 组件
import { defineComponent, PropType } from 'vue';
const Button = defineComponent({
name: 'Button',
props: {
label: String,
},
setup(props, { slots }) {
return () => (
<button>
{slots.default ? slots.default() : props.label}
</button>
);
}
});
export default Button;
使用插槽
在父组件中,你可以通过 TSX 语法来使用插槽:
父组件
import { defineComponent } from 'vue';
import Button from './Button';
const ParentComponent = defineComponent({
name: 'ParentComponent',
setup() {
return () => (
<div>
<Button>
<span>Click Me!</span>
</Button>
</div>
);
}
});
export default ParentComponent;
具名插槽
如果你需要使用具名插槽,可以使用以下方式:
Button 组件(具名插槽)
import { defineComponent, PropType } from 'vue';
const Button = defineComponent({
name: 'Button',
props: {
label: String,
},
setup(props, { slots }) {
return () => (
<button>
{slots.icon && slots.icon()}
{slots.default ? slots.default() : props.label}
</button>
);
}
});
export default Button;
使用具名插槽
在父组件中使用具名插槽:
父组件(具名插槽)
import { defineComponent } from 'vue';
import Button from './Button';
const ParentComponent = defineComponent({
name: 'ParentComponent',
setup() {
return () => (
<div>
<Button>
{{
icon: () => <span>🔍</span>,
default: () => <span>Search</span>,
}}
</Button>
</div>
);
}
});
export default ParentComponent;
作用域插槽
对于作用域插槽,可以使用以下方式:
List 组件(作用域插槽)
import { defineComponent, PropType } from 'vue';
const List = defineComponent({
name: 'List',
props: {
items: {
type: Array as PropType<string[]>,
required: true,
},
},
setup(props, { slots }) {
return () => (
<ul>
{props.items.map((item, index) =>
slots.default ? slots.default({ item, index }) : <li>{item}</li>
)}
</ul>
);
}
});
export default List;
使用作用域插槽
在父组件中使用作用域插槽:
父组件(作用域插槽)
import { defineComponent } from 'vue';
import List from './List';
const ParentComponent = defineComponent({
name: 'ParentComponent',
setup() {
const items = ['Item 1', 'Item 2', 'Item 3'];
return () => (
<div>
<List items={items}>
{({ item, index }) => <li>{index}: {item}</li>}
</List>
</div>
);
}
});
export default ParentComponent;
总结
- 默认插槽:使用
slots.default()渲染默认插槽内容。 - 具名插槽:通过对象解构语法传递具名插槽。
- 作用域插槽:在插槽函数中传递参数,并在父组件中使用这些参数。
和react进行横向对比
Vue 3 的插槽和 React 的 children/props 功能有很多相似之处,但也有一些关键的区别。这些区别主要体现在语法、功能和使用方式上。以下是详细的对比和说明。
基本概念
React
在 React 中,组件之间的内容传递主要通过 children 和 props 完成。children 是一个特殊的 prop,用于传递嵌套的 JSX 元素。
Vue
在 Vue 中,插槽(slots)是组件内容分发的一种方式。插槽允许在父组件中定义模板内容,并将这些内容传递给子组件。
基本用法对比
React
定义子组件
const Button = ({ children }) => {
return <button>{children}</button>;
};
使用子组件
const App = () => {
return (
<Button>
<span>Click Me!</span>
</Button>
);
};
Vue 3 (使用 TSX)
定义子组件
import { defineComponent } from 'vue';
const Button = defineComponent({
setup(props, { slots }) {
return () => <button>{slots.default ? slots.default() : ''}</button>;
},
});
export default Button;
使用子组件
import { defineComponent } from 'vue';
import Button from './Button';
const App = defineComponent({
setup() {
return () => (
<Button>
<span>Click Me!</span>
</Button>
);
},
});
export default App;
具名插槽与自定义 prop
React
React 通过传递自定义的 prop 来实现具名插槽的效果:
定义子组件
const Button = ({ icon, children }) => {
return (
<button>
{icon && <span>{icon}</span>}
{children}
</button>
);
};
使用子组件
const App = () => {
return (
<Button icon={<span>🔍</span>}>
<span>Search</span>
</Button>
);
};
Vue 3 (使用 TSX)
Vue 3 通过具名插槽实现类似的效果:
定义子组件
import { defineComponent } from 'vue';
const Button = defineComponent({
setup(props, { slots }) {
return () => (
<button>
{slots.icon && slots.icon()}
{slots.default ? slots.default() : ''}
</button>
);
},
});
export default Button;
使用子组件
import { defineComponent } from 'vue';
import Button from './Button';
const App = defineComponent({
setup() {
return () => (
<Button>
{{
icon: () => <span>🔍</span>,
default: () => <span>Search</span>,
}}
</Button>
);
},
});
export default App;
作用域插槽与 render prop
React
React 通过 render prop 模式实现作用域插槽:
定义子组件
const List = ({ items, renderItem }) => {
return (
<ul>
{items.map((item, index) => (
<li key={index}>{renderItem(item, index)}</li>
))}
</ul>
);
};
使用子组件
const App = () => {
const items = ['Item 1', 'Item 2', 'Item 3'];
return (
<List items={items} renderItem={(item, index) => `${index}: ${item}`} />
);
};
Vue 3 (使用 TSX)
Vue 3 通过作用域插槽实现类似的功能:
定义子组件
import { defineComponent, PropType } from 'vue';
const List = defineComponent({
props: {
items: {
type: Array as PropType<string[]>,
required: true,
},
},
setup(props, { slots }) {
return () => (
<ul>
{props.items.map((item, index) =>
slots.default ? slots.default({ item, index }) : <li>{item}</li>
)}
</ul>
);
},
});
export default List;
使用子组件
import { defineComponent } from 'vue';
import List from './List';
const App = defineComponent({
setup() {
const items = ['Item 1', 'Item 2', 'Item 3'];
return () => (
<List items={items}>
{({ item, index }) => <li>{index}: {item}</li>}
</List>
);
},
});
export default App;
主要区别总结
-
语法:
- React 使用
children和自定义 prop 传递内容。 - Vue 使用
slots传递内容,具名插槽和作用域插槽通过特定的语法实现。
- React 使用
-
功能:
- React 的
children是一个特殊的 prop,可以是任意的 React 元素或组件。 - Vue 的插槽系统更为强大和灵活,支持具名插槽和作用域插槽,能够更加直观地处理复杂的内容分发。
- React 的
-
使用方式:
- React 更加依赖于组件的 props 来传递内容。
- Vue 提供了更直接的插槽系统,使得内容分发和传递更加结构化和语义化。
通过这些对比,你可以更清楚地了解在 Vue 3 中如何使用 TSX 来实现插槽,以及与 React 中 children 和 render props 的差异。