首页 > 其他分享 >Vue3 tsx 和 template 之间的相互使用

Vue3 tsx 和 template 之间的相互使用

时间:2024-12-12 14:24:26浏览次数:6  
标签:tsx 插槽 props list 写法 item template Vue3 jsx

本文会介绍多种场景下的 jsx 和 template 相互使用,主要内容是插槽,包含常规 slot、slot 传值 等场景,不涉及非常基础的 jsx 语法使用(类似 v-for 是 jsx 的 map 函数等诸如此类的不介绍),因此可能无法覆盖全面,还请多多包涵。

长期写 react 深知其痛,这也是我司也在向 vue 方向靠拢,对 vue 的接受度也还可以(主要是相对完备的 jsx 支持,实在不行就写 jsx)。作为 jsx 的拥趸,也不忘在 vue 里灌输 jsx 思想(滑稽),这也算是一个学习记录吧。

没有说 vue 的模板语法不好的意思,vue 里 jsx 出现就是为了解决某些痛点,互相补足。所以经常看到有文章阔谈 jsx 与 template 优劣,一堆人在下边吵,觉得属实没必要,取长补短而已。

tsx 写法使用

这里以 vant 为例

注意: jsx 无法使用 unplugin-vue-components 插件自动导入样式,且组件本身也需要手动导入。

子组件接收 props

JSX 写法目前还是比较繁琐的,即声明 TS 类型之后,还要再声明运行时的 props 声明。不过官方文档有说明未来会对该部分优化。相关说明

  • 常规 template 写法
<script setup lang="ts">
type MyProps = {
  list: number[]
}
const { list = [] } = defineProps<MyProps>()
</script>

<template>
  <div v-for="item in list">{{ item }}</div>
</template>

  • JSX 第一种写法(vue 3.3+ 支持,其实第二种更为常见)
export default defineComponent(
  (props: MyProps, ctx) => {
    const { list = [] } = props

    return () => (
      <>
        {list.map((item) => (
          <div>{item}</div>
        ))}
      </>
    )
  },
  {
    props: {
      list: {
        type: Array as PropType<number[]>,
        default: () => [],
      },
    },
  },
)
  • JSX 写法二
export default defineComponent<MyProps>({
  props: {
    list: {
      type: Array as PropType<number[]>,
      default: () => [],
    },
  },

  setup(props) {
    return () => <>{props.list?.map((item) => <div>{item}</div>)}</>
  },
})

image

slot 插槽

default slot(两种写法一致)

默认插槽的写法 jsx 和 template 都差不多,闭合标签内的内容默认插槽

  • template 默认插槽写法
<template>
  <van-button type="primary">
    <div>this is default slot</div>
  </van-button>
</template>
  • jsx 默认插槽写法
  return () => (
    <>
      <Button type="primary">
        <div>this is default slot</div>
      </Button>
    </>
  )

image

自定义插槽

比如 vant 的 cell 组件,给出了很多插槽,两种写法概括如下:

  1. template 可以使用 #xxx 的格式写
  2. jsx 需要在 v-slots 对象中定义,对象的 key 就是插槽名,value 必须是一个函数返回 VNode。
  • template 写法
<template>
  <van-cell title="标题">
    <template #icon>
      <van-icon name="setting-o" />
    </template>
    <template #right-icon>
      <div style="color: red;">right-icon 插槽</div>
    </template>
  </van-cell>
</template>
  • jsx 写法
  return () => (
    <Cell
      title="标题"
      v-slots={{
        icon: () => <Icon name="setting-o" />,
        'right-icon': () => <div style={{ color: 'red' }}>right-icon 插槽</div>,
      }}
    />
  )

jsx 写法中,插槽使用 v-slots 且对象的 value 必须是一个函数返回

image

插槽传值

这个例子实际上是一个虚拟列表的封装,但是内容有点多,就简化代码了,方便读

子组件的插槽传值写法

  • template 写法
<script setup lang="ts">
import { computed } from 'vue'
import type { MyProps } from './interface'

const { list } = defineProps<MyProps>()

const innerList = computed(() => {
  // 组件内部对传入的数据进行统一处理,回传给父组件自定义渲染
  return list.map((item) => item * 3)
})
</script>

<template>
  <header>header</header>
  <slot name="list" :list="innerList"></slot>
  <footer>footer</footer>
</template>
  • jsx 写法
import { computed, defineComponent, type SetupContext, type SlotsType, type VNode } from 'vue'
import type { MyProps } from './interface'

interface MySlot {
  list?: (props: number[]) => VNode[]
}

// jsx 中,props 的运行时校验仍需手动声明,vue 官方未来计划会对此部分优化,类似于 defineProps,
// https://cn.vuejs.org/api/general.html#function-signature
const myProps = {
  list: { type: Array, default: () => [] },
}

export default defineComponent(
  (props: MyProps, ctx: SetupContext<object, SlotsType<MySlot>>) => {
    const { list } = props

    const innerList = computed(() => {
      // 组件内部对传入的数据进行统一处理,回传给父组件自定义渲染
      return list.map((item) => item * 3)
    })

    return () => (
      <>
        <header>header</header>
        {ctx.slots.list?.(innerList.value)}
        <footer>footer</footer>
      </>
    )
  },
  {
    //声明 props 运行参数校验规则
    props: myProps,
  },
)

defineComponent 函数的第一个参数是回调函数,主要 jsx 代码就在这个回调函数里,第二个参数是一个对象,接收 props emits 等运行时参数

image

jsx 的插槽是通过 context 拿到 slots,然后调用函数的,这也刚好对应了为什么我们使用 jsx 的 v-slots 时,对象的 value 必须是一个函数了,因为在 jsx 中,组件接收插槽就是一个函数并调用它

父组件使用插槽传递的值

子组件就是上边的例子,我们分别使用 template 和 jsx 使用这个组件(Child 组件哪个写法都可以用)

  • 父组件使用 template 写法
<template>
  <Child :list="[1, 2, 3, 4, 5]">
    <template #list="{ list }">
      <div v-for="item in list" :key="item">{{ item }}</div>
    </template>
  </Child>
</template>
  • 父组件 jsx 写法
export default defineComponent(() => {
  return () => (
    <>
      <Child
        list={[1, 2, 3, 4, 5]}
        v-slots={{
          list: (list: number[]) => list.map((item) => <div key={item}>{item}</div>),
        }}
      />

      {/* 如果是默认插槽,则不使用 v-slots 也可以 */}
      <Child list={[1, 2, 3, 4, 5]}>
        {/* default slot */}
        {(list: number[]) => list.map((item) => <div key={item}>{item}</div>)}
      </Child>
    </>
  )
})

image

标签:tsx,插槽,props,list,写法,item,template,Vue3,jsx
From: https://www.cnblogs.com/jsonq/p/18597739

相关文章

  • 前端框架 React 与 Vue3对比 —— 技术选型
    在进行前端框架React与Vue3的技术选型对比时,我们可以从以下几个方面进行综合考虑:1.性能比较• Vue3通过Vite打包工具实现了快速的开发和构建,同时使用了响应式系统和Proxy技术来提高数据响应速度。在大部分测试用例中,Vue3比React更快,但在一些特定测试用例中,React......
  • Vue3+Nest+GraphQL+Prisma 入门全栈开发图书管理系统
    Vue3+Nest+GraphQL+Prisma入门全栈开发图书管理系统https://www.bilibili.com/video/BV1K44y197Za 101.课程介绍02.GraphQL入门-上03.GraphQL入门-中04.GraphQL入门-下05.Prisma入门-106.Prisma入门-207.Prisma入门-308.Prisma入门-409.Prisma入门-510.前端编写-上11......
  • vue3开发中常见的代码错误或者其他相关问题小文章4.0
    31. VueRouter动态路由匹配错误示例:动态路由配置不当,导致参数无法正确传递或解析。解决方案:确保正确配置动态路由,并在组件中使用$route.params来访问参数。//router/index.jsconstroutes=[{path:'/user/:id',component:User},];//在User.vue中访问......
  • (系列十四)Vue3+WebApi 搭建动态菜单
    说明  该文章是属于OverallAuth2.0系列文章,每周更新一篇该系列文章(从0到1完成系统开发)。   该系统文章,我会尽量说的非常详细,做到不管新手、老手都能看懂。   说明:OverallAuth2.0是一个简单、易懂、功能强大的权限+可视化流程管理系统。友情提醒:本篇文章是属于系......
  • H.265流媒体播放器EasyPlayer.js网页直播播放器,如何在vue3中播放H.265视频流?
    在Vue3中使用EasyPlayer播放H.265视频流,你需要先确保你已经安装了EasyPlayer播放器库,以及相关的依赖和支持的H.265编解码器。以下是一个基本的示例,说明如何在Vue3应用中集成EasyPlayer并播放H.265视频流。步骤1:安装依赖确保你的项目中已经安装了EasyPlayer,你可以通过npm或ya......
  • vue3中vconsole使用方法
    1.安装npmivconsole-D 2.在Vue项目的入口文件(通常是main.js或main.ts)中导入VConsole请注意,在生产环境下,你应该避免将VConsole包含在你的项目中。你可以使用条件语句来仅在开发环境下引入VConsole//处理是开启H5调试importVConsolefrom"vconsole";//在dev环境使......
  • vue3 路由
    路由(router)一、就是对应关系前端路由的工作方式:1.用户点击了页面上的路由链接2.导致了URL地址栏中的hash值发生了改变3.前端路由监听到了hash地址的变化4.前端路由吧当前hash地址对应的组件渲染到浏览器中二、history原理1、history模式主要使用两个HTML5history新增的ap......
  • Vue3 状态管理问题(Vuex / Pinia)
    Vue3状态管理问题详解(Vuex/Pinia)引言随着前端应用复杂度的不断增加,状态管理成为开发者面临的一个关键挑战。Vue.js作为流行的前端框架,提供了多种状态管理解决方案,其中最为广泛使用的两种是Vuex和Pinia。在Vue3的发布后,Pinia逐渐崭露头角,成为Vuex的有力竞争者。......
  • Vue3 序列化与反序列化问题
    Vue3序列化与反序列化问题详解在现代前端开发中,数据的序列化与反序列化是一个常见且重要的任务。无论是在数据存储、网络传输,还是在本地缓存中,正确地处理数据的序列化与反序列化都是确保应用稳定性和性能的关键。对于使用Vue3框架的开发者而言,理解和掌握序列化与反序列......
  • 重生之我在学Vue-- Vue3 学习路径总览
    重生之我在学Vue--Vue3学习路径总览文章目录重生之我在学Vue--Vue3学习路径总览前言Day1-10:基础阶段Day1:Vue3基础与开发环境搭建Day2:CompositionAPI与响应式系统Day3:模板语法与指令Day4:组件化开发Day5:路由管理(VueRouter)Day6:状态管理(Pinia)Day7:数据请求(A......