这是我参与11月更文挑战的第1天,活动详情查看:2021最后一次更文挑战
JSX是什么
JavaScript + XML = JSX
是一种 HTML-in-JavaScript
的语法,既不是字符串也不是 HTML,是属于 JavaScript 语法上的拓展
利用 JSX,在 React 使用 JavaScript,来声明元素(构成 React 应用的最小单位),继而描述用户页面
建议将JSX与 React 一起使用来描述 UI 应该是什么样子。JSX 可能会让您想起 模板语言,但它具有 JavaScript 的全部功能。JSX 产生 React “元素”,可将它们渲染到 DOM
为何在Vue中使用JSX
(可能会有这样的疑惑:在Vue中用JSX,不如选 React……)
来个声明
首先,此文并不是推崇用 JSX 作为主流去进行 Vue 开发,放弃 SFC 的优势
Vue 推荐在绝大多数情况下使用模板(template)来创建你的 HTML
尤大大在某乎点赞了文章:# 前端开发,为什么我支持模板而不是JSX。
作者提到几点原因:
- 需要 JSX 的情况,往往是出现在不合格的设计中
- 需额外考虑 JSX 编译为虚拟 DOM 的执行情况
- View 与 Model 通过 ViewModel 实现双向绑定,但 JSX 是偏向模板和逻辑分离的写法
- 性能方面:JSX 过度的灵活性,编译阶段难优化
- 补充:Vue 3.x,在编译优化方面:重写了 diff 算法,编译生成了 Block tree,性能有更大的提升
辅助角色
一枚硬币有正反两面,JSX 虽然有明显的缺点,但是相对而言,也存在一定的优点
先来看看一个需求场景:根据判断,从多个组件中选择一个来渲染 (基于 Vue 2.x)
进行以下选择:
-
template模板
-
有几种条件判断结果就有几个条件判断,可能会是
v-if => v-else-if => …… => v-else
,template较长,略笨重 -
基于上述,把每个组件都抽离出来为子组件,单独为一个.vue文件,再用上动态组件,template是简化了,但组件引用多了
-
如果抽离的子组件都不算太复杂,加上复用性不大(假设就为此需求服务),就需考虑抽离的必要性
-
-
render函数
-
即使结构使较简单的情况下,render 函数的写法也变得复杂,不够直观,可读性差
return h("div", [ h( "el-button", { props: { plain: true }, style: { marginRight: "10px" } }, "Hello World" ) ]);
- 条件判断较多,代码量一大,写起来更为痛苦,果断放弃
-
-
JSX
- template 和 render 的方案都觉得不太合适,试试在 components 选项中用 JSX 写个小组件
components: { demoChild: { props:{//……}, render() { const events = { on: { click: (e) => console.log(e) } }; return ( <div> <el-button plain style="{margin-right: 10px}"> Hello World </el-button> <el-button type="info" {...events}> Hello JSX </el-button> </div> ); } } }
可以看出:JSX 写法与 template 模板类似,相对而言:
-
可读性提高,避免较笨重的 template 写法
-
可减少组件引入,避免不必要的抽离
所以,个人认为,JSX 灵活性高,一定程度上,Vue开发中可作为辅助手段
案例
element-ui 组件库的开发中,更为直观地使用 JSX 的有:submenu、avatar,等等
submenu源码如:
// 无template
<script>
// ……
render(h) {
const popupMenu = (
<transition name={menuTransitionName}>
<div>……</div>
</transition>
);
const inlineMenu = (
<el-collapse-transition>
<ul>……</ul>
</el-collapse-transition>
);
return (
<li>
<div
class="el-submenu__title"
ref="submenu-title"
on-click={this.handleClick}
on-mouseenter={this.handleTitleMouseenter}
on-mouseleave={this.handleTitleMouseleave}
style={[paddingStyle, titleStyle, { backgroundColor }]}
>
{$slots.title}
<i class={["el-submenu__icon-arrow", submenuTitleIcon]}></i>
</div>
{this.isMenuPopup ? popupMenu : inlineMenu}
</li>
);
}
</script>
链接传送门
Last but not least
如有不妥,请多指教呀~