likes
comments
collection
share

vue3.0+vite项目中使用JSX语法

作者站长头像
站长
· 阅读数 17

导读

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-showJSX虽然不支持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.oncewithModifiers并不生效,我们需要使用链式驼峰的写法,以下是使用.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
评论
请登录