JSX就是Javascript和XML结合的一种格式。React发明了JSX,利用HTML语法来建立虚拟DOM。当遇到<,JSX就当HTML解析,遇到{就当JavaScript解析.html
想折腾一下呗,开玩笑.最开始是由于近期在学习react,在里面体验了一把jsx语法,发现也并无别人说的很难受的感受啊,因而就想尝试在vue中也试下,废话很少说,先来用代码来看下二者的区别吧.vue
ps:vue中大部分场景是不须要用render函数的,仍是用模板更简洁直观.react
// item.vue
<template>
<div>
<h1 v-if="id===1">
<slot></slot>
</h1>
<h2 v-if="id===2">
<slot></slot>
</h2>
<h3 v-if="id===3">
<slot></slot>
</h3>
<h4 v-if="id===4">
<slot></slot>
</h4>
</div>
</template>
<script>
export default {
name: "item",
props:{
id:{
type:Number,
default:1
}
}
}
</script>
复制代码
item组件中就是接收父组件传过来的id值来显示不一样的h标签,v-if能够说用到了"极致",并且写了不少个冗余的slotgit
// item.vue
<script>
export default {
name: "item",
props:{
id:{
type:Number,
default:1
}
},
render(){
const hText=`
<h${this.id}>${this.$slots.default[0].text}</h${this.id}>
`
return <div domPropsInnerHTML={hText}></div>
}
}
</script>
复制代码
再加上父组件来控制props的值。父组件不作对比还用传统的template格式,github
// list.vue
<template>
<div>
<h-title :id="id">Hello World</h-title>
<button @click="next">下一个</button>
</div>
</template>
<script>
import Title from './item'
export default {
name: "list",
data() {
return {
id:1
}
},
components: {
"h-title":Title
},
methods:{
next(){
++this.id
}
}
}
</script>
复制代码
运行后页面就渲染出了h1 or h2 or h3标签,同时slot也只有一个,点击切换props的值,也会显示不一样的h标签。第二种写法虽然不是很直接,可是省去了不少冗余代码,页面一下清爽了不少。面试
不要着急,这些指令只是黑魔法,用js很容易实现。数组
render(){
return (
<div>
{this.show?'你帅':'你丑'}
</div>
)
}
复制代码
写三元表达式只能写简单的,那么复杂的还得用if/elsebash
render(){
let ifText
if(this.show){
ifText=<p>你帅</p>
}else{
ifText=<p>你丑</p>
}
return (
<div>
{ifText}
</div>
)
}
复制代码
data(){
return{
show:false,
list:[1,2,3,4]
}
},
render(){
return (
<div>
{this.list.map((v)=>{
return <p>{v}</p>
})}
</div>
)
}
复制代码
在jsx中{}中间是没办法写if/for语句的只能写表达式,因此就用map来当循环,用三元表达式来当判断了babel
v-modeldom
最近在帮公司面试招人发现v-model不少人都不知道语法糖是什么?而后有些人说我能够用原生js实现,可是他们居然不知道在vue中怎么实现,好吧,两个点:传值和监听事件改变值。
<script>
export default {
name: "item",
data(){
return{
show:false,
list:[1,2,3,4],
text:'',
}
},
methods:{
input(e){
this.text=e.target.value
}
},
render(){
return (
<div>
<input type="text" value={this.text} onInput={this.input}/>
<p>{this.text}</p>
</div>
)
}
}
</script>
复制代码
很简单,只须要导入进来,不用再在components属性声明了,直接写在jsx中好比
<script>
import HelloWolrd from './HelloWorld'
export default {
name: "item",
render(){
return (
<HelloWolrd/>
)
}
}
</script>
复制代码
来看下面的写法
render (h) {
return (
<div
// normal attributes or component props.
id="foo"
// DOM properties are prefixed with `domProps`
domPropsInnerHTML="bar"
// event listeners are prefixed with `on` or `nativeOn`
onClick={this.clickHandler}
nativeOnClick={this.nativeClickHandler}
// other special top-level properties
class={{ foo: true, bar: false }}
style={{ color: 'red', fontSize: '14px' }}
key="key"
ref="ref"
// assign the `ref` is used on elements/components with v-for
refInFor
slot="slot">
</div>
)
}
复制代码
上面有个地方须要注意,当给自定义组件绑定事件时用nativeOnClick,而模板格式是用 @click.native
,另外当用到给函数式组件绑定事件时就有点小坑了下面说。
函数式组件无状态,无this实例,下面是vue文档中提到的一段话:
由于函数式组件只是一个函数,因此渲染开销也低不少。然而,对持久化实例的缺少也意味着函数式组件不会出如今 Vue devtools 的组件树里。
我我的理解由于没了状态(data),少了不少响应式的处理,还有生命周期等过程会提升速度和减小内存占用吧?
函数式组件也能够在模板格式中用只须要这样
<template functional>
</template
复制代码
那jsx中的函数式组件呢?也很简单只需增长配置functional: true
就能够了 那函数式组件没有了this
实例怎么绑定事件怎么获取props呢?
组件须要的一切都是经过上下文传递,包括:
props
: 提供全部 prop 的对象children
: VNode 子节点的数组slots
: 返回全部插槽的对象的函数data
:传递给组件的数据对象,并将这个组件做为第二个参数传入 createElement上面我只列举了部分属性,这些是非函数式组件的东西,对于函数式组件 vue 增长了context对象,须要做为render(h,context)
第二个参数传入,this.$slots.default
更新为context.children
props本来是直接挂在this上的,如今变为context.props
挂在了context.props上。this.data
变为了context.data
须要注意的是对于函数式组件,没有被定义为prop的特性不会自动添加到组件的根元素上,意思就是须要咱们手动添加到组件根元素了,看个例子吧
//父组件
...省略无关代码
render(){
return (
<Item data={this.data} class="large"/>
)
}
//Item.vue组件
export default {
functional:true,
name: "item",
render(h,context){
return (
<div class="red" >
{context.props.data}
</div>
)
}
}
复制代码
上面代码期待的是.large类名传入到了Item的根元素上,可是其实没有。咱们须要增长点东西
// Item.vue
export default {
functional:true,
name: "item",
render(h,context){
return (
<div class="red" {...context.data}>
{context.props.data}
</div>
)
}
}
复制代码
注意到,经过展开运算符把全部的属性添加到了根元素上,这个context.data就是你在父组件给子组件增长的属性,他会跟你在子元素根元素的属性智能合并,如今.large类名就传进来了。这个颇有用,当你在父组件给子组件绑定事件时就须要这个了。下面说一个关于绑定事件的小坑
向 createElement 经过传入 context.data 做为第二个参数,咱们就把 my-functional-button 上面全部的特性和事件监听器都传递下去了。事实上这是很是透明的,那些事件甚至并不要求 .native 修饰符
上面是vue官网的一段话,然而我看了一遍就忽略了一句很重要的话,就是最后一句,他说不须要.native修饰符了?好先看代码
// 父组件
methods:{
show(){
alert('你好')
}
},
render(){
return (
<Item data={this.data} onNativeClick={this.show} class="large"/>
)
}
复制代码
上面代码乍一看没毛病,自定义组件用onNativeClick嘛,结果就是不会弹窗。唉,最后读了几遍刚才vue文档中的解释,才发现原来函数式组件不须要.native修饰符,对于template格式确定一下就反应过来了,可是jsx的话,好吧,把上面的onNativeClick
从新改成onClick
就行了。
这个其实跟最开始我例举的例子很像。我在项目中用它来干掉了满屏的v-if/v-else 因为个人业务是pad上的,需求是一套试卷有几十道题目,要求一屏只显示一道题目,点击下一题显示下一个题,思路也比较简单:
这一写,模板里面好多啊,因为咱们的题目每道题的模板可能都不同,因此没办法循环,只能手写所有。以前考虑过用动态组件来切换,可是放弃了,由于没有if直观啊。
下面看怎么用jsx优化一下
//父组件
export default {
name: "list",
data() {
return {
data:'我是函数式组件',
id:1,
tests:{
1:<div><span>第一道题</span></div>,
2:<div><section>第二道题</section></div>,
3:<div><p>第三道题</p></div>
}
}
},
methods:{
next(){
++this.id
}
},
render(){
return (
<div>
<Item data={this.tests[this.id]} class="large"/>
<button onClick={this.next}>下一题</button>
</div>
)
}
}
复制代码
上面每道题目的结构都不一致
//子组件,只接受数据展现,用函数式组件
<script>
export default {
functional:true,
name: "item",
render(h,context){
return (
<div class="red" {...context.data}>
{context.props.data}
</div>
)
}
}
</script>
复制代码
上面没有用任何if/else判断就完成了功能,这里用jsx我以为比较合适,不知道各位大佬有什么其余思路?
总结一下吧,咱们平时开发仍是多用temlate由于直观简洁,各类指令用着很方便,等你以为用template写出的代码看着很冗余,或者想本身控制渲染逻辑好比循环,判断等等时能够考虑用JSX。另外推荐你们多用函数式组件提升性能。
第一次写文章,但愿各位花时间看了的大佬以为哪一个说的不太严谨还需多多包涵,提出意见我都接受。