vue可以使用jsx语法吗(vue中正确使用jsx语法的姿势分享)
vue可以使用jsx语法吗
vue中正确使用jsx语法的姿势分享目录
- 前言
- 虚拟DOM
- 什么是虚拟DOM
- 虚拟DOM的优点
- 渲染函数是什么
- jsx
- 在vue3中编写jsx的两种方式
- 用法
- 最后
- 参考
又到了愉快的摸鱼时间,我觉得不能荒废,H5页面我一直用的vant,出于对源码的好奇,我从git上拉了一份vant源码,里面竟然都是jsx写的组件,于是我开始了对在vue中使用jsx的探索
什么是虚拟DOM
在这之前,先了解下虚拟DOM,vue和react框架都在内部使用了虚拟DOM,这样做的原因是通过js操作DOM的计算成本很高,虽然js更新速度很快,但是查找dom并更新的成本很高。那么有什么方法可以优化呢,vue等框架使用js对象,通过改变js对象,最后进行批量处理,一次更新DOM,所以虚拟DOM本质上就是一个js对象
虚拟DOM的优点
- 从原先的操作真实DOM到操作虚拟DOM,降低查找成本
- 通过diff比对,我们可以更快的定位数据的变化,从而更新DOM
- 更好的ui更新
- 抽象渲染过程,带来了实现跨平台的能力,如vue3中的createRenderer API
渲染函数是用来生成虚拟DOM的。我们在vue单文件中编写模板语法,最终会在底层实现中被编译成渲染函数
Vue 推荐在绝大多数情况下使用模板来创建你的 HTML。然而在一些场景中,你真的需要 JavaScript 的完全编程的能力。这时你可以用渲染函数,它比模板更接近编译器。
当出现以下场景,虽然下列写法也能实现想要的效果,但是他不仅冗长,而且我们为每个级别标题重复书写了 。当我们添加锚元素时,我们必须在每个 v-if/v-else-if 分支中再次重复它
const { createApp } = Vue const app = createApp({}) app.component('anchored-heading', { template: ` <h1 v-if="level === 1"> <slot></slot> </h1> <h2 v-else-if="level === 2"> <slot></slot> </h2> <h3 v-else-if="level === 3"> <slot></slot> </h3> <h4 v-else-if="level === 4"> <slot></slot> </h4> <h5 v-else-if="level === 5"> <slot></slot> </h5> <h6 v-else-if="level === 6"> <slot></slot> </h6> `, props: { level: { type: Number, required: true } } })
虽然模板在大多数组件中都非常好用,但是显然在这里它就不合适了。那么,我们来尝试使用 render 函数重写上面的例子:
const { createApp, h } = Vue const app = createApp({}) app.component('anchored-heading', { render() { return h( 'h' + this.level, // tag name {}, // props/attributes this.$slots.default() // array of children ) }, props: { level: { type: Number, required: true } } })
这样写渲染函数有点痛苦,有没有更接近模板的写法呢,vue提供了一个babel-plugin-jsx babel插件来让vue支持jsx写法
我这边使用的vuecli创建的vue3 + ts项目,脚手架已经集成了jsx和ts的相关依赖
在vue3中编写jsx的两种方式
直接将文件后缀名从vue改成tsx或者jsx
在vue3中,可以直接使用render选项编写
import { defineComponent } from "vue"; export default defineComponent({ name: "Jsx", render() { return <li>我是一个li</li>; }, });
也可以在setup中返回
import { defineComponent } from "vue"; export default defineComponent({ name: "Jsx", setup() { return () => <li>我是li</li>; }, });
两种方式都可以,具体看个人习惯,setup中访问不到this,但是render中可以通过this访问当前vue实例
用法
class绑定,和react的jsx绑定的有区别,react中使用className,vue中使用class
setup() { return () => <li class="test">我是li</li>; },
style绑定
setup() { return () => <li style={{ color: "red" }}>我是li</li>; },
props绑定
// 父组件 setup() { return () => ( <li style={{ color: "red" }}> <span>我是父组件</span> <Mycom msg={"我是父组件传的值"} /> </li> );
// 子组件,setup的第一个参数,可以获取props里的值 setup(props) { return () => <li>我是子组件{props.msg}</li>; },
事件绑定
setup() { function eventClick() { console.log("点击"); } return () => <button onClick={eventClick}>按钮</button>; },
组件自定义事件
// 子组件 import { defineComponent } from "vue"; export default defineComponent({ name: "Mycom", emits: ["event"], setup(props, { emit }) { function sendData() { emit("event", "子组件传递的数据"); } return () => ( <li> <span>自定义事件</span> <button onClick={sendData}>传递数据</button> </li> ); }, });
// 父组件 // @ts-nocheck // 这样写在jsx中没问题,但是在tsx中会报ts类型错误,所以我在上面忽略了当前文件ts监测@ts-nocheck import { defineComponent } from "vue"; import Mycom from "./mycom"; export default defineComponent({ name: "Jsx", setup() { function getSon(msg: string) { console.log(msg); } return () => ( <li> <Mycom onEvent={getSon} /> </li> ); }, });
也可以这样解决ts类型报错
setup() { function getSon(msg: string) { console.log(msg); } return () => ( <li> <Mycom {...{ onEvent: getSon }} /> </li> ); },
插槽
// 父组件 setup() { const slots = { test: () => <li>具名插槽</li>, default: () => <li>默认插槽</li>, }; return () => ( <li> <Mycom v-slots={slots}></Mycom> </li> ); },
setup(props, { slots }) { // 子组件 return () => ( <li> <span>插槽</span> {slots.default?.()} {slots.test?.()} </li> ); },
指令,v-if,v-for等指令在jsx中无法使用,jsx只支持v-model和v-show指令
setup() { const inputData = ref(""); return () => ( <li> <span v-show={true}>显示</span> <span v-show={false}>隐藏</span> <input type="text" v-model={inputData.value} /> <span>{inputData.value}</span> </li> ); },
话不多说,我先打开vant源码,准备开启我的第一个组件源码阅读 src =>button=>button.tsx
到此这篇关于vue中正确使用jsx的文章就介绍到这了,更多相关vue中使用jsx内容请搜索开心学习网以前的文章或继续浏览下面的相关文章希望大家以后多多支持开心学习网!
参考- vue渲染函数
- vuejsx文档
- issues
- vue3中的setup的参数(Vue3中ref与reactive的详解与扩展)
- vue3.0 黑暗风格(Vue3.0 手写放大镜效果)
- vue 为什么使用虚拟dom(Vue虚拟Dom到真实Dom的转换)
- vue怎么实现预览与放大(Vue实现牌面翻转效果)
- vue用手动上传图片(vue上传图片文件的多种实现方法)
- vue接收网络请求数据类型配置(vue中对接Graphql接口的实现示例)
- vue 父组件传值(Vue两个同级组件传值实现)
- vue表单上传图片数据(vue-cropper插件实现图片截取上传组件封装)
- vue怎么实现拖动(Vue拖动截图功能的简单实现方法)
- vue设置div大小(Vue实现div滚轮放大缩小)
- springboot+vue项目演示(springboot+VUE实现登录注册)
- vue多个对象实现双向数据绑定(利用js实现Vue2.0中数据的双向绑定功能)
- vue 单文件组件(vue实现一个单文件组件的完整过程记录)
- vue子视图里再加routerview(vue router-view的嵌套显示实现)
- vue路由跳转的方法(Vue路由监听实现同页面动态加载的示例)
- vue自定义列组件(vue自定义表格列的实现过程记录)
- 纳兰性德绝美作,一场重逢,成就最后一首称得上惊艳的《如梦令》(纳兰性德绝美作)
- 如何快速赚钱(如何快速赚钱方法真实有效)
- 这里输入关键词(如何输入关键词)
- 熊猫中国国宝(熊猫国宝酒53酱香)
- 春节会放假几天(春节会放假吗)
- 小浴室,大民生 缙云3200多户困难群众洗上免费热水澡(小浴室大民生缙云3200多户困难群众洗上免费热水澡)
热门推荐
- mysql 触发器是什么(MySQL触发器的使用)
- dedecms 内容页模板(dedecms列表页与详情页调用tag标签的方法)
- mysql中默认排序教程(基于mysql 默认排序规则的坑)
- python中查看数据类型的内置函数(python学习——内置函数、数据结构、标准库的技巧推荐)
- zabbix5.0源码安装(nginx的zabbix 5.0安装部署的方法步骤)
- mysql批量生成uuid(一种简单的ID生成策略: Mysql表生成全局唯一ID的实现)
- linux命令du和df的区别(Linux系统目录大小通过du命令获取实例)
- linux安装php目录路径修改(ubuntu环境下的php相关路径与修改方法)
- 排序算法口诀php(PHP快速排序算法实现的原理及代码详解)
- 如何降低SQL语句复杂度