Vue 之 JSX 初识篇
介绍一下 JSX
JSX 简介
JSX 是一种 Javascript 的语法扩展,JSX
= Javascript
+ XML
,即在Javascript
里面写XML
,因为JSX
的这个特性,所以他即具备了Javascript
的灵活性,同时又兼具html
的语义化和直观性。
学习 JSX,先了解一下 createElement
提到JSX
,不可避免的就要提到createElement
,当你看完本节,你会发现,奇怪的知识又增多了。
无论是Vue
还是React
,都存在createElement
,而且作用基本一致。可能你对createElement
不是很了解,函数名翻译过来就是增加一个元素,但他的返回值你一定知道。createElement
函数返回的值称之为虚拟节点,即VNode
,而由VNode
扎堆组成的树便是大名鼎鼎,面试必问的虚拟DOM
。
createElement
函数的参数,在这里抄一下Vue
官方文档
从上面可以看出createElement
一共有三个参数,三个参数分别是
- 第一个参数是需要渲染的组件,可以是组件的标签,比如
div
;或者是一个组件对象,也就是你天天写的export default {}
;亦或者可以是一个异步函数。 - 第二个参数是这个组件的属性,是一个对象,如果组件没有参数,可以传 null(关于组件的属性,下文将依次介绍)
- 第三个参数是这个组件的子组件,可以是一个字符串(textContent)或者一个由 VNodes 组成的数组
没有 v-model 怎么办,还有其他指令可以用吗?
当你选择使用JSX
的时候,你就要做好和指令说拜拜的时候了,在JSX
中, 你唯一可以使用的指令是v-show
,除此之外,其他指令都是不可以使用的,有没有感到很慌,这就对了。不过呢,换一个角度思考,指令只是Vue
在模板代码里面提供的语法糖,现在你已经可以写Js
了,那些语法糖用Js
都可以代替了。
v-model
v-model
是Vue
提供的一个语法糖,它本质上是由 value
属性(默认) + input
事件(默认)组成的, 所以,在JSX
中,我们便可以回归本质,通过传递value
属性并监听input
事件来实现数据的双向绑定
v-if 与 v-for
在模板代码里面我们通过v-for
去遍历元素,通过v-if
去判断是否渲染元素,在jsx
中,对于v-for
,你可以使用for
循环,array.map
来代替,对于v-if
,可以使用if
语句,三元表达式
等来代替
循环遍历列表
使用条件判断
v-bind
在模板代码中,我们一般通过 v-bind:prop="value"
或:prop="value"
来给组件绑定属性,在JSX
里面写法也类似
v-html 与 v-text
在说v-html
与v-text
之前,我们需要先了解一下Vue
中的属性,Vue
中的属性一共分为三种:
第一种是大家写 bug 时候最常用的props
,即组件自定义的属性;
第二种是attrs
,是指在父作用域里面传入的,但并未在子组件内定义的属性。
第三种比较特殊,是domProps
,经小编不完全测试,在Vue
中,domProps
主要包含三个,分别是innerHTML
,textContent/innerText
和value
。
-
v-html
: 在模板代码中,我们用v-html
指令来更新元素的innerHTML
内容,而在JSX
里面,如果要操纵组件的innerHTML
,就需要用到domProps
-
v-text
: 看了上面的v-html
,你是不是立即就想到了v-text
在JSX
的写法domPropsInnerText
,是的,你没有想错
但实际上我们不需要使用domPropsInnerText
,而是将文本作为元素的子节点去使用即可
实际上,对于domProps
,只有innerHTML
才需要使用domPropsInnerHTML
的写法,其他使用正常写法即可
我还要监听事件呢
监听事件与原生事件
当我们开发一个组件之后,一般会通过this.$emit('change')
的方式对外暴露事件,然后通过v-on:change
的方式去监听事件,很遗憾,在JSX
中你无法使用v-on
指令,但你将解锁一个新的姿势
JSX
中,通过on
+ 事件名称的大驼峰写法来监听,比如事件icon-click
,在JSX
中写为onIconClick
有时候我们希望可以监听一个组件根元素上面的原生事件,这时候会用到.native
修饰符,有点绝望啊,修饰符也是不能用了,但好在也有替代方案,如下代码
监听原生事件的规则与普通事件是一样的,只需要将前面的on
替换为nativeOn
除了上面的监听事件的方式之外,我们还可以使用对象的方式去监听事件
事件修饰符
和指令一样,除了个别的之外,大部分的事件修饰符都无法在JSX
中使用,这时候你肯定已经习惯了,肯定有替代方案的。
-
.stop
: 阻止事件冒泡,在JSX
中使用event.stopPropagation()
来代替 -
.prevent
:阻止默认行为,在JSX
中使用event.preventDefault()
来代替 -
.self
:只当事件是从侦听器绑定的元素本身触发时才触发回调,使用下面的条件判断进行代替
-
.enter
与keyCode
: 在特定键触发时才触发回调
除了上面这些修饰符之外,尤大大为了照顾我们这群 CV 仔,还是做了一点优化的,对于.once
,.capture
,.passive
,.capture.once
,尤大大提供了前缀语法帮助我们简化代码
插槽
插槽就是子组件中提供给父组件使用的一个占位符,插槽分为默认插槽,具名插槽和作用域插槽,下面小编依次为你带来每种在JSX
中的用法与如何去定义插槽。
默认插槽
- 使用默认插槽
使用element-ui
的Dialog
时,弹框内容就使用了默认插槽,在JSX
中使用默认插槽的用法与普通插槽的用法基本是一致的,如下代码所示:
- 自定义默认插槽
在Vue
的实例this
上面有一个属性$slots
,这个上面就挂载了一个这个组件内部的所有插槽,使用this.$slots.default
就可以将默认插槽加入到组件内部
具名插槽
- 使用具名插槽
有时候我们一个组件需要多个插槽,这时候就需要为每一个插槽起一个名字,比如element-ui
的弹框可以定义底部按钮区的内容,就是用了名字为footer
的插槽
- 自定义具名插槽
在上节自定义默认插槽时提到了$slots
,对于默认插槽使用this.$slots.default
,而对于具名插槽,可以使用this.$slots.footer
进行自定义
作用域插槽
- 使用作用域插槽
有时让插槽内容能够访问子组件中才有的数据是很有用的,这时候就需要用到作用域插槽,在JSX
中,因为没有v-slot
指令,所以作用域插槽的使用方式就与模板代码里面的方式有所不同了。比如在element-ui
中,我们使用el-table
的时候可以自定义表格单元格的内容,这时候就需要用到作用域插槽
- 自定义作用域插槽
使用作用域插槽不同,定义作用域插槽也与模板代码里面有所不同。加入我们自定义了一个列表项组件,用户希望可以自定义列表项标题,这时候就需要将列表的数据通过作用域插槽传出来。
只能在 render 函数里面使用 JSX 吗
当然不是,你可以定义method
,然后在method
里面返回JSX
,然后在render
函数里面调用这个方法,不仅如此,JSX
还可以直接赋值给变量,比如下面这段代码