全国免费咨询:

13245491521

VR图标白色 VR图标黑色
X

中高端软件定制开发服务商

与我们取得联系

13245491521     13245491521

2025-04-29_Vue 开发者狂喜!我在 React 中完美复刻了 v-ifv-for 指令

您的位置:首页 >> 新闻 >> 行业资讯

Vue 开发者狂喜!我在 React 中完美复刻了 v-ifv-for 指令 (??金石瓜分计划回归,速戳下图了解详情??) 前言?作为一名同时使用 Vue 和 React 的开发者,我深深被 Vue 的指令系统所吸引。 v-if 、 v-for 、 v-show 等指令让模板开发变得异常简洁高效。但在 React 中,我们却不得不使用略显冗长的三元表达式和 map 方法。这让我萌生了一个想法:能否在 React 中实现类似 Vue 的指令系统? 经过多次尝试,我找到了三种实现方案,其中 Babel 插件方案最为完美。下面我将详细介绍这些方案的实现思路和优劣对比。 ?为什么需要 React 指令?传统 React 条件渲染// 条件渲染 { isShow div显示内容/div } // 列表渲染 { items.map((item) =div key={item.id}{item.name}/div } 理想中的写法div r-if={isShow}显示内容/div div r-for={item in items} key={item.id}{item.name}/div 给人感觉就是很简洁 完美! 实现方案对比方案一:高阶组件(不完美)const If = ({ condition, children }) = condition ? children : null; const For = ({ list, children }) = list.map((item, index) = children(item, index)); If condition={isShow} div显示内容/div /If For list={items} {(item, index) =div key={index}{item}/div} /For 「优缺点分析:」 ? 优点:遵循 React 设计理念,无需额外工具 ? 缺点: 语法不够直观嵌套层级增加无法实现真正的指令效果方案二:Babel 插件实现思路因为 React 的 JSX 本质上是 JavaScript 的语法糖,无法直接扩展类似 Vue 的模板指令系统,但是我们可以通过自定义 Babel 插件,在代码编译阶段将类似 r-if 的属性转换为 React 代码 核心原理:通过 Babel AST 转换,将: div r-if={count 4}我大于4才能显示/div 转换为: { count 4 div我大于4才能显示/div } 我们都知道 React 代码的转换主要是通过 Babel 来完成的。 在之前 webpack 项目中 我们还得下载 babel-loader,用于转换 JSX 和 ES6+ 代码 我们现在用 vite 来做项目,@vitejs/plugin-react 插件已经内置了 Babel 配置,我们只需要进行相关配置即可。 接下来核心就是如何实现这个插件了 如果还不熟悉如何编写 bable 插件,可以先看一下下面的文档学习一下「扩展阅读」: ??Babel 官方插件指南[1] ??实战:如何编写 Babel 插件[2](掘金) ??掘金文章[3](掘金) ??掘金文章[4](掘金) 如果觉得内容太多学习太烦,你可以直接看我的代码,其实思路很简单 首先 bable 插件一定是一个函数,函数的参数对象 这个对象有一个 types 属性,这个属性是一个对象,这个对象有很多方法,我们可以通过这些方法来操作 ast 树export default function (babel) { //babel 中 types 属性是一个对象,这个对象有很多方法,我们可以通过这些方法来操作 ast 树 const { types: t } = babel; ... ... } 这个函数必须返回一个具有 visitor 属性的对象,具体原因你可以看一下文档,你也可以就当做就是格式如此export default function (babel) { //babel 中 types 属性是一个对象,这个对象有很多方法,我们可以通过这些方法来操作 ast 树 const { types: t } = babel; return { name: "react-directives", visitor: { // 在这里编写你的访问者函数 }, } 该对象内部是对各种类型的标签(比如 JSXElement)的处理逻辑,是一个个的函数, 然后我们编写函数 JSXAttribute ,目的就是转换 jsx 的 Attribute 为我们需要的语法, 这个函数名称无所谓export default function (babel) { //babel 中 types 属性是一个对象,这个对象有很多方法,我们可以通过这些方法来操作 ast 树 const { types: t } = babel; return { name: "react-directives", visitor: { JSXElement(path) {}, }, } visitor 的每个方法都接收两个参数:path 和 state。我们这次只关注 path,path 是一个对象,它包含了当前节点的信息,比如节点的类型、属性、子节点等。我们可以通过 path 来操作当前节点。具体 path 中有哪些值 不用过多关注, 我们要获取的就是两个东西, 一个是属性的名称 一个是属性的值,属性的名称 path.node.name.name === 'r-if'属性的值 path.node.value.expression === {count 4}查找当前 JSX 属性节点的最近的 JSX 元素父节点并且将其替换为一个新的 JSX 表达式容器节点,该节点包含一个逻辑表达式,该表达式使用逻辑与运算符将条件和原始的 JSX 元素连接起来。 jsxElement.replaceWith( t.jSXExpressionContainer( t.logicalExpression("&&", condition, jsxElement.node) ) ); 最后移除原来的属性 path.remove(); 实现效果完整代码vite.config.js import { defineConfig } from "vite"; import react from "@vitejs/plugin-react"; export default defineConfig({ plugins: [ react({ babel: { plugins: ["./babel-plugin-react-directives.js"], }, }), ], }); 插件实现babel-plugin-react-directives.js export default function (babel) { const { types: t } = babel; return { name: "react-directives", visitor: { JSXAttribute(path) { if (path.node.name.name?.startsWith("r-")) { const directive = path.node.name.name; const condition = path.node.value?.expression; if (directive === "r-if" && condition) { const jsxElement = path.findParent((p) = p.isJSXElement()); jsxElement.replaceWith( t.jSXExpressionContainer( t.logicalExpression("&&", condition, jsxElement.node) ) // 移除原来的属性 path.remove(); } } }, }, } 方案三:覆写 createElement我的思路就是在运行时重写 createElement,然后在 createElement 中处理 r-if 指令,但是我没有成功,有懂的大佬可以留言交流一下,不知道是不是我的方式有问题 import React from "react"; const originalCreateElement = React.createElement; const customCreateElement = function (type, props, ...children) { // 处理 r-if 指令 if (props && props["r-if"] === false) { return null; } if (props && typeof props["r-if"] !== "undefined") { return props["r-if"] ? originalCreateElement( type, { ...props, "r-if": undefined }, ...children ) : null; } return originalCreateElement(type, props, ...children); }; export const applyDirectives = () = { // 确保只应用一次 if (!React.__directivesApplied) { React.__directivesApplied = true; React.createElement = customCreateElement; // 实际应用覆写 } }; 然后在 main.jsx 引入 import { applyDirectives } from "./directives"; applyDirectives(); 结语通过 Babel 插件,我们成功在 React 中实现了类似 Vue 的指令系统。这不仅让代码更加简洁,也为 React 开发者提供了一种新的开发体验。虽然这只是一个开始,但它展示了 AST 操作的强大能力。 你会考虑在项目中使用这种方案吗?欢迎在评论区分享你的看法! ??项目源码地址[5] 关注更多AI编程资讯请去AI Coding专区:https://juejin.cn/aicoding 阅读原文

上一篇:2025-07-08_想给面试官吹DDD吗?项目像搭积木一样运行:领域驱动设计(DDD)让复杂业务变简单 下一篇:2022-10-26_香港中文大学薛天帆老师招收全奖博士生、硕士生 | 2023夏季

TAG标签:

16
网站开发网络凭借多年的网站建设经验,坚持以“帮助中小企业实现网络营销化”为宗旨,累计为4000多家客户提供品质建站服务,得到了客户的一致好评。如果您有网站建设网站改版域名注册主机空间手机网站建设网站备案等方面的需求...
请立即点击咨询我们或拨打咨询热线:13245491521 13245491521 ,我们会详细为你一一解答你心中的疑难。
项目经理在线

相关阅读 更多>>

猜您喜欢更多>>

我们已经准备好了,你呢?
2022我们与您携手共赢,为您的企业营销保驾护航!

不达标就退款

高性价比建站

免费网站代备案

1对1原创设计服务

7×24小时售后支持

 

全国免费咨询:

13245491521

业务咨询:13245491521 / 13245491521

节假值班:13245491521()

联系地址:

Copyright © 2019-2025      ICP备案:沪ICP备19027192号-6 法律顾问:律师XXX支持

在线
客服

技术在线服务时间:9:00-20:00

在网站开发,您对接的直接是技术员,而非客服传话!

电话
咨询

13245491521
7*24小时客服热线

13245491521
项目经理手机

微信
咨询

加微信获取报价