什麼是JSX?
JSX就是Javascript和XML連繫的一種花樣。React發清楚明了JSX,應用HTML語法來建立假造DOM。當碰到<,JSX就當HTML剖析,碰到{就當JavaScript剖析.
我為何要在vue頂用JSX?
想折騰一下唄,開頑笑.最最先是因為近期在進修react,在內里體驗了一把jsx語法,發明也並沒有他人說的很難熬痛苦的以為啊,因而就想嘗試在vue中也試下,空話不多說,先來用代碼來看下二者的區分吧.
ps:
vue中大部份場景是不須要用render函數的,照樣用模板更簡約直觀.## 運用template
// 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能夠說用到了”極致”,而且寫了許多個冗餘的slot
## 運用render函數和jsx
// 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花樣,
// 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標籤。第二種寫法雖然不是很直接,然則省去了許多冗餘代碼,頁面一下清新了許多。
## 沒了v-if,v-for,v-model怎樣辦?
不要焦急,這些指令只是黑魔法,用js很輕易完成。
v-if
render(){ return ( <div> {this.show?'你帥':'你丑'} </div> ) }
寫三元表達式只能寫簡樸的,那末龐雜的還得用if/else
render(){
let ifText
if(this.show){
ifText=<p>你帥</p>
}else{
ifText=<p>你丑</p>
}
return (
<div>
{ifText}
</div>
)
}
- v-for
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來當輪迴,用三元表達式來當推斷了
- v-model
近來在幫公司口試招人發明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>
事宜,class,style,ref等等怎樣綁定?
來看下面的寫法
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
,別的當用到給函數式組件綁定事宜時就有點小坑了下面說。
JSX中的函數式組件
函數式組件無狀況,無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
就好了。
現有項目哪些功用能夠用jsx替代呢?
這個實在跟最最先我例舉的例子很像。我在項目頂用它來幹掉了滿屏的v-if/v-else
因為我的營業是pad上的,需求是一套試卷有幾十道問題,請求一屏只顯現一道問題,點擊下一題顯現下一個題,思緒也比較簡樸:
- 用一個num變量示意當前正在展現的問題索引
- 每次點擊下一題按鈕時num++
- 用v-if來推斷 num===1,num===2如許來決議展現哪一個。
這一寫,模板內里很多啊,因為我們的問題每道題的模板能夠都不一樣,所以沒辦法輪迴,只能手寫悉數。之前斟酌過用動態組件來切換,然則摒棄了,因為沒有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。別的引薦人人多用函數式組件進步機能。
第一次寫文章,願望列位花時間看了的大佬以為哪一個說的不太嚴謹還需多多見諒,提出看法我都接收。