[toc]html
經過本文, 你能夠學到一些vue
中jsx
的語法。
vue
更加推薦使用模板開發組件,可是在一些基礎組件開發中,爲了靈活實現,不可避免須要使用一些jsx
語法,而官方對這方面的文檔特別少, 本文記錄一些本人在開發過程當中使用jsx
的經驗和思考。vue
總體上來看,因爲vue
的createElement
跟react
的createElement
有區別,致使jsx
的寫法也有區別.react
jsx本質上是createElement
的語法糖,最終會被編譯器轉爲createElement
函數.當在jsx
的標籤中使用{ ...obj }
時, obj將會編譯爲createElement
的第二個參數.git
vue
的createElement跟react的createElement函數第二個參數意義是不同的.在vue
中,第二個參數是 data對象, 而react
第二個參數是props
。因此本人將這種方式稱爲data寫法
。github
如在vue
中須要設置動態屬性時:編程
const props={ name: 'joyer', }, <my-button {...{ props:props, }}></my-button>
當不知道模板中某個vue
語法怎麼用jsx
中實現時,能夠先轉換爲createElement
的data
對象,而後使用{...data}
寫在jsx
標籤上(本文重點).api
如官方推薦原生dom
屬性的jsx
寫法:數組
<button domPropsType="submit"><button>
採用data
寫法爲:babel
<button { ...{ domProps: { type: 'submit', }, }}><button>
該方式不夠優雅,若是官方有更加優雅的語法糖,推薦使用官方推薦。若是某個語法,官方沒有案例,該方式就能夠做爲最終選擇。 而且經過這種方式,createElement
中全部的特性均可以用於jsx
的開發了。dom
官網中v-model寫法不可行。
模板中寫法爲:
<el-input v-model.trim="inputValue"/>
jsx
寫法須要爲:
<el-input vModel_trim={inputValue}/> // 或者使用 <el-input value={this.inputValue} on-input={val => this.inputValue = val.trim()}/>
模板中的寫法:
<el-tag v-for="(item, index) in content" :key="index" type="success" > {{item.name}} </el-tag>
jsx
的寫法:
{ this.content.map((item, index) = >{ return (<el-tag key={ index } type="success">{ item.name }</el-tag>); }) }
官方的寫法
<input vOn:click_stop_prevent="newTodoText" />
一些編輯器會提示語法錯誤(由於react
的jsx
不容許這樣寫),推薦使用下面的寫法
<input nativeOn-keyup={arg => arg.keyCode === 13 && this.fetch()} on-click={event => {event.stopPropagation();event.preventDefault();this.click()} }/>
修飾符須要本身在代碼中實現。或者可使用修飾符簡寫,對照官網的語法, jsx
寫法爲:
<input {...{ on: { '!click': () => this.doThisInCapturingMode, '~keyup': () => this.doThisOnce, '~!mouseover': () => this.doThisOnceInCapturingMode } }} />
事件處理都採用了箭頭函數, 跟react
同樣, 須要處理this
綁定問題,可使用bind
綁定,
`on-click={this.click.bind(this, args) }`
不能直接賦值函數on-click={this.click}
。
v-on="$listeners"
和v-bind="$attrs"
在高階組件中, 通常都會使用v-on="$listeners"
和v-bind="$attrs"
,但在官方文檔沒有說明jsx
如何實現,只有createElement
中說明了實現:
return createElement('div', { props: { ...$attrs, otherProp: value, }, on: { ...$listeners, click() { }, } },this.$slots.default])
參照data寫法
, jsx
實現爲:
const data = { props: { ...$attrs, otherProp: value, }, on: { ...$listeners, click() { }, } } <button { ...data }><button>
對於$attrs
和$listeners
能夠有更加靈活的用法。如要實現elemet-ui
中一個能夠快速佈局el-form-item
高階組件,將el-form-item
跟el-col
的結合:
render(h) { // 拆分出做用於col和form-item上的屬性 const colAttrs = {}; const itemAtts = {}; this.$attrs.forEach((attrName) => { // 這裏使用了lodash if (_.startsWith(attrName, `col-`)) { colAttrs[attrName.replace(`col-`, '')] = this.$attrs[attrName]; return; } itemAtts[attrName] = this.$attrs[attrName]; }); return (<el-col { ...{ props: this.inputAttrs, } }> </el-col>); }
該高階組件能夠傳遞兩種類型的屬性, 帶col-
開頭的屬性,做用於el-col
上面, 其餘屬性做用於el-form-item
組件上。
若是須要標籤屬性透傳,將當前組件的全部attrs
傳遞給內部組件(內部組件也用v-bind="$attrs"
),還需設置attrs
值。
如高階組件my-button
:
<el-button v-bind="$attrs" type="primary"> <slot></slot> </el-button>
高階組件high-button
:
render(h) { return (<my-button { ...{ props: this.attrs, attrs: this.$attrs, } }><my-button>); }
經過設置attrs
將high-button
接收到的全部標籤設置傳遞給my-button
中。若是不這樣作, 那麼my-button
中將接收不到任何屬性設置,由於只傳遞props
,在high-button
組件中對於沒有匹配high-button
的props
聲明的標籤屬性都會被丟棄。
默認插槽模板寫法:
<button> <slot></slot> </button>
jsx
的寫法:
<button> {this.$scopedSlots.default()} </button>
具名插槽模板寫法:
<button> <slot name="before"></slot> <slot ></slot> </button>
jsx
寫法:
let before = ''; if (this.$scopedSlots.before) { before = this.$scopedSlots.before(props => props.text); } return (<button> { before } {this.$scopedSlots.default()} </button>)
做用域插槽模板寫法:
<slot :isAdvancedPanelShow="isAdvancedPanelShow"></slot>
jsx
寫法:
{this.$scopedSlots.default({ isAdvancedPanelShow: this.isAdvancedPanelShow })}
還記得官網怎麼介紹 createElement
獲取js
的徹底編程能力嗎? 舉了一個根據不一樣的等級使用不一樣標題的案例:
Vue.component('anchored-heading', { render: function (createElement) { return createElement( 'h' + this.level, // 標籤名稱 this.$slots.default // 子節點數組 ) }, props: { level: { type: Number, required: true } } })
這個案例經過jsx
的寫法爲:
Vue.component('anchored-heading', { render: function (h) { const TagName = 'h' + this.level; return <TagName>{ this.$slots.default(this.props) }</TagName> }, props: { level: { type: Number, required: true } } })
要知道,vue
的createElement
函數的第一個參數能夠是一個 HTML 標籤名、組件選項對象,或者resolve
了上述任何一種的一個async
函數。
在實際開發中, 碰到一種場景, 有組件CompA
, CompB
, CompC
。若是是a
狀況,須要在當前組件按照CompA
, CompB
, CompC
順序展現, 若是是否是a
狀況, 則經過CompC
, CompB
, CompA
來展現。jsx
寫法爲:
render(h) { // 假設組件A是須要特殊設置一些屬性的 const compA = (<CompA name="joyer">hellow word</CompA>) const content = this.status === 'a' ? [compA, CompB, CompC] : [CompC, CompB, compA]; return (<div>{content}</div>) }
這裏末尾也能夠這樣寫:
return (<div>{...content}</div>)
但在有些編輯器會報錯,由於在react
不容許這樣寫:
Spread children are not supported in React.
能夠在babel官方提供的編輯器中jsx
嘗試代碼,不過須要記得在左邊最下角添加babel=plugin-transform-vue-jsx
插件: