了解什么是JSX
为什么要在Vue中使用jsx呢,首先我们需要了解JSX是什么,它解决了什么问题,最后如何使用它。
jsx的定义
JSX 是一种类似于 XML 的 JavaScript 语法扩展 JSX 不是由引擎或浏览器实现的。相反,我们将使用像 Babel 这样的转换器将 JSX 转换为常规 JavaScript。基本上,JSX 允许我们在 JavaScript 中使用类似 HTML 的语法。
jsx的优势
- 可以将 模版分离 这样模版的每个部分更加独立,又可以随机的组合,复用性更高。相比与组件的组合,粒度更细
- 使用 js 可配置每项要渲染的 dom,更加动态可配置化
小结
虽然了解了jsx的相关定义,可能对它还是比较陌生,首先要知道无论在 Vue中还是React,使用JSX 都是可选的。如:
// react 中使用jsx
class Hello extends React.Component {
render() {
return <div>Hello {this.props.toWhat}</div>;
}
}
// 同等效果的代码可以如下,只不过是babel帮我们做了这些
class Hello extends React.Component {
render() {
return React.createElement('div', null, `Hello ${this.props.toWhat}`);
}
}
了解Vue组件
在使用 Vue 时通常我们通过new Vue()是创建一个根实例,而组件是可复用的 Vue 实例 它们与 new Vue 接收相同的选项,例如 data、computed、watch、methods 以及生命周期钩子等。
new Vue({
data: {
foo: 1
},
computed: {
bar: function () { /* ... */ }
},
methods: {
baz: function () { /* ... */ }
}
})
为了处理多个组件映射关系,将路由实例对象作为参数传递给 Vue构造函数。new Vue()创建的是根实例,而每个页面组件实例通过 router 来控制。结构如下:
export default {
name: '',
props:{},
data:{},
methods:{}
}
可以看到路由映射的组件其实也是暴露出一个对象,在Vue就是通过一个对象去描述组件。而默认情况下,我们使用 template 作为模版,如果想使用 jsx 来渲染模版写格式如下,其实就是省略来 template 模版,取而代之使用 render 方法 return 要渲染的模版。并且其他都是选填项,render 方法必须返回出要渲染的模版。
export default {
name: '',
props:{},
data:{
return {
text:'hello jsx'
}
},
render(){
return <div>{text}</div>
},
methods:{}
}
Vue 中使用jsx
常用 React 的同学对 jsx 的语法比较熟悉,其实很多用法可以参照 react 的官方文档如下面我们会提到的常用语法
js 环境
在 Vue 模版中渲染一个变量的方式
<div id="app">
{{ message }}
</div>
包括使用 v-bind 绑定一个变量值
<span v-bind:title="message">
鼠标悬停几秒钟查看此处动态绑定的提示信息!
</span>
而在 jsx 中是用 {} 表示的相同的代码表示如下
render(){
return (
<div id="app">
<div>
{ message }
</div>
<span title={message}>
鼠标悬停几秒钟查看此处动态绑定的提示信息!
</span>
</div>
)
}
需要解释一下的是,在 Vue 中 "" 表示一个js环境,你可以在其中做一些简单的运算
<img :src="'/path/to/images/' + fileName">
,在 jsx 中{}表示 js 环境。<span>{3+2}</span>
v-if 语法糖
Vue常用的 v-if 来控制dom的显示隐藏,本质就是 dom 的渲染和卸载。那么在 jsx 中如何实现
data(){
return {
isShow:false
}
},
render(){
return <div>
{ this.isShow ? <span>显示啦</span>:null}
</div>
}
上面代码中 { } 表示一个js环境,判断this.isShow 的真假来控制 dom 的显示与否
绑定事件
Vue 中使用 v-on 来绑定事件 简写@
<button @click="onButtonClick">按钮</button>
而在jsx中绑定事件前面都会加一个 on- 作为前缀
<button onClick={this.onButtonClick}>按钮</button>
- 如何在 jsx 中传参
<button onClick={this.onButtonClick.bind(this,value)}>按钮</button>
上面对面中的 value 就是传递给 onButtonClick 函数的参数。首先通过 { } 建立起js环境,然后通过 this.onButtonClick 拿到定义在 methods 中定义的函数,通过 bind 函数给当前函数传递参数 value 并返回一个待执行的新函数。最终,onClick 绑定的是 bind 返回的新函数。
- 如何绑定子组件 emit 的事件,假设在 child.vue 中派发了一个 emit 事件,jsx中如何去绑定监听事件
// father.js
export default {
components:{
child
},
render(){
return <div>
<child onCancel={this.onCancel} />
</div>
}
}
// child.vue
methods:{
onCancelClick(){
this.$emit('cancel')
}
}
- 其他类型的事件的绑定 , 类比 onClick 就是前面加上 on-
<input onChange={this.onValueChange} />
v-for 枚举实现
在 Vue 中我们可以用 v-for 指令基于一个数组来渲染一个列表。
<ul id="example-1">
<li v-for="item in items">
{{ item.message }}
</li>
</ul>
在 jsx 中在 { } 使用数组的 map 方法遍历生成一个新的数组
<div>
{this.tagList.map(item => {
return <div>{item}</div>
})}
</div>
slot
Vue 中在标签中间添加内容的方式,向组件传递内容,slot 位置内容会被传入的内容替代
// 传值
<alert-box>
Something bad happened.
</alert-box>
// 接收
Vue.component('alert-box', {
template: `
<div class="demo-alert-box">
<slot></slot>
</div>
`
})
jsx 中通过 this.$slots 对象可以拿到组件标签中的内容
<Temp>
123
<span>ccc</span>
</Temp>
// Temp.js
export default {
render(){
return <h1>{this.$slots.default}</h1>
}
}
- 具名插槽
<Temp>
123
<span slot="text">ccc</span>
</Temp>
// Temp.js
export default {
render(){
return <h1>{this.$slots.text}</h1>
}
}
- 解构插槽
export default {
data(){
return {
list: [
{
"id":11,
"name":"保险百科"
}
],
propList: [
{
props: {
prop: "name",
label: "分类名称"
}
},
]
}
},
render(){
let slot = {
scopedSlots :{
default :props=>{
return <h1>{props.row.name}</h1>
}
}
}
return (
<el-Table data={this.list} >
{this.propList.map((item, index) =>{
return (
<el-table-column {...item} {...slot} ></el-table-column>
)
}
)}
</el-Table>
)
}
}
props 属性传递
Vue 中父组件传递 props 给子组件 通过 v-bind,如果有多个值需要传递,则需要声明多个props,或者传递一个对象给子组件,
<my-component :prop="someThing"></my-component>
而 jsx 中可以使用... 扩展符来实现多个值的传递,注意传递的属性需要声明在 props 对象下
render(){
let value = {
props:{
type:'primary',
disabled:'disabled'
}
}
return (
<el-button {...value}>按钮</el-button>
)
}
codepen 完整示例
codepen 上没有找到 babel-plugin-transform-vue-jsx 插件,无法正常展示,可以copy代码到本地项目使用