vue3使用 JSX / TSX语法

一、什么是 JSX / TSX

JSX / TSX 语法
JSX 是一种将XML语法嵌入到JavaScript中的语法。在 Vue3 中,我们可以使用JSX语法来编写组件的模板。使用JSX语法可以让我们更加灵活地定义组件的模板,并且可以让我们在编写组件时使用JavaScript的全部语言特性。

let jsx = <h1>hello world</h1>;

二、在vue3中使用

1、基本使用

// index.tsx
const tsxDom = () => {
  return (
    <>
      <div class="container">
        <h1>Hello, world!</h1>
        <p>This is a tsx.</p>
      </div>
    </>
  );
};

export default tsxDom;

// tsx.vue
<template>
  <div>
    <tsxDom></tsxDom>
  </div>
</template>

<script setup lang="ts">
import tsxDom from "@/tsx/index";
</script>

<style scoped></style>

2、使用 vue 中的语法

1)插值表达式

// index.tsx
// tsx 中使用{}语法
import { ref } from "vue";

let hello = ref<string>("Hello, world!");
const tsxDom = () => {
  return (
    <>
      <div>
        <h1>{hello.value}</h1>
        <p>This is a tsx.</p>
      </div>
    </>
  );
};

export default tsxDom;

2)v-model
注意:使用 v-model 时,需要 .value 获取值

// index.tsx
// tsx 中使用 v-model 语法
import { ref } from "vue";
let hello = ref<string>("Hello, world!");

const tsxDom = () => {
  return (
    <>
      <input type="text" v-model={hello.value} />
    </>
  );
};

export default tsxDom;

  1. v-if
    注意:在jsx中不支持v-if的指令,需要使用三元表达式
// tsx 中模拟 v-if 语法
import { ref } from "vue";
let flag = ref<boolean>(false);

const tsxDom = () => {
  return <>{flag.value ? <div>显示</div> : <div>隐藏</div>}</>;
};

export default tsxDom;

4) v-for
注意:jsx中不支持v-for语法,需要使用js的array.map函数实现

// tsx 中模拟 v-for 语法
import { reactive } from "vue";
interface Data {
  name: string;
  age: number;
}
let list = reactive<Data[]>([
  { name: "张三", age: 12 },
  { name: "李四", age: 18 },
]);

const tsxDom = () => {
  return (
    <>
      {
      	{/* 此处完全遵循 react 语法即可 */}
        list.map((item) => {
          return <div>{item.name}</div>;
        })
      }
    </>
  );
};

export default tsxDom;

5)v-bind
注意:jsx语法中不支持 v-bind,可以采用{}包裹变量来实现

// tsx 中模拟 v-bind 语法
import { reactive } from "vue";

interface List {
  name: string;
  age: number;
}

let list = reactive<List[]>([
  {
    name: "张三",
    age: 10,
  },
  {
    name: "李四",
    age: 18,
  },
]);

const tsxDom = () => {
  return (
    <>
      {
        list.map((item) => {
          return <div key={item.name}>{item.age}</div>;
        })
      }
    </>
  );
};

export default tsxDom;

  1. v-on
    注意:jsx语法中不支持v-on,jsx/tsx中事件的使用与 react 一致
    以 on 开头,接收一个回调函数,不能使用vue中的修饰符
// tsx 中模拟 v-on 语法

const handleClick = () => {
  console.log("被点击了");
};

const tsxDom = () => {
  return (
    <>
      <button onClick={() => handleClick()}>点击</button>
    </>
  );
};

export default tsxDom;

7)Props

  • 父子组件传值
  • 通过父组件传递参数
  • jsx/tsx接收props并使用
// tsx.vue
<template>
  <div>
    <tsxDom :userName="userName" :userAge="userAge"></tsxDom>
  </div>
</template>

<script setup lang="ts">
import { ref } from "vue";
import tsxDom from "@/tsx/props";

const userName = ref<string>("张三");
const userAge = ref<number>(18);
</script>

<style scoped></style>

// props.tsx
// tsx 中接收及使用props
interface Props {
  userName?: string;
  userAge?: number;
}

const handleClick = (props: Props) => {
  console.log(props);
};

const tsxDom = (props: Props) => {
  return (
    <>
      <div>{props.userName}</div>
      <div>{props.userAge}</div>
      <button onClick={() => handleClick(props)}>点击</button>
    </>
  );
};

export default tsxDom;

8)Emit

  • jsx/tsx组件中通过第二个参数 ctx 拿到 emit 方法
  • 通过 emit() 方法传递一个自定义事件以及参数
  • 父组件通过 v-on:自定义事件 拿到传递过来的值
// tsx.vue
<template>
  <div>
    <tsxDom
      :userName="userName"
      :userAge="userAge"
      @on-click="handleClick"
    ></tsxDom>
  </div>
</template>

<script setup lang="ts">
import { ref } from "vue";
import tsxDom from "@/tsx/emit";

const userName = ref<string>("张三");
const userAge = ref<number>(18);

const handleClick = (value: string) => {
  console.log(value); // 张三
};
</script>

<style scoped></style>

// emit.tsx
interface Props {
  userName?: string;
  userAge?: number;
}

const handleClick = (props: Props, ctx: any) => {
  ctx.emit("on-click", props.userName);
};

const tsxDom = (props: Props, ctx: any) => {
  return (
    <>
      <div>{props.userName}</div>
      <div>{props.userAge}</div>
      <button onClick={() => handleClick(props, ctx)}>点击</button>
    </>
  );
};

export default tsxDom;

9)v-slot

  • 子组件通过 centex.slots 传参
  • 父组件通过 v-slots={} 接收参数
import { defineComponent, reactive } from "vue";

const state = reactive({ name: "张三" });
const list = reactive([1, 2, 3]);

export const tsxDom = (props: any, ctx: any) => (
  <>
    {/* 默认插槽 */}
    <div>{ctx.slots.default ? ctx.slots.default() : "默认"}</div>
    {/* 声明名称为state的插槽 并传值,不传值为ctx.slots.state() */}
    <div>{ctx.slots.state && ctx.slots.state(state)}</div>
    {/* 声明名称为list的插槽 并传值,不传值为slots.list() */}
    <div>{ctx.slots.list && ctx.slots.list(list)}</div>
  </>
);

export default defineComponent({
  setup() {
    type State = {
      name: string;
    };

    // 使用插槽
    const slots = {
      // default: () => <div>匿名插槽</div>,
      state: (state: State) => <div>{state.name}</div>,
      list: (list: number[]) => list.map((item) => <div>{item}</div>),
    };
    return () => (
      <>
        {/* 引用组件, 使用插槽:v-slots={slots} */}
        <tsxDom v-slots={slots} />
      </>
    );
  },
});

3、ts中报错
需要在 tsconfig.json 增加:

{
  "compilerOptions": {
    "jsx": "preserve",
    "jsxImportSource": "vue"
  }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值