接着上面的讲,当咱们看到上面用createElement
去实现组件,太麻烦了,别说工做效率提升了,就是那些嵌套能够嵌套正确就很赞了,因此咱们须要用JSX
javascript
methods: { $_handleInputUser(value) { this.formInline.user = value }, $_handleChangeRegion(value) { this.formInline.region = value }, $_handleSubmit() {} }, /** *将 h 做为 createElement 的别名是 Vue 生态系统中的一个通用惯例,实际上也是 JSX 所要求的。从 Vue 的 Babel 插件的 3.4.0 *版本开始,咱们会在以 ES2015 语法声明的含有 JSX 的任何方法和 getter 中 (不是函数或箭头函数中) 自动注入 *const h = this.$createElement,这样你就能够去掉 (h) 参数了。对于更早版本的插件,若是 h 在当前做用域中不可用,应用会抛错。 */ render(h) { return ( <ElForm inline model={this.formInline} class="demo-form-inline"> <ElFormItem label="审批人"> <ElInput value={this.formInline.user} onInput={this.$_handleInputUser} placeholder="审批人" ></ElInput> </ElFormItem> <ElFormItem label="活动区域"> <ElSelect value={this.formInline.region} onChange={this.$_handleChangeRegion} placeholder="活动区域" > <ElOption label="区域一" value="shanghai"></ElOption> <ElOption label="区域二" value="beijing"></ElOption> </ElSelect> </ElFormItem> <ElFormItem> <ElButton type="primarty" onClick={this.$_handleSubmit}> 查询 </ElButton> </ElFormItem> </ElForm> ) }
看了上面的代码,你们其实会发现用JSX
与template
的语法都属于xml
的写法,并且也比较像,但实质上仍是有许多区别的,下面我将为你们一一分析php
v-model
怎么办,还有其余指令能够用吗?当你选择使用JSX
的时候,你就要作好和指令说拜拜的时候了,在JSX
中, 你惟一可使用的指令是v-show
,除此以外,其余指令都是不可使用的,有没有感到很慌,这就对了。不过呢,换一个角度思考,指令只是Vue
在模板代码里面提供的语法糖,如今你已经能够写Js
了,那些语法糖用Js
均可以代替了。html
v-model
是Vue
提供的一个语法糖,它本质上是由 value
属性(默认) + input
事件(默认)组成的。因此,在JSX
中,咱们即可以回归本质,经过传递value
属性并监听input
事件来实现数据的双向绑定vue
export default { data() { return { name: '' } }, methods: { // 监听 onInput 事件进行赋值操做 $_handleInput(e) { this.name = e.target.value } }, render() { // 传递 value 属性 并监听 onInput事件 return <input value={this.name} onInput={this.$_handleInput}></input> } }
经我测试,在新版脚手架
vue-cli4
中,已经默认集成了对v-model
的支持,你们能够直接使用`,若是你的项目比较老,也能够安装插件
babel-plugin-jsx-v-model`来进行支持java
一样的,在JSX
中,对于.sync
也须要用属性+事件来实现,以下代码所示:c++
export default { methods: { $_handleChangeVisible(value) { this.visible = value } }, render() { return ( <ElDialog title="测试.sync" visible={this.visible} on={{ 'update:visible': this.$_handleChangeVisible }} ></ElDialog> ) } }
在模板代码里面咱们经过v-for
去遍历元素,经过v-if
去判断是否渲染元素,在jsx
中,对于v-for
,你可使用for
循环,array.map
来代替,对于v-if
,可使用if
语句,三元表达式
等来代替vue-cli
循环遍历列表element-ui
const list = ['java', 'c++', 'javascript', 'c#', 'php'] return ( <ul> {list.map(item => { return <li>{item}</li> })} </ul> )
使用条件判断c#
const isGirl = false return isGirl ? <span>小妹,哥哥教你写Vue</span> : <span>鸟你干啥</span>
在模板代码中,咱们通常经过 v-bind:prop="value"
或:prop="value"
来给组件绑定属性,在JSX
里面写法也相似babel
render() { return <input value={this.name}></input> }
在说v-html
与v-text
以前,咱们须要先了解一下Vue
中的属性,Vue
中的属性一共分为三种,第一种是你们写bug时候最经常使用的props
,即组件自定义的属性;第二种是attrs
,是指在父做用域里面传入的,但并未在子组件内定义的属性。第三种比较特殊,是domProps
,经小编不彻底测试,在Vue
中,domProps
主要包含三个,分别是innerHTML
,textContent/innerText
和value
。
v-html
: 在模板代码中,咱们用v-html
指令来更新元素的innerHTML
内容,而在JSX
里面,若是要操纵组件的innerHTML
,就须要用到domProps
export default { data() { return { content: '<div>这是Heo写的一篇新的文章</div>' } }, render() { // v-html 指令在JSX的写法是 domPropsInnerHTML return <div domPropsInnerHTML={this.content}></div> } }
v-text
: 看了上面的v-html
,你是否是当即就想到了v-text
在JSX
的写法domPropsInnerText
,是的,你没有想错
export default { data() { return { content: '这是Heo写的一篇新的文章的内容' } }, render() { return <div domPropsInnerText={this.content}></div> } }
但实际上咱们不须要使用domPropsInnerText
,而是将文本做为元素的子节点去使用便可
<div>{this.content}</div>
实际上,对于domProps
,只有innerHTML
才须要使用domPropsInnerHTML
的写法,其余使用正常写法便可
当咱们开发一个组件以后,通常会经过this.$emit('change')
的方式对外暴露事件,而后经过v-on:change
的方式去监听事件,很遗憾,在JSX
中你没法使用v-on
指令,但你将解锁一个新的姿式
render() { return <CustomSelect onChange={this.$_handleChange}></CustomSelect> }
JSX`中,经过`on` + 事件名称的大驼峰写法来监听,好比事件`icon-click`,在`JSX`中写为`onIconClick
有时候咱们但愿能够监听一个组件根元素上面的原生事件,这时候会用到.native
修饰符,有点绝望啊,修饰符也是不能用了,但好在也有替代方案,以下代码
render() { // 监听下拉框根元素的click事件 return <CustomSelect nativeOnClick={this.$_handleClick}></CustomSelect> }
监听原生事件的规则与普通事件是同样的,只须要将前面的on
替换为nativeOn
除了上面的监听事件的方式以外,咱们还可使用对象的方式去监听事件
render() { return ( <ElInput value={this.content} on={{ focus: this.$_handleFocus, input: this.$_handleInput }} nativeOn={{ click: this.$_handleClick }} ></ElInput> ) }
和指令同样,除了个别的以外,大部分的事件修饰符都没法在JSX
中使用,这时候你确定已经习惯了,确定有替代方案的。
.stop
: 阻止事件冒泡,在JSX
中使用event.stopPropagation()
来代替
.prevent
:阻止默认行为,在JSX
中使用event.preventDefault()
来代替
.self
:只当事件是从侦听器绑定的元素自己触发时才触发回调,使用下面的条件判断进行代替
if (event.target !== event.currentTarget){
return
}
.enter
与keyCode
: 在特定键触发时才触发回调
if(event.keyCode === 13) {
// 执行逻辑
}
除了上面这些修饰符以外,尤大大为了照顾咱们这群CV仔,仍是作了一点优化的,对于.once
,.capture
,.passive
,.capture.once
,尤大大提供了前缀语法帮助咱们简化代码
render() { return ( <div on={{ // 至关于 :click.capture '!click': this.$_handleClick, // 至关于 :input.once '~input': this.$_handleInput, // 至关于 :mousedown.passive '&mousedown': this.$_handleMouseDown, // 至关于 :mouseup.capture.once '~!mouseup': this.$_handleMouseUp }} ></div> ) }
插槽就是子组件中提供给父组件使用的一个占位符,插槽分为默认插槽,具名插槽和做用域插槽,下面我依次为您带来每种在JSX
中的用法与如何去定义插槽。
使用默认插槽
使用element-ui
的Dialog
时,弹框内容就使用了默认插槽,在JSX
中使用默认插槽的用法与普通插槽的用法基本是一致的,以下代码所示:
render() { return ( <ElDialog title="弹框标题" visible={this.visible}> {/*这里就是默认插槽*/} <div>这里是弹框内容</div> </ElDialog> ) }
自定义默认插槽
在Vue
的实例this
上面有一个属性$slots
,这个上面就挂载了一个这个组件内部的全部插槽,使用this.$slots.default
就能够将默认插槽加入到组件内部
export default { props: { visible: { type: Boolean, default: false } }, render() { return ( <div class="custom-dialog" vShow={this.visible}> {/**经过this.$slots.default定义默认插槽*/} {this.$slots.default} </div> ) } }
使用具名插槽
有时候咱们一个组件须要多个插槽,这时候就须要为每个插槽起一个名字,好比element-ui
的弹框能够定义底部按钮区的内容,就是用了名字为footer
的插槽
render() { return ( <ElDialog title="弹框标题" visible={this.visible}> <div>这里是弹框内容</div> {/** 具名插槽 */} <template slot="footer"> <ElButton>肯定</ElButton> <ElButton>取消</ElButton> </template> </ElDialog> ) }
自定义具名插槽
在上节自定义默认插槽时提到了$slots
,对于默认插槽使用this.$slots.default
,而对于具名插槽,可使用this.$slots.footer
进行自定义
render() { return ( <div class="custom-dialog" vShow={this.visible}> {this.$slots.default} {/**自定义具名插槽*/} <div class="custom-dialog__foolter">{this.$slots.footer}</div> </div> ) }
使用做用域插槽
有时让插槽内容可以访问子组件中才有的数据是颇有用的,这时候就须要用到做用域插槽,在JSX
中,由于没有v-slot
指令,因此做用域插槽的使用方式就与模板代码里面的方式有所不一样了。好比在element-ui
中,咱们使用el-table
的时候能够自定义表格单元格的内容,这时候就须要用到做用域插槽
data() { return { data: [ { name: 'Heo' } ] } }, render() { return ( {/**scopedSlots即做用域插槽,default为默认插槽,若是是具名插槽,将default该为对应插槽名称便可*/} <ElTable data={this.data}> <ElTableColumn label="姓名" scopedSlots={{ default: ({ row }) => { return <div style="color:red;">{row.name}</div> } }} ></ElTableColumn> </ElTable> ) }
自定义做用域插槽
使用做用域插槽不一样,定义做用域插槽也与模板代码里面有所不一样。加入咱们自定义了一个列表项组件,用户但愿能够自定义列表项标题,这时候就须要将列表的数据经过做用域插槽传出来。
render() { const { data } = this // 获取标题做用域插槽 const titleSlot = this.$scopedSlots.title return ( <div class="item"> {/** 若是有标题插槽,则使用标题插槽,不然使用默认标题 */} {titleSlot ? titleSlot(data) : <span>{data.title}</span>} </div> ) }