Vue3 JSX 插槽、v-model 的用法以及 React JSX 的区别

news/2024/7/15 13:28:27 标签: react.js, vue.js, 前端

前言

写这篇文章的初衷是,Vue3 JSX 部分与 React JSX 容易混淆,比如如本文所说的 slot & v-model,
如果你是第一次接触 JSX,可先阅读前面写过的 React & JSX 日常用法与基本原则 来对 JSX 有一个整体的认知以及比较两者间的差异。

一、什么是 JSX

JSX 是用一种可以将 HTML + JS 混合写的一种语法糖,最初由 React 率先研发,后来 Vue3 也借鉴了这种写法灵感实现自家的 JSX

实际上,能够快速研发 JSX 还得得益于一款叫做由 @babel/plugin-syntax-jsx 的插件,
是由 Babel 研发的,它只负责解析但不负责转换,于是 ReactVue3 基于此插件实现了自家的 JSX

举个例子

const Component = () => <div> {[1,2,3].map((num) => <span>{num}</span>)} </div>
// 等价于 <div><span>1</span><span>2</span><span>2</span></div>

这种写法就叫 JSX,换句话说,只要你用过 React/Vue3 其中的 JSX ,你就同时掌握了两种框架的 JSX 。当然,每个框架对自己的 JSX 都喜欢添砖加瓦,如独特的 API,独特的属性修饰符;
但万变不离其宗, HTML + JS 写法是任何 JSX 框架统一遵循规范的不变事实。

二、Vu3 使用 JSX

2.1 准备工作

a) 针对新项目

使用官方提供的安装命令,里面内置了 JSX、TypeScript 等插件,无须手动配置

npm init vue@latest

按照提示选项勾选即可,请添加图片描述
接下来就可以愉快的使用 JSX 和 TypeScript ~

b) 针对现有项目

  1. 安装 JSX 依赖包:
npm install @vue/babel-plugin-jsx -D
  1. 新建 Babel 配置文件: babel.config.json ,内容如下:
{
  "plugins": ["@vue/babel-plugin-jsx"]
}

然后就可以愉快的使用 JSX 啦~

对有关 Babel 的概念感兴趣的可参考前面写过的:
JS & 介绍 Babel 的使用及 presets & plugins 的概念

2.2 使用 slot 插槽

定义插槽方式1

// NavBar.jsx
import { defineComponent } from 'vue'
const NavBar = defineComponent({
	setup(props, { slots }) {
		return () => {
			return (
				<>
					<div>Simple</div>
					<div> { slots?.default() } </div>
					<header> { slots?.header() } </header>
				</>
			)
		}
	}
})

注意,使用 slot 时,setup return 必须是一个函数,实际上就是 render() 。

定义插槽方式2

// NavBar.jsx
const NavBar = (props, { slots }) => {
  return (
    <>
      <div>Simple</div>
      <div> { slots?.default() } </div>
      <header> { slots.header() } </header>
    </>
  )
}

这两种定义方式的区别取决于你是否需要用到 Vue 提供的一些钩子函数或响应式 API,比如第一种有 setup ,如果是纯普素的组件,使用第二种方式即可。

使用插槽方式1:双括号

// App.jsx
import NavBar from '@/components/nav-bar'
const App = () => {
  return (
    <>
      <NavBar>
        {{
          default: () => 'Hello,world.',
          header: () => 'Hello, header.'
        }}
      </NavBar>
    </>
  )
}
export default App

使用插槽方式2:v-slots

// App.jsx
import NavBar from '@/components/nav-bar'
const App = () => {
  const slots = {
    default: () => 'Hello,world.',
    header: () => 'Hello, header.'
  }
  return (
    <>
      <NavBar v-slots={slots}>
      </NavBar>
    </>
  )
}
export default App

使用插槽方式3:把它当成 .vue 文件使用即可

// App.vue
<template>
  <div>
    <NavBar>
      Hello, world.
      <template #header>
        Hello, header.
      </template>
    </NavBar>
  </div>
</template>

<script lang="ts">
import { defineComponent } from 'vue';
import NavBar from '@/components/nav-bar'
export default defineComponent({
  components: {
    NavBar
  },
  props: {},
  setup(props) {
    return {}
  }
})
</script>

提示:.vue 组件可以引入 .jsx/tsx 组件,反之 .jsx/tsx 也可以引入 .vue 组件,它们本质上就是一个 Object 。

2.3 使用 v-model

使用方式1:标签绑定 v-model

// NavBar.jsx
import { ref, defineComponent } from 'vue'
const NavBar = defineComponent({
  setup() {
    const phone = ref()
    return () => {
      return (
          <input type="text" v-model={phone.value} />
      ) 
    }
  }
})
export default NavBar;

使用方式2:组件绑定 v-model

// Card.jsx 引入 component 组件。
import { defineComponent, ref } from 'vue'
import Component from './component'

const CardComponent = defineComponent({
  setup() {
    const componentName = ref()
    return () => {
      return (
        <main>
          <Component 
            v-model={[componentName.value, 'modelValue']} 
          />
        </main>
      )
    }
  }
})
export default CardComponent

// 定义组件 Component.jsx 。
import { defineComponent, toRefs } from 'vue'
const Component = defineComponent({
  emits: ['update:modelValue'],
  setup(props, { emit }) {
    return () => {
      return (
        <input type="text" onInput={($event) => emit('update:modelValue', $event.target.value)} />
      )
    }
  }
})
export default Component

解释:

  1. Card.jsx 引入 Component 组件并绑定 v-model
  2. v-model 的第二个参数 modelValue 与 Component 组件的 update:modelValue 成对应关系,是双向更新的必备定义条件。

使用方式3:组件绑定多个 v-model

// Card.jsx 引入 component 组件。
import { defineComponent, ref } from 'vue'
import Component from './component'

const CardComponent = defineComponent({
  setup() {
    const componentName = ref()
    const modelPhoneNumber = ref()
    return () => {
      return (
        <main>
          <Component 
            v-model={[componentName.value, 'modelValue']} 
            v-model={[modelPhoneNumber.value, 'modelPhoneNumber']} 
            // 上面等同于下面。
            // v-model:modelValue={modelValue.value} 
            // v-model:modelPhoneNumber={modelPhoneNumber.value} 
          />
        </main>
      )
    }
  }
})
export default CardComponent

// 定义组件 Component.jsx 。
import { defineComponent, toRefs } from 'vue'
const Component = defineComponent({
  emits: ['update:modelValue', 'update:modelPhoneNumber'],
  setup(props, { emit }) {
    return () => {
      return (
        <input type="text" onInput={($event) => emit('update:modelValue', $event.target.value)} />
        <input type="text" onInput={($event) => emit('update:modelPhoneNumber', $event.target.value)} />
      )
    }
  }
})
export default Component

提示:对于绑定 v-model 的组件来说,组件内无需再自定义 props: {},可别跟平时的传参给混淆了,如果组件内部确实要访问,则给组件加上 x={x} 然后用 props 接受即可。

2.4 支持 TSX 写法

TSX 指的是能够在 TypeScript 中写 JSX,在 tsconfig.json 中加以下选项:

"compilerOptions": {
  "jsx": "preserve"
}

接下来只需将文件后缀由 .jsx 改成 .tsx 即可。

2.5 注意事项

  1. 使用 JSX 语法时,文件名必须为 .jsx.tsx ,不支持 .vue
  2. 在 JSX 里的标签内访问响应式数据时,须带上 .value 访问。

三、Vue3 JSX 与 React JSX 的差别

  1. 绑定数据方式不同,Vue3 JSX 采用 v-model 双向绑定数据,React 采用 setState 。
  2. 生命周期函数不同。
  3. 插槽用法不同。
  4. 有各自的 API。

其实不管是 Vue3 or React,它们最大的特点就是 JSX ,本质上就是 HTML & JS 可以混合写,这才是它们的共同之处。

文献:
https://juju.one/using-jsx-with-vue3/
https://github.com/vuejs/babel-plugin-jsx


http://www.niftyadmin.cn/n/1007721.html

相关文章

qemu 源码编译 qemu-system-aarch64 的方法

前言 最近调试 RT-Thread bsp qemu-virt64-aarch64 时&#xff0c;遇到无法使用网络设备问题&#xff0c;最后确认是 当前 ubuntu 20.04 系统 使用 apt install 安装的 qemu qemu-system-aarch64 版本太低。 RT-Thread qemu-virt64-aarch64 里面的网络设备&#xff0c;需要较新…

Dell-Precision5520 电脑 Hackintosh 黑苹果efi引导文件

原文来源于黑果魏叔官网&#xff0c;转载需注明出处。&#xff08;下载请直接百度黑果魏叔&#xff09; 硬件配置 硬件型号驱动情况 主板Dell-Precision5520 处理器Intel Core i7-7820HQ已驱动 内存Micron 2400MHz DDR4 16GB x2已驱动 硬盘Samsung 970EVO 512GB已驱动 显…

ModaHub魔搭社区:向量数据库MIlvus服务端配置(一)

目录 服务端配置 配置概述 Milvus 文件结构 配置修改 编辑配置文件 运行时修改 server_config.yaml 参数说明 cluster 区域 general 区域 network 区域 服务端配置 配置概述 以下配置说明可同时应用于单机或者分布式场景。 Milvus 文件结构 成功启动 Milvus 服务后…

手机提醒打卡软件哪个好用 每日计划的打卡软件推荐

在人生的不同阶段&#xff0c;人们会有不同的目标&#xff0c;为了目标可以很好地实现&#xff0c;可以将其分散为多个不同的小计划&#xff0c;并坚持不断地打卡完成每项计划&#xff0c;助力自己最终完成目标。那手机提醒打卡软件哪个好用些&#xff0c;每日计划的打卡软件推…

python多维数据可视化

文章目录 数据数据可视化平行坐标RadViz雷达图Andrews曲线矩阵图相关系数热力图参考文献多维度(3维以上)数据的可视化,用常规的方法不太好实现。本文介绍几种用Python实现的将多维数据展示在二维平面中的方法。 数据 以经典的鸢尾花数据集为例。 以下是5条经过格式处理的数…

深度学习与神经网络阅读笔记(持续更新)

深度学习与神经网络阅读笔记&#xff08;持续更新&#xff09; 机器学习基础绪论人工智能主要领域可分为如下&#xff1a;人工智能的发展史&#xff1a;机器学习表示学习深度学习 线性模型Logistic回归Softmax回归感知器支持向量机总结对比 基础模型循环神经网络应用到机器学习…

Option 类型

Option 不是结构体声明&#xff0c;而是枚举类型。印象中的枚举类型都是固定的常量&#xff0c;这里 Rust 的枚举支持了泛型。枚举了两种可能&#xff1a;有值、或没值。None表示没有值&#xff0c;Some(T) 表示存在 T 类型的值。 enum Option<T> {Some(T),None, }简单示…

Linux 系统查看当前正在运行的某个进程的详细执行脚本和目录ls -l /proc/PID/cwd和 ls -l /proc/PID/exe

在 Linux 系统中&#xff0c;可以使用 ps 命令结合 /proc 目录来查看当前正在运行的某个进程的详细执行脚本。具体来说&#xff1a; 首先使用 ps 命令查看当前正在运行的某个进程的 PID&#xff0c;例如&#xff1a; ps aux | grep your_process_name这个命令会列出所有包含 yo…