vue 中使用 jsx
调用方式
-
标签函数组件
// 模式1: 类式函数组件 const Sub = { functional: true, name: "Sub", render(h, context){...} } // 模式2: 函数式函数组件 const Sub = (context) => ( <div> { context.props.title } </div> ) // 标签式调用 <template> <Sub title='函数式组件' /> </template> // 注册为组件 { components: { 'l-sub': Sub } } // 可以直接使用函数作为组件的原因是,vue会将函数式函数组件 转换为 类式函数组件
-
函数组件
// 可以使用直接调用函数的形式调用组件 function Sub(h, title){ return ( <div> { title } </div> ) } // 调用 { render(h){ return ( <div> { Sub("jsx title") } </div> ) } } // 这里 h[createElement] 函数是必须的, vue 将使用该函数渲染组件
为什么存在两种调用模式
这里我们可以直接打印出组件函数,查看vue对两者的不同处理
- 标签模式
const Tagsub = (context) => ( <div> { context.props.title } </div> )
console.log(Tagsub)
/**
* {
functional: true,
name: "Sub",
render(h, context){...}
}
*/
- 函数模式
function Fnsub(h, title){
return ( <div> { title } </div> )
}
console.log(Fnsub)
/**
ƒ Fnsub(h, title) {
return h("div", [" ", title, " "]);
}
*/
通过比较我们知道,vue 对不同编写方式的不同解析,造成了不同的调用方式, 所以虽然都是函数式组件,
但
标签模式
不能直接通过函数的方式调用,因为已经被编译成类而
函数模式
需要传入 createElement 函数, 且不能作为标签直接调用,应为无法获取到 createElement函数除此外,两者获取的参数也是有所不同.
传值/取值
标签类函数组件 通过 context 参数获取组件上的参数 详情
函数类函数组件 可以参考 react 传参, 函数接收的参数既是组件获取的参数
插槽
jsx 中没有
<slot />
标签, 我们可以通过高阶函数 或$scopedSlots
属性 提供组件嵌套功能
-
高阶函数
const Title = context => <h1> title </h1> const Content = context => <p> content </p> const Wrap =(Title, Content) => { return { render(h){ return ( <div> <Title /> <Content /> </div> ) } } } // 使用1: 注册为组件 { components: { article: Wrap(Title, Content) } } // 使用2:jsx { render(h){ const Article = Wrap(Title, Content) return ( <Article /> ) } }
这里 Wrap 返回一个组件类,而不是直接返回标签模板, 如果直接返回标签模板, Wrap 将被识别为函数组件而不是单纯的包装函数
-
属性
// 类似 react children 我们可以将组件作为属性传给嵌套组件 const Title = context => <h1> { context.props.title } </h1> const Content = context => <p> content </p> const Article = context => { const Title = context.props.title const Content = context.props.content return ( <div> <Title title='article title' /> <Content /> </div> ) } // 使用1: 注册为组件 { components: { Article } } // 使用2:jsx { render(h){ return ( <Article title={ Title } content={Content} /> ) } }
$scopedSlots
// vue 原生提供插槽属性, 我们可以直接使用该属性 实现嵌套
// 设置作用域插槽
const Article = context => {
// 因为需要获取参数,所以作用域插槽返回函数
const titleSlot = context.scopedSlots.title
const contentSlot = context.scopedSlots.content
return (
<div>
{ titleSlot({title: 'article title'}) }
{ contentSlot({content: 'article content'}) }
</div>
)
}
// 使用1: 标签
<template>
<Article>
<h1 slot='title' slot-scope="slotProps">
{{ slotProps.title }}
</h1>
<p slot='content' slot-scope="slotProps">
{{ slotProps.content }}
</p>
</Article>
</template>
<script>
export default {
components: {
Article
}
}
</script>
// 使用2:jsx
{
render(h){
const scopedSlots = {
title: data => (<h1> { data.title } </h1>),
content: data => ( <p> { data.content } </p> )
}
return (
<Article scopedSlots={ scopedSlots } />
)
}
}