vue的jsx寫法記錄

[toc]html

經過本文, 你能夠學到一些 vuejsx的語法。

vue更加推薦使用模板開發組件,可是在一些基礎組件開發中,爲了靈活實現,不可避免須要使用一些jsx語法,而官方對這方面的文檔特別少, 本文記錄一些本人在開發過程當中使用jsx的經驗和思考。vue

總體上來看,因爲vuecreateElementreactcreateElement有區別,致使jsx的寫法也有區別.react

data寫法

jsx本質上是createElement的語法糖,最終會被編譯器轉爲createElement函數.當在jsx的標籤中使用{ ...obj }時, obj將會編譯爲createElement的第二個參數.git

vuecreateElement跟react的createElement函數第二個參數意義是不同的.在vue中,第二個參數是 data對象, 而react第二個參數是props。因此本人將這種方式稱爲data寫法github

如在vue中須要設置動態屬性時:編程

const props={
  name: 'joyer',
},

<my-button {...{
  props:props,
}}></my-button>

當不知道模板中某個vue語法怎麼用jsx中實現時,能夠先轉換爲createElementdata對象,而後使用{...data}寫在jsx標籤上(本文重點).api

如官方推薦原生dom屬性的jsx寫法:數組

<button domPropsType="submit"><button>

採用data寫法爲:babel

<button { ...{
  domProps: {
    type: 'submit',
  }, 
}}><button>

該方式不夠優雅,若是官方有更加優雅的語法糖,推薦使用官方推薦。若是某個語法,官方沒有案例,該方式就能夠做爲最終選擇。 而且經過這種方式,createElement中全部的特性均可以用於jsx的開發了。dom

v-model的寫法

官網中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()}/>

v-for

模板中的寫法:

<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" />

一些編輯器會提示語法錯誤(由於reactjsx不容許這樣寫),推薦使用下面的寫法

<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-itemel-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>);
}

經過設置attrshigh-button接收到的全部標籤設置傳遞給my-button中。若是不這樣作, 那麼my-button中將接收不到任何屬性設置,由於只傳遞props,在high-button組件中對於沒有匹配high-buttonprops聲明的標籤屬性都會被丟棄。

slot寫法

默認插槽模板寫法:

<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
    }
  }
})

要知道,vuecreateElement函數的第一個參數能夠是一個 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官方編輯器中嘗試

能夠在babel官方提供的編輯器jsx嘗試代碼,不過須要記得在左邊最下角添加babel=plugin-transform-vue-jsx插件:

添加vue-jsx插件

相關文章
相關標籤/搜索