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。另外推薦你們多用函數式組件提升性能。
第一次寫文章,但願各位花時間看了的大佬以爲哪一個說的不太嚴謹還需多多包涵,提出意見我都接受。