1.探索 Vue 3 中的 JSX
2.1.1 React 介绍
3.React Native UI界面还原,组件布局与动画效果
4.å¨Reactä¸ä¸ºä»ä¹è¦ç¨JSXï¼
5.element-tabs组件 源码阅读
6.react源码解析8.render阶段
探索 Vue 3 中的 JSX
探索 Vue 3 中的 JSX
引言
各位前端技术爱好者,我是来自字节跳动大力智能前端团队的林成璋。近期我专注维护 Vue 3 的 Babel JSX Plugin,今天有幸与大家一同探讨《探索 Vue 3 中的 JSX》。
开发经验
我利用业余时间以及一些额外的商业笔记源码休息时间,致力于 Vue 3 的 Babel JSX Plugin 的维护工作。起初,我开发此插件的初衷是为了协助 Ant Design Vue 和 Vant 快速升级至 Vue 3,这些框架的源码主要使用 JSX 构建。
JSX 使用情况
在 NPM 上,@vue/babel-plugin-jsx 的周下载量高达 万次,这一数字也超越了 Vue 3 的下载量。然而,实际使用 JSX 的开发者人数远少于这一数字所反映的,因为大多数通过 vue-cli 创建的项目(无论是 Vue 2 还是 Vue 3)都会下载该插件。准确统计使用 JSX 开发的用户数量较为困难,大部分开发者仍然采用模板方式开发为主。
基本概念
在 Vue 中,.vue 结尾的文件称为 sfc(单一文件组件),通常包含三种类型的顶级语言块。
1.1 React 介绍
React 是一个用于构建用户界面的 JavaScript 库,起源于 Facebook 的内部开源项目。它不仅仅是一个框架,而是一个完整的前端开发生态体系,包含了多个相关的技术组件。学习 React 并非仅限于学习框架本身,而是要掌握整个技术栈和生态体系,本书将围绕这个技术栈系统讲解。
React 的核心组件包括 React.js,这是框架的核心库,需要在应用中先加载;以及 ReactDOM.js,蚂蚁帮源码这是用于将 React 组件渲染到实际 HTML 页面的渲染器。JSX 是 React 自定义的语法,用于在 JavaScript 代码中编写类似于 HTML 的标签。组件是 React 中的核心概念,所有页面元素都是通过组件表达,我们编写的大部分 React 代码都是围绕组件开发的。
虚拟 DOM(Virtual DOM)是 React 抽象出来的概念,它帮助提高了应用的性能,通过比较虚拟 DOM 和真实 DOM 的差异,仅更新需要变化的部分,而不是整个页面。单向数据流(one-way reactive data flow)是 React 的核心设计模式,数据流向自顶向下,确保了代码的清晰性和预测性。
了解了基本概念和一个简单的“Hello React World”示例之后,你可能会有如下疑问:JSX 语法与 HTML 有何不同?为什么 React 除了 JSX 之外没有其他特别之处,它与其他框架有何不同?“Hello World”并不能展示 React 的全部能力,那它能做些什么?答案分别在后续章节中详细阐述。
React 的独特之处在于其组件的组合模式,该模式模糊了简单元素和复杂元素的概念,使得客户程序能够像处理简单元素一样处理复杂元素,从而实现了与复杂元素内部结构的解耦。单向数据流设计让前端 bug 定位变得简单,页面 UI 和数据的对应关系清晰,便于追踪问题。高效的性能得益于虚拟 DOM 算法,它只更新需要改变的元素,显著提升了应用的响应速度。
React 的分离框架设计允许它在 Web、服务端(如 Node.js)、原生应用(如 iOS 或 Android)和桌面应用(如使用 NW.js 或 Electron)上运行。amcl 源码解读React.js 的源码已分为 ReactDOM 和 React.js 两部分,这意味着它可以在不同环境中灵活使用。
React 应用范围广泛,从简单的 Web 应用,如 TODOAPP 或电商网站,到数据可视化、图表展现甚至游戏开发。在 Web 端,React 也能实现数据可视化和 UI 控制。通过 React Native,开发者可以使用 JSX 编写具有原生应用性能的 UI,适用于 iOS 和 Android 应用开发。此外,React 还支持服务器端渲染,使得在服务器端生成 HTML,优化了前后端分离架构。
React Native UI界面还原,组件布局与动画效果
React Native UI与Android XML布局的对比,显示了两者之间的相似性。在《ReactJS到React-Native,架构原理概述》一文中提到,React框架在Web环境中,通过最终渲染到浏览器的真实DOM中。而在React Native环境中,通过编译后的JSX源码与对应平台的Bridge通信,实现与原生框架的交互。如果在程序中调用React Native API,React Native框架通过Bridge调用原生框架方法。
React Native底层为React框架,UI层的变更映射至虚拟DOM进行diff算法,计算变动后的编程序源码JSON文件,最终由原生层渲染到iOS与Android平台的页面元素上。编写React Native代码最终生成main.bundle.js文件,支持本地或服务器下载。Yoga,一个C语言编写的CSS3/Flexbox跨平台布局引擎,旨在实现iOS、Android、Windows平台的布局兼容,通过API向开发者开放,简化界面布局。
React Native核心组件与API提供了丰富的UI构建基础,样式方面支持通过JavaScript添加样式表,Flexbox布局提供了响应式App的最佳选择,但在样式一致性上与Web应用存在差异。Weex等开源项目利用了React和宿主平台间的桥接,实现了一个简化版的CSS子集,主要通过flexbox布局,与Android的LinearLayout相似,但Flex布局在优先级上高于宽度。
动画系统包括Animated和LayoutAnimation,Animated以声明方式定义动画输入与输出,封装6个组件,实现效率优化。配置动画具有灵活性,支持自定义或预定义的 easing 函数、延迟、持续时间等。组合动画可实现同时执行、顺序执行、延迟等效果。合成动画值和插值功能丰富了动画控制。手机源码转换跟踪动态值和启用原生动画驱动提供了更高效、独立于JS线程的动画执行。
LayoutAnimation允许全局范围内创建和更新动画,无需测量或计算特定属性,适用于更新flexbox布局的动画。注意,尽管LayoutAnimation强大,但对动画控制不如Animated等库方便,且在不同驱动方式间不兼容。若需在Android上使用LayoutAnimation,需在UIManager中启用。
å¨Reactä¸ä¸ºä»ä¹è¦ç¨JSXï¼
èµ·å
大家好ï¼ææ¯ç±åé±¼ç桶å¥Zãç¸ä¿¡ä½¿ç¨Reactå¼åçç«¥éï¼å¨ç¼åç»ä»¶çè¿ç¨ä¸æ¥è§¦æå¤çå°±æ¯JSXãé£ä¹ä¸ºä»ä¹Reactè¦ç¨JSXæ¥ç¼åç»ä»¶å¢ï¼JSXçæ¬è´¨æ¯ä»ä¹ï¼æ¯ä¸æ¯åªæReactæè½ç¨JSXï¼é对è¿å 个é®é¢ï¼ä»å¤©æ们就ä¸èµ·æ¥å¦ä¹ ä¸ä¸å§ã
JSXJSXå¨å®ç½ç解éæ¯ï¼å®æ¯ä¸ç§JavaScriptè¯æ³çæ©å±ï¼å¹¶ä¸å®å ·æJavaScriptçææç¹æ§ãå¦ææ人é®ä½ 为ä»ä¹Reactä¸è¦ä½¿ç¨JSXï¼å ¶å®æ¬è´¨æ¯é®ä½ 为ä»ä¹ä¸ç¨å ¶å®çæ¹æ¡æ¥å®ç°ï¼ä¸ºä»ä¹ååæ¯JSXï¼
é¦å ï¼æ们å¨åé¢ä¹äºè§£å°JSXæ¬è´¨æ¯JavaScriptçè¯æ³æ©å±ï¼å ¶æ¬¡ï¼å¨Reactçå¼åä¸ï¼React并ä¸æ¯å¼ºå¶è¦æ±ä¸å®è¦ä½¿ç¨JSXï¼æ们å®å ¨å¯ä»¥éè¿React.createElementæ¥å建Reactç»ä»¶ï¼ç±»ä¼¼ä¸é¢è¿æ ·ï¼
render(){ returnReact.createElement("div",null,"Hello",this.props.name);}èæ们éè¿JSXç¼åçç»ä»¶ï¼ç¸å¯¹React.createElementæ¥è¯´å°±è¦ç®æ´æäºè®¸å¤ï¼åæ ·çç»ä»¶ï¼ç¼åèµ·æ¥ä¼æ´ä¸ºç®æ´ï¼å¹¶ä¸ä»£ç çå±æ¬¡ä¹ä¼æ´å çæ¸ æ°ï¼ç±»ä¼¼ä¸é¢è¿æ ·ï¼
render(){ return<div>Hello{ this.props.name}</div>;}å½æ们使ç¨JSXå°ç»ä»¶ç¼åå®æåï¼Reactå é¨éè¦å°ç»ä»¶è½¬å为DOMæ ï¼çèµ·æ¥å°±åXMLä¸æ ·ãèXMLå¨æ ç»æçæè¿°ä¸å¤©çå°±å ·æå¯è¯»æ§å¼ºçä¼å¿ã
è½ç¶æ们æ¯éè¿JSXæ¥ç¼åç»ä»¶ï¼ä½æ¯æç»Reactè¿æ¯ä¼éè¿babelå°JSXç¼è¯ä¸ºjså¯æ§è¡ç代ç ãæ们ä¹æ以ä¸ç´æ¥ç¨React.createElementæ¥å建ç»ä»¶ï¼å¨åé¢ä¹å·²ç»è¯´æäºåå ï¼è¿éå°±ä¸åèµè¿°äºã
å 为æ们ç¥éæç»ç代ç ä¼éè¿babelç¼è¯æjså¯ç´æ¥æ§è¡ç代ç ï¼å æ¤JSXä¸ä» è½å¨Reactä¸è¿è¡ä½¿ç¨ï¼åæ ·å¨Vueä¸ä¹å¯ä»¥ä½¿ç¨JSXæ¥ç¼åç»ä»¶ã并ä¸ä½¿ç¨JSXç¼åçç»ä»¶ä¹å¯ä»¥ç¨äºè·¨ç«¯åºç¨ç渲æï¼ä¾å¦React-Nativeä¸ä½¿ç¨çç»ä»¶ç»æè·Reactç»ææ¯ä¸æ ·çã
æ©å±å¨ä¸é¢æ们ä»ç»äºJSXæç»ä¼éè¿babelç¼è¯ä¸ºjså¯æ§è¡ç代ç ï¼é£ä¹Babelæ¯å¦ä½å®ç°JSXå°jsçç¼è¯å¢ï¼æ们å¯ä»¥éè¿æ¥çç¸å ³çæºç æ¥äºè§£ä¸ä¸ï¼æºç å¦ä¸ï¼
module.exports=function(babel){ vart=babel.types;return{ name:"custom-jsx-plugin",visitor:{ JSXElement(path){ varopeningElement=path.node.openingElement;vartagName=openingElement.name.name;varargs=[];args.push(t.stringLiteral(tagName));varattribs=t.nullLiteral();args.push(attribs);varreactIdentfier=t.identifier("React")ï¼varcreateElementIdentifier=t.identifier("createElement");varcallee=t.memberExpression(reactIdentfier,createElementIdentifier);varcallExpression=t.callExpresion(callee,args);callExpression.arguments=callExpression.arguments.concat(path.node.children);path.replaceWith(callExpression,path.node);},},};}æåæ们éè¿å¦ä¹ äºè§£å°Reactä¸éç¨JSXçåå ï¼ä»¥åJSXçæ¬è´¨æ¯ä»ä¹ï¼ä¹äºè§£å°babelæ¯å¦ä½å°JSXç¼è¯ä¸ºjså¯æ§è¡ç代ç ãå¦æä½ å¯¹babelçç¼è¯æå ´è¶£ï¼å¯ä»¥å°babelå®æ¹ç½ç«è¿è¡æ¥çåå¦ä¹ ã
element-tabs组件 源码阅读
在深入分析element-tabs组件源码的过程中,需要把握两个基本前提:首先,对API有着深入的理解;其次,带着具体问题进行阅读,以便更高效地获取所需信息。遵循两个基本原则:不要过于纠结于那些无关紧要的细节,而应首先明确自己的实现思路,然后再深入阅读源码。接下来,我们将针对几个关键点进行详细探讨。
首先,我们关注于元素切换时的滑动效果。通过观察源码,可以发现这种效果实现的关键在于tabs内部的计算逻辑。在`/tabs/src/tab-nav.vue`文件中,使用jsx语法实现的逻辑中,通过判断`type`的类型来决定是否调用`tab-bar`。`tab-bar`内部通过计算属性来计算`nav-bar`的宽度,这一计算依赖于`tabs.vue`通过`props`传入的`panes`数据。这表明`nav-bar`的宽度是由`panes`数组驱动的,从而实现了动态调整和滑动效果。
接下来,我们探讨`border-card`中的边框显示机制。通过观察源码,发现`tabs.scss`中`nav-wrap`的样式设置为`overflow: hidden`。这个设置与边框显示之间的关系在于,通过改变当前选中的`tab`的`border-bottom-color`为`#fff`,来实现边框的动态显示效果。具体来说,当激活某个`tab`时,通过调整CSS样式使得边框底边颜色变白,从而达到视觉上的边框显现效果。实现的细节在于通过设置`nav`的盒子位置下移动1px,并且使激活的`tab`的`border-bottom`颜色为白色,以此达成效果。
再者,`tab-position`共有四个位置调节选项:`top`、`right`、`bottom`和`left`。通过分析源码可以发现,`top`是常规布局,而`left`与`right`是基于`BFC`的两侧布局,`bottom`则通过改变插槽子节点的位置来实现常规布局。具体实现细节在于`el-tabs__content`的代码中,针对`is-left`和`is-right`的SCSS代码,以及`is-top`和`is-bottom`的区别仅在于`tabs.vue`里的放置位置。这意味着`left`和`bottom`的布局是基于`BFC`的两侧等高布局,而`top`和`bottom`则只是常规流体布局,只是位置不同。
对于`stretch`功能的实现细节,通过分析源码可以得出当`stretch`设置为`false`时,`tab`的显示形式为`inline-block`;当设置为`true`时,父级变为`flex`布局,而子`tab`具有`flex:1`的属性。这表明`stretch`功能通过调整显示模式和布局方式,实现了`tab`的弹性扩展。
在业务逻辑方面,`tabs`组件的逻辑主要体现在计算`tabs`插槽里的`tab-pane`组件,并将其解析为对应的组件数组`panes`。渲染分为两部分:一方面,通过`tabs`组件将`panes`传给`tab-nav`渲染`tab-header`,另一方面,直接渲染`$slots.default`对应的`tab-pane`组件。`tabs`组件的选中状态由`currentName`控制。`tab-header`通过`inject`获取`tabs`实例的`setCurrentName`方法,从而操作选中的`tab`;而`tab-pane`则是通过`$parents.currentName`实时控制当前`pane`是否展示。
对于动态新增`tab`的细节,`tabs.vue`在`mounted`时会调用`calcPaneInstances`函数来获取对应的`panes`。`calcPaneInstances`的主要作用是通过`slots.default`获取对应的组件实例。`panes`在两个关键位置被使用:在`tab-nav`组件中构造`tab-header`,以及在不考虑切换影响的内容渲染中。当动态增加`tab-pane`时,虽然`panes`不会响应变化,但通过在`tabs.vue`的虚拟DOM补丁更新后执行`updated`钩子,可以自动更新`panes`。
此外,`tabs`插槽可以插入不受切换影响的内容,这一特性在`tabs.vue`中的渲染函数中体现。这里,全插槽内容都会被渲染,而`tab-pane`会根据`currentName`来决定是否展示。由此产生的效果是,插槽内容与`tab-pane`的选择逻辑完全分离,使得插槽内容不受切换状态影响。
当点击单个`tab`时,`tabs.vue`组件内部会通过`props`传递`handleTabClick`函数到`tabNav`组件。`nav`组件将该函数绑定到`click`事件上。当`click`事件触发时,如果不考虑`tab`是否为`disabled`状态,会触发`setCurrentName`函数。这个函数通过`beforeLeave`起到作用,以确保在切换到下一个`tab`之前进行适当的过渡。在`setCurrentName`中使用了两次`$nextTick`,其目的是确保在更新视图时子组件的`$nextTick`操作不会影响父组件的更新流程。
最后,源码中展示了`props`值`activeName`的使用,其功能与`value`类似,用于绑定选中的`tab`。源码中还提到了组件名称的获取方式,`props`值`vnode.tag`实际指向的是注册组件时返回的`vue-component+[name]`,而通过`vnode.componentOptions.Ctor.options.tag`可以获取正常组件名。如果在`options`中未声明`name`,那么组件名将基于注册组件时的名称。
通过这次深入阅读,我们不仅掌握了`element-tabs`组件的核心工作原理和实现细节,还学会了如何更有效地阅读和理解复杂的前端组件源码。在阅读过程中,耐心地记录问题、适时放松心情,都能帮助我们更好地理解代码,从而提升技术能力。
react源码解析8.render阶段
本文深入解析React源码中的渲染阶段,带你掌握React高效学习的精髓。让我们一起探索React的源代码,从基础到进阶,实现深入理解。
1. 开篇介绍和面试题
从最基础开始,解读面试题背后的原理,为你的学习之旅铺垫。
2. React设计理念
了解React的核心理念,为何它在现代前端开发中独树一帜。
3. React源码架构
拆解React源码结构,理解其设计的精妙之处。
4. 源码目录结构与调试
掌握React源码的目录布局和调试技巧,提升代码阅读效率。
5. JSX与核心API
深入学习JSX语法与React核心API,构建高效、灵活的组件。
6. Legacy与Concurrent模式入口函数
比较Legacy和Concurrent模式,了解React性能优化之道。
7. Fiber架构
揭秘Fiber的运作机制,理解React渲染的高效实现。
8. Render阶段
重点解析Render阶段的核心工作,构建Fiber树与生成effectList。
9. Diff算法
深入了解React的Diff算法,高效计算组件更新。
. Commit阶段
探索Commit阶段的流程,将Fiber树转换为真实DOM。
. 生命周期
掌握React组件的生命周期,优化组件性能。
. 状态更新流程
分析状态更新的机制,实现组件响应式的开发。
. Hooks源码
深入Hooks源码,理解状态管理与函数组件的结合。
. 手写Hooks
实践动手编写Hooks,巩固理解。
. Scheduler与Lane
探讨React的调度机制与Lane概念,优化渲染性能。
. Concurrent模式
探索Concurrent模式下的React渲染流程,提高应用的交互流畅度。
. Context
学习Context的用法,简化组件间的数据传递。
. 事件系统
深入事件处理机制,实现组件间的交互。
. 手写迷你版React
实践构建一个简单的React框架,深化理解。
. 总结与面试题解答
回顾学习要点,解答面试常见问题,为面试做好充分准备。
. Demo
通过实际案例,直观展示React渲染流程与技巧。
本课程带你全面掌握React渲染阶段的关键知识与实战技能,从理论到实践,提升你的前端开发能力。