vue3.0+vite项目中使用JSX语法
导读
vue3提供了强大的JSX/TSX的支持,我们该怎样上手并使用呢?请看本文总结的一些经验。
安装vite插件
首先,我们要在vite下支持,需要我们安装插件@vitejs/plugin-vue-jsx
npm i @vitejs/plugin-vue-jsx -D
之后,我们需要在vite.config.js中加上我们的插件
export default defineConfig({
plugins: [vue(),vueJsx()],
})
在SFC中使用
如果需要在.vue文件中使用jsx,我们必须将script中的lang设置为jsx
,在我们的setup函数中返回这个模板,且return的返回需要写成箭头函数的形式(和React的JSX直接返回不太一样)
<script lang="jsx">
import {defineComponent} from "vue"
export default defineComponent({
name:"app",
setup(props,ctx){
return ()=><div> zerotower </div>
}
})
</script>
在.jsx中使用
定义多个模板
函数式组件
语法说明
此章节简要说明jsx在vue中的一些语法。
插值
与template
中的{{}}
相比,jsx中使用{}
import {defineComponent, ref} from "vue"
export default defineComponent({
name:"app",
setup(props,ctx){
const msg=ref('zerotower')
return ()=><div> {msg.value} </div>
}
})
而且,你依然需要使用.value
这样的写法。
条件渲染v-if
在JSX
中已经没有了template
中的v-if
,而是使用原生if(更多情况下使用三元表达式)
import {defineComponent, ref} from "vue"
export default defineComponent({
name:"app",
setup(props,ctx){
const msg=ref('zerotower')
const body=<div>{msg.value}</div>
const visible=ref(false);
return ()=><div> {visible.value? body:<></>} </div>
}
})
并建议jsx片段复杂时,尽可能使用语义明确的变量另外声明jsx片段,以增强代码的可读性。
条件渲染v-show
条件渲染除了v-if
还有v-show
,JSX
虽然不支持v-if
却能支持v-show
import {defineComponent, ref} from "vue"
export default defineComponent({
name:"app",
setup(props,ctx){
const msg=ref('zerotower');
const canshow=ref(true)
return ()=><div v-show={!canshow.value}> zerotower </div>
}
})
列表循环v-for
在SFC中我们会使用v-for
来渲染列表数据,但是在JSX中我们需要使用map
来渲染列表。
import {defineComponent, ref} from "vue"
export default defineComponent({
name:"app",
setup(props,ctx){
const nameList=ref(['David','Susan','Jack'])
return ()=><div> {
nameList.value.map((name,index)=>(<div key={index}>name:{name}</div>))
} </div>
}
})
需要注意的是,即使是JSX,我们仍然要明确地指定key。
事件绑定
例如,我们在SFC经常使用@click
这样的语法,其等价于v-on:click
这样的写法。但在JSX中,我们需要使用onClick
的写法来进行事件的绑定,下面是一个计数器的参考例子:
import {defineComponent, ref} from "vue"
export default defineComponent({
name:"app",
setup(props,ctx){
const count=ref(0);
function handleCount(){
count.value++;
}
return ()=><div>
<div>{count.value}</div>
<button onClick={handleCount}>+</button>
</div>
}
})
但如果,我们的handleCount
需要传递一些参数,就得写成箭头函数调用的形式:
function handleCount(step){
count.value+=step;
}
return ()=><div>
<div>{count.value}</div>
<button onClick={()=>handleCount(3)}>+</button>
</div>
}
事件修饰符
如果我们需要使用vue提供的一些事件修饰符,我们需要借助于withModifiers
方法,以下是使用.self
的例子:
import {defineComponent, ref,withModifiers} from "vue"
export default defineComponent({
name:"app",
setup(props,ctx){
return ()=><div>
<div onClick={withModifiers(()=>{console.log('我被命中了')},["self"])}><span>zerotower</span></div>
</div>
}
})
但是对于修饰符.passive
、.capture
、.once
,withModifiers
并不生效,我们需要使用链式驼峰的写法,以下是使用.once
的一个例子:
import {defineComponent, ref,withModifiers} from "vue"
export default defineComponent({
name:"app",
setup(props,ctx){
return ()=><div>
<div onClickOnce={()=>{console.log('我被命中了')}}><span>zerotower</span></div>
</div>
}
})
v-model数据绑定
JSX
中是可以直接使用v-model的,如下所示:
import {defineComponent, ref} from "vue"
export default defineComponent({
name:"app",
setup(props,ctx){
const text=ref("")
return ()=><div>
<input type="text" v-model={text.value}/>
</div>
}
})
但是,对于组件的自定义事件,例如elementPlus的el-pagination
组件,在SFC中可能写成这样:
<el-pagination v-model:currentPage="current" v-model:size="size"></el-pagination>
但在JSX
中得按照这样的写法:
<el-pagination v-model:current-page={current.value} v-model:size={size.value} layout="prev,pager,next" total={total.value}></el-pagination>
插槽
vue中最强大的一部分无疑是插槽了,让我们看看JSX中是如何使用的吧。
普通插槽
我们首先创建一个子组件(如果子组件比较简单,我们可以直接定义在父组件所在的文件中)
import {defineComponent, ref} from "vue"
export default defineComponent({
name:"app",
setup(props,ctx){
const Child =(props,{slots})=>{
return <div>{slots.default()}</div>
}
return ()=><div>
<Child>我是默认插槽,普普通通的</Child>
</div>
}
})
具名插槽
如果是具名插槽,我们则通过对象的形式传入,每一个key是插槽的名字,value是一个箭头函数,其返回JSX片段。如下所示:
import {defineComponent, ref} from "vue"
export default defineComponent({
name:"app",
setup(props,ctx){
const Child =(props,{slots})=>{
return <div>
<div>{slots.one()}</div>
<div>{slots.two()}</div>
<div>{slots.three()}</div>
</div>
}
return ()=><div>
<Child>{
{
one:()=><span>我是插槽1</span>,
two:()=><span>我是插槽2</span>,
three:()=><span>我是插槽3</span>
}
}</Child>
</div>
}
})
作用域插槽
作用域插槽写成JSX反而更容易理解一些,插槽传进来是一个函数,那么子组件的作用域的变量势必也是传入函数的参数,这个参数是由子组件提供并绑定的。请看下例所示:
import {defineComponent, ref} from "vue"
export default defineComponent({
name:"app",
setup(props,ctx){
const Child =(props,{slots})=>{
const arg=ref('我是插槽1,我躲在子组件里,快来抓我啊')
return <div>
<div>{slots.one(arg.value)}</div>
<div>{slots.two()}</div>
<div>{slots.three()}</div>
</div>
}
return ()=><div>
<Child>{
{
one:(arg)=><span>{arg}</span>,
two:()=><span>我是插槽2</span>,
three:()=><span>我是插槽3</span>
}
}</Child>
</div>
}
})
总结
Vue3中的JSX给予了我们更强大的创建组件的能力,同时也方便React的小伙伴更好地熟悉和掌握Vue。但Vue3中的JSX和React的相比还是有一定地差距,语法上还是有一些繁琐的,但我觉得其插槽的部分还是比较友好的,也便于概念上的理解。具体使用什么语法,我觉得可以根据实际需要来采用,我一般会以template为主,一些复杂的功能使用JSX。我的下一篇文章就会在Cesium中使用气泡弹窗来具体例证在Vue3中使用JSX的必要性。
转载自:https://juejin.cn/post/7239744255674400825