vue项目中为什么用jsx,vue3.0 jsx
本文主要介绍为什么推荐JSX开发vue3,帮助你更好的理解和使用vue框架。感兴趣的朋友可以了解一下。
长期以来,Vue官方一直将推广重点放在简单的动手上。这确实给Vue带来了非常庞大的用户量,尤其是对需求开发效率的追求。
在往往不太关心工程代码质量的国内中小企业中,Vue的份额增长很快。但是,作为开发商自己,我们必须认识到一个关键点。简单性和重用不应该在技术选择中占据很大份额,而是可维护性。
万一有的同学真的不看公文,我先提一下。证监会是。在写vue组件时写的Vue文件。这个文件是一个SFC,全称是单文件组件,也就是单文件组件。
在开始我的个人观点之前,我们先来看几个事实:
是的,Vue3的定义原生支持JSX,Vue3源代码中有JSX.d.ts,方便使用JSX。不知道同学们看到这个会怎么想,
我的第一反应是:社区对JSX的需求不小,所以会把Vue3对JSX的官方支持往后推。
第二,AntDesign的vue3版本基本都是用JSX开发的,现在Vue3的官方babel-jsx插件最初都是阿里的人维护的。
虽然我一直不喜欢阿里的KPI驱动技术,目前的JSX语法支持也不符合我的预期,但至少我认同AntDesign团队的观点,JSX开发是更好的选择。
好了,说这些东西,主要是摆出一些事实作为依据,让有些同学什么都不用拿:
啊,都是你想出来的。你太自我了。
不管你怎么想,都没用。我们的Vue应该用SFC开发。
这些观点批评我。首先我会从客观的角度分析一下为什么。至少,我能说出强弱的原因。
好了,序言差不多到了。接下来我给大家分析一下为什么要选择JSX发展Vue。
TypeScript 支持
其实第一点已经是杀手锏了。对于想用TypeScript开发Vue3应用的同学来说,这简直是SFC无法攻克的世界难题。
总之:TypeScript原生支持JSX语法,但基本上不希望ts官方能支持SFC的模板语法。
毫无疑问,ts在前端社区越来越重要,但任何一个未来对代码质量有一定要求的前端团队,都应该选择TS进行开发。
现在基本上你可以在NPM上看到软件包,你可以找到相应的TS定义。现在用TS开发的成本只是你懂不懂TS语法。在这种情况下,你是否支持TS是未来发展模式不会走远的重要原因。
目前SFC只能允许TS进口。vue文件,但是所有SFC组件的定义都是相同的:
声明模块“*”。vue {
从“vue”导入{ DefineComponent }
const component:define component {},{},{ },any
导出默认组件
}
也就是说你介绍的SFC组件TS不知道这个组件应该收到什么道具。所以你享受不到这些TS的优点:
开发过程中自动提示
编译时的TS检查允许您尽早发现问题。
编译组件会生成您的组件定义(这对类库开发尤其重要)。
当然你会说,既然Vue可以正式开发SFC的语法,自然会支持这些特性。我说当然可以,但是这个难度非常大,需要多方面的支持,甚至官方ts团队都愿意协助。
但我想不出TS官方有什么理由支持SFC,因为这只是Vue自己创造的一种方言,其他场景用不到。TS是面向整个社区的,我认为他们不会考虑积极支持SFC。
那么有同学要问了,JSX不也是非母语的JS语法吗?他怎样才能得到TS官方的支持?FB和微硬有PY交易吗?
这让我想到了第二点,JSX和静态模板之间的灵活性差异。
JSX 其实并不是方言
很多人都犯了一个错误,就是认为SFC的模板语法和JSX一样,是别人发明的语法,不是JS原生的。这是事实,但也有一些差异,这主要体现在对JSX的认识上。
一句话:JSX没有扩展JS的语法,只是缩写了JS的写法!它的本质就是JS的语法糖。
就像es6加的语法糖,比如
常数a=1
常数b=2
const obj={ a,b }
//实际上相当于
const obj={ a: a,b: b }
这种写法并没有拓展JS的能力,只是简单的让它变得更容易,JSX也是一样。
JSX实际上是一个方法调用,JS和JS是一一对应的。让我们看一个例子:
const element=div id= root hello World/div
这里的JSX语法实际上是:
const element=createElement( div ,{ id: root }, Hello World )
而JSX就是全部,没有更多的内容,所以JSX只是一个方便我们编写嵌套函数调用的语法糖,它没有扩展任何其他内容。
但是SFC不一样。
SFC不仅定义语法,还定义文件。
SFC的具体定义是单个文件组件,它本身就把一个文件当作一个单元,所以约束力要大得多。要使用SFC,您必须有一个固定的文件结构,这造成了许多限制:
一个文件中只能写入一个组件。
节点片段只能写在模板里,非常不灵活。
一个变量绑定只能获取this的内容,而不能使用全局变量(很多时候我们要先在this上挂载全局变量)。
让我们稍微谈一谈。
一个文件只能写一个组件
说实话,这非常非常不方便。很多时候,我们在编写页面的时候,往往需要把一些小的节点片段拆分成小部件来复用(如果你现在没有这个习惯,可能是因为SFC的限制,你习惯把它们都写在一个文件里)。
React生态系统中丰富的css-in-js方案就是一个很好的例子。我们可以使用:
const styled button=styled( button ,{
颜色:红色,
})
如果我们需要在这个页面中使用特定样式的按钮,通常会以这种方式将它们封装在页面文件中。因为不需要拆分这个组件,而且它不是一个可重用的组件,所以需要再次导入。
Vue生态基本没有css-in-js的成熟方案,其实和这个限制有很大关系。
我们再举一个例子。比如我们封装了一个Input组件,想把Password组件和Textarea组件都导出,方便用户根据实际需要使用。这两个组件是内部使用的输入组件,只是定制了一些道具:
常量输入={.}
导出默认输入
导出常量Textarea=(props)=输入多行={true} {.道具} /
导出常量密码=(props)=输入类型=密码 {.道具} /
它可以在JSX非常简单地实现,但是如果它通过了SFC,你可能不得不强行把它分成三个文件。此外,为了方便起见,您可能需要添加一个index.js来导出这三个组件。你能想象这需要多少工作吗?
节点片段只能写在 template 里面,非常不灵活
不知道有多少同学看过Vue的模板编译的代码。以我的经验来看,他们的阅读量可能不会超过50%(乐观估计)。如果还不知道的话建议同学们去尝试一下。
为什么要看这个?因为看完之后你会发现你在模板里写的类似HTML的内容和HTMl完全没有关系,它们也会被编译成类似JSX编译的结果。
{
渲染(h) {
返回h(div ,{on: {},props: {}},h(span ))
}
}
类似的结果,这里H函数调用的结果是一个VNode,它是Vue中节点的基本单位。因为这些单元是一个对象,它们当然可以作为参数传递。
也就是说,理论上他们可以通过props将节点作为参数传递给其他组件。
这种做法在React中非常常见,称为renderProps,而且非常灵活:
const Comp=()=Layout header={ my header/} footer={ my footer/}/
但是由于SFC模板的限制,我们很难在SFC中编写道具上的节点:
模板
Layout:header= my header//Layout
/模板
这是不可能的,因为SFC定义了头绑定只能接受js表达式,而MyHeader/显然不是。
因为通过 props 传递不行,所以 Vue 才发明了 slot 插槽的概念
虽然我们口口声声说Vue简单,但实际上ScopedSlots一度成为初学者理解Vue的噩梦,很多同学都被这种令人费解的范围害死了。
让我们看一个ScopedSlots的例子:
模板
免费票
模板v-slot:scope=ctx
div{{ctx.name}}/div
/模板
/Comp
/模板
这里ctx是Comp中的属性,通过这种方式传出来,这样我们就可以在当前组件中调用父组件中的属性。这简直是理解的噩梦,但是实现与JSX类似的功能却非常简单:
comp scope={ name=div { name }/div }/
我们只是将一个函数传递给一个叫做scope的道具。这个函数接受一个name属性,这个属性将在Comp中被调用,name将被传入。
简单来说,我们传入的是一个构建节点片段的函数。就这么简单。
这是因为SFC的模板限制,导致灵活性不足。Vue需要创造概念和关键词来抹平这些不足,创造出来的概念自然引入了学习成本。
其实我并不认同Vue比React好学的说法。如果你真的研究了所有的用法,总是试图用最合理的方式实现功能,那么Vue永远不会比React简单。
变量绑定只能获取this上面的内容,不能使用全局变量
这体现在两个方面。一个是我们全局定义的一些固定数据,如果要在组件中使用,应该通过这个挂载到组件上。
比如我们缓存一个城市的数据,基本不会改变,所以不需要把它挂载到组件上使其有响应性。但这在SFC中是做不到的,
因为模板的执行上下文是在编译时绑定的。你在模板中访问的变量在编译时会自动绑定到这个,因为模板需要编译,字符串没有作用域也是这个概念。
这在JSX已经不存在了:
const citys=[]
const Comp=()={
返回citys.map(c=div{c}/div)
}
另一个方面是组件的使用。在SFC中,组件必须提前注册,因为我们在模板中写的只能是字符串,而不是具体的组件变量。
那么模板中的组件和真正的组件对象只能通过字符串匹配来绑定。这带来了以下问题:
增加注册组件的步骤,增加代码量。
用字符串名注册自然会产生可能的冲突。
模板解析组件支持不同的样式,比如MyComp和my-comp,很容易导致不同的样式。
在JSX不存在这样的问题,因为JSX直接使用组件引用作为参数:
const Comp={.}
const App=()=Comp /
需要通过directive来扩展能力
其实从上面可以看出,除了SFC本身的问题,Vue使用字符串模板也会带来很多灵活性的问题。
最直接的证据就是Vue用directive来扩展功能(当然这不是Vue发明的,模板引擎早就有类似问题了)。
为什么指令是最后的选择?因为静态模板缺乏逻辑处理的能力。我们以list循环为例。在JS中,我们可以很容易地通过map函数创建一个列表:
const list=arr . map(name=span key={ name } { name }/span
而且因为JSX本身就是一个函数调用,所以把上面的代码和JSX结合起来也是非常自然的:
const App=()=(
差异
标题/
{arr.map(name=(
span key={name}{name}/span
))}
/div
)
上述示例对应于JS,如下所示:
const App=()=
createElement(div ,{},[
标题/,
arr . map(name=createElement( span ,{ key: name },name)),
])
这还是因为JSX只是JS的语法糖。在JSX可以实现的一切在JSX也可以实现。
但是,SFC的模板是基于一个字符串编译的,这个字符串本身就是一个字符串。我们不能直接在模板中写map来循环节点(当然也可以写在可以接收表达式的地方,比如v-on)。
所以不能循环节点,需要这样的函数来渲染列表。我们做什么呢就是发明一个标志告诉编译器这里需要一个循环,在Vue中的体现就是v-for指令。
同学们可能要问了,既然Vue可以实现v-for,为什么不直接实现表达式循环链表呢?他当然可以实现,但他肯定不会选择,因为成本太高。
他要做的事情相当于实现了一个JS引擎。其实里面很多内容都是不必要的,一个v-for其实可以适用于大多数情况。
但是有了v-for,就需要v-if,然后后面就需要其他能力了。这是一种方言产生和发展的过程。
当然,指令不仅仅是JS表达式的替代品,还增加了一些其他的能力,比如它可以让我们更容易的访问DOM节点。
但是,我们之所以使用框架,是为了尽可能屏蔽DOM操作~
总结
这是我对应该使用JSX还是SFC进行开发的分析。其实说到底,SFC的问题是不拥抱JS。
他的语法是他自己发明的,需要一个JS实现的编译器让它在JS环境下运行,本质上是一个发明。
我们不能否认发明确实有优点,但不能只看它不看问题。如果我们没能拥抱JS,自然就很难充分重用JS社区的优势。
JS社区一直在蓬勃发展,有用的工具不断出现。然而,SFC想要使用JS社区的这些工具,必须自己实现另一个工具。我们可以统计一下SFC做的以下兼容性。
vue-loader在webpack中的应用
Eslint-plugin-vue到Eslint
汇总插件-用于汇总的vue
玩笑对玩笑
Vetur用作代码提示
基本上,我们需要等待Vue社区或者插件的官方开发,才能运行常用的工具。在babel和typescript的官方支持下,
基本上,所有新的JS生态工具都是原生支持的。
在Vue3准备的这个阶段,我们还是希望Vue社区能够用更好更规范的方式去开发。
其实如果直接用JSX开发Vue3,我们会发现很多时候并不需要用到emit和attrs的概念。
即使Vue3的JSX插件支持它,我们甚至可以放弃插槽。
但由于Vue3必须考虑兼容Vue2,潜力巨大的Vue3总是显得畏首畏尾,很可惜。
这就是为什么建议JSX开发Vue3。关于与JSX一起开发Vue3的更多信息,请关注我们的其他相关文章!
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。