React&Vue 系列:简述 Vue 中 的 JSX

背景:作为使用三年 react.js 的搬运工,目前正在积极学习 vue.js 语法,而在学习的过程中,总是喜欢和 react.js 进行对比,这里也不是说谁好谁坏,而是怀有他有我也有,他没我还有的思想去学习,去总结。

  • React18
  • Vue3

最近看 vue 官网的时候,发现了 vue 中也使用 JSX/TSX,就比较的感兴趣。为什么呢?

因为在工作的三年过程中,都是使用的 React 进行开发的,而 React 就是使用的 JSX 语法进行开发的,对其基本语法也是比较熟悉的。若以后机会使用 vue 开发,那么 JSX 也不失为一种选择。

我记得最开始的,react jsx 的语法写习惯了,当写 vue 代码时,总会犯一个错误: {}{{}} 的写法。

vue 要使用 {{}}, react 要使用 {},不停的转变,最后造成的原因就是 react 那边喜欢写错,vue 这边也喜欢写错。 幸好的是,最近慢慢熟悉过来了

这里 react 中使用 JSX 使用语法就不用多做介绍了,写过 react 进行开发的码友都应该熟悉。

  • map 进行循环
  • 三目运算 或者 逻辑运算 进行判断
  • className 代替 class
  • 事件前面加上 on,采用驼峰式命名
  • 变量使用 {} 包裹

常用的就这些,直接开始 Vue 中的 JSX 旅程吧。

Vue 系列:JSX

先来个简单的介绍吧(我也不知道是哪里抄的,哈哈哈)

JSX(JavaScript XML)是一种用于在 javaScript 中编写类似 XML 的语法扩展。

JSX 允许开发者在 JavaScript 代码中直接编写类似 HTML 的标记语法,以声明式地描述 UI 组件的结构和交互。通过使用 JSX,可以将 HTML 结构、组件逻辑和数据绑定等内容组合在一起,更加直观地描述页面结构和交互。

安装插件并使用

create-vue 和 Vue Cli 都有预置的 JSX 语法支持,但是 vite 创建的项目是需要安装插件的
虽然下面说的都是 JSX, 但是创建的项目是 ts,都是采用 tsx 的书写方式。

使用 vue + vite 创建的项目是不支持 JSX,需要安装一个插件@vitejs/plugin-vue-JSX

bash 复制代码
pnpm add @vitejs/plugin-vue-JSX -D
ts 复制代码
// vite.config.ts
import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
import vueJSX from "@vitejs/plugin-vue-JSX";
​
// https://vitejs.dev/config/
export default defineConfig({
  plugins: [vue(), vueJSX()],
});

这样配置之后,就可以在项目中,使用 JSX 语法了。

使用 JSX 的两种方式

使用 JSX 文件存在两种形式,但都是使用 setup 函数的返回值来实现的。请确保返回的是一个函数而不是一个值!setup() 函数在每个组件中只会被调用一次,而返回的渲染函数将会被调用多次。

第一种方式 : 采用.vue 文件后缀名。

  1. 修改 script 标签上的 lang 属性,从 ts 改为 tsx。
  2. setup 函数返回一个 render 函数,该函数的返回值是 JSX 语法
ts 复制代码
<script lang="tsx">
import { defineComponent, ref } from "vue";
​
export default defineComponent({
  setup() {
    const msg = ref("copyer");
    return () => (
      <div>{msg.value}</div>
    );
  },
});
</script>

第二种方式 :采用 .tsx 文件后缀名

也是采用的 setup 返回 render 函数,该函数的返回值是 JSX 语法

ts 复制代码
import { defineComponent, ref } from "vue";
​
export default defineComponent({
  setup() {
    const msg = ref("copyer");
    return () => <div>{msg.value}</div>;
  },
});

具体采用哪种形式,就自己爱好了(其实 JSX 写法,本来在 vue 中很少使用)。

JSX VS template

template:

  • 更加贴近实际的 html。
  • 由于其确定的语法,更容易对模板做静态分析。这使得 Vue 的模板编译器能够应用许多编译时优化来提升虚拟 DOM 的性能表现。

JSX:

  • 处理高度动态渲染逻辑的可重用组件中使用。

JSX 的具体细节

官网已经明确的指出了,Vue 的 JSX 转换方式与 React 中 JSX 的转换方式不同,所以 JSX 的写法肯定会存在差异。

jsx 写法形式

选项语法

ts 复制代码
export default defineComponent({
  name: "test",
  props: {
    name: {
      type: String,
      required: true,
    },
  },
  // 拿取 props context: {emit, expose, slots, attrs }
  setup(props, context) {
    return () => {
      return <div>{props.name}</div>;
    };
  },
});

函数语法(vue3.3+)

ts 复制代码
import { defineComponent, ref } from "vue";
interface Props {
  name: string;
}
const TestTsx = defineComponent<Props>(
  (props, context) => {
    const msg = ref<string>("copyer");
    return () => (
      <div>
        <div>{msg.value}</div>
      </div>
    );
  },
  {
    // 需要手动声明运行时的 props,不然拿不到 props
    props: ["name"],
  }
);
export default TestTsx;

不能使用 className,而是直接使用 class

ts 复制代码
setup() {
    const msg = ref("copyer");
    return () => {
      return <div class="red">{msg.value}</div>;
    };
  },

动态 class 和 style

ts 复制代码
setup() {
  const show = ref(false);
  return () => (
    <div class="content">
      <div class={{ color: show.value }}>321321</div>
    </div>
  );
},

style 也是一样。

这种形式跟 react 采用 classnames 库的写法一致。

jsx 里面不能自动解包

就是针对 ref 变量,需要 .value,在上面案例即可验证。

组件插槽使用

在 jsx 中使用插槽,都是以函数的形式调用

ts 复制代码
const testslot = defineComponent({
  setup(props, { slots }) {
    return () => (
      <div>
        {/*默认插槽*/}
        <div>{slots.default && slots.default()}</div>
        {/*具名插槽*/}
        <div>{slots.footer && slots.footer()}</div>
      </div>
    );
  },
});

组件插槽传递

ts 复制代码
setup(props, context) {
  return () => {
    return (
      <div>
        <TestJsxVue
          v-slots={{
            default: () => <span>我是默认插槽</span>,
            footer: () => <span>我是具名插槽</span>,
          }}
        />
      </div>
    );
  };
},

这里的案例跟上面是对应的

注意:这里是使用的 v-slots 而不是 v-slot

作用域插槽就不用多说了,函数传递参数和函数接受参数。

事件修饰符

对于 .passive.capture.once 事件修饰符,可以使用驼峰写法将他们拼接在事件名后面(on+事件名+修饰符)。例如:

ts 复制代码
setup(props, context) {
  const btn = () => {
    console.log("321======>", 321);
  };
  return () => {
    return (
      <div>
        {/* 这里功能是好的,但是会飘红,不存在属性 onClickOnce */}
        <button onClickOnce={btn}>点击</button>
      </div>
    );
  };
},

对于事件和按键修饰符,可以使用 withModifiers 函数,vue 内部提供的。

支持部分的指令

  • v-text
  • v-html
  • v-show
ts 复制代码
 setup(props, context) {
  const text = ref("copyer");
  const show = ref(true);
  const btn = () => {
    console.log(321);
  };
  return () => {
    return (
      <div>
        {props.name}
        <button
          onClickOnce={btn}
          v-text={text.value}
          v-show={show.value}
        ></button>
      </div>
    );
  };
},

v-model 在组件上的使用

v-model 在组件上使用,默认名称就是 modelValue,也可以自定义名称,采用 v-model:title="xxx" 的方式。

默认值

html 复制代码
<!-- 定义 -->
<script lang="tsx">
import { defineComponent, ref } from "vue";

export default defineComponent({
  props: {
    {/* v-model 的默认值 */}
    modelValue: {
      type: String,
    },
  },
  emits: ["update:modelValue"],
  setup(props, { emit }) {
    const btn = () => {
      emit("update:modelValue", "321");
    };
    return () => (
      <div>
        <button onClick={btn}>{props.modelValue}</button>
      </div>
    );
  },
});
</script>
ts 复制代码
// 组件中使用
export default defineComponent({
  setup() {
    const text = ref("copyer");
    return () => {
      return (
        <div>
          <TestJsxVue v-model={text.value} />
        </div>
      );
    };
  },
});

取名为 title

html 复制代码
<!-- 定义 -->
<script lang="tsx">
import { defineComponent, ref } from "vue";

export default defineComponent({
  props: {
    {/* v-model 的取名 */}
    title: {
      type: String,
    },
  },
  emits: ["update:title"],
  setup(props, { emit }) {
    const btn = () => {
      emit("update:title", "321");
    };
    return () => (
      <div>
        <button onClick={btn}>{props.title}</button>
      </div>
    );
  },
});
</script>
ts 复制代码
// 使用
export default defineComponent({
  setup() {
    const text = ref("copyer");
    return () => {
      return (
        <div>
          {/* 取名为 title,是一个数组,[绑定的值,名称] */}
          <TestJsxVue v-model={[text.value, 'title']} />
        </div>
      )
    }
  }
})

存在其他的新 jsx 语法,以后慢慢收集。

总结

习惯 react 的 jsx 语法, 在 vue 写 jsx 应该也不在话下,当然 vue 还有一些个性的 jsx 语法,就需要在开发中平时积累。

上面存在错误的话,告诉我一下,因为 vue 我也不太会,我改正。

相关推荐
拉不动的猪2 分钟前
# 关于初学者对于JS异步编程十大误区
前端·javascript·面试
玖釉-7 分钟前
解决PowerShell执行策略导致的npm脚本无法运行问题
前端·npm·node.js
Larcher40 分钟前
新手也能学会,100行代码玩AI LOGO
前端·llm·html
徐子颐1 小时前
从 Vibe Coding 到 Agent Coding:Cursor 2.0 开启下一代 AI 开发范式
前端
小月鸭1 小时前
如何理解HTML语义化
前端·html
jump6801 小时前
url输入到网页展示会发生什么?
前端
诸葛韩信2 小时前
我们需要了解的Web Workers
前端
brzhang2 小时前
我觉得可以试试 TOON —— 一个为 LLM 而生的极致压缩数据格式
前端·后端·架构
yivifu2 小时前
JavaScript Selection API详解
java·前端·javascript
这儿有一堆花2 小时前
告别 Class 组件:拥抱 React Hooks 带来的函数式新范式
前端·javascript·react.js