vue jsx寫法記錄

[toc]

通過本文, 你可以學(xué)到一些vuejsx的語法。

vue更加推薦使用模板開發(fā)組件,但是在一些基礎(chǔ)組件開發(fā)中,為了獲取js的完全編程能力,不可避免需要使用一些jsx語法,而官方vue jsxvue特有的語法糖這方面的文檔特別少, 本文記錄一些本人在開發(fā)過程中使用jsx的經(jīng)驗(yàn)和思考。

整體上來看,由于vuecreateElementreactcreateElement有區(qū)別,導(dǎo)致jsx的寫法也有一些區(qū)別.但整體上還是符合react的jsx,react jsx進(jìn)階的語法。

如果需要了解vue jsx特殊寫法的原理,可以閱讀babel-plugin-transform-vue-jsx , 本文不做探討。

data寫法

jsx本質(zhì)上是createElement的語法糖,最終會被編譯器轉(zhuǎn)為createElement函數(shù).當(dāng)在jsx的標(biāo)簽中使用{ ...obj }時, obj將會編譯為createElement的第二個參數(shù).

vuecreateElement跟react的createElement函數(shù)第二個參數(shù)意義是不一樣的.在vue中,第二個參數(shù)是 data對象, 而react第二個參數(shù)是props。所以本人將這種方式稱為data寫法。

如在vue中需要設(shè)置動態(tài)屬性時:

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

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

當(dāng)不知道模板中某個vue語法怎么用jsx實(shí)現(xiàn)時,可以先轉(zhuǎn)換為createElementdata對象,然后使用{...data}寫在jsx標(biāo)簽上(本文重點(diǎn)).

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

<button domPropsType="submit"><button>

采用data寫法為:

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

該方式不夠優(yōu)雅,如果官方有更加優(yōu)雅的語法糖,推薦使用官方推薦。如果某個語法,官方?jīng)]有案例,該方式就可以作為最終選擇。 并且通過這種方式,createElement中所有的特性都可以用于jsx的開發(fā)了。

下文中所有的寫法, 都可以使用data寫法。

v-model的寫法

官網(wǎng)中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" />

一些編輯器會提示語法錯誤(因?yàn)?code>react的jsx不允許這樣寫),推薦使用下面的寫法

<input
 nativeOn-keyup={arg => arg.keyCode === 13 && this.fetch()}
 on-click={event => {event.stopPropagation();event.preventDefault();this.click()} }/>

修飾符需要自己在代碼中實(shí)現(xiàn)?;蛘呖梢允褂眯揎椃唽?,對照官網(wǎng)的語法, jsx寫法為:

<input {...{
    on: {
     '!click': () => this.doThisInCapturingMode,
    '~keyup': () => this.doThisOnce,
    '~!mouseover': () => this.doThisOnceInCapturingMode
    }
}} />

事件處理都采用了箭頭函數(shù), 跟react一樣, 需要處理this綁定問題,可以使用bind綁定,

`on-click={this.click.bind(this, args) }`

不能直接賦值函數(shù)on-click={this.click}。

高階組件中的v-on="$listeners"v-bind="$attrs"

在高階組件中, 一般都會使用v-on="$listeners"v-bind="$attrs",但在官方文檔沒有說明jsx如何實(shí)現(xiàn),只有createElement中說明了實(shí)現(xiàn):

return createElement('div', {
    props: {
      ...$attrs,
      otherProp: value,
    },
    on: {
      ...$listeners,
      click() {
      },
    }
},this.$slots.default])

參照data寫法, jsx實(shí)現(xiàn)為:

const data = {
  props: {
     ...$attrs,
     otherProp: value,
  },
  on: {
     ...$listeners,
     click() {
     },
  }
}

<button { ...data }><button>

對于$attrs$listeners可以有更加靈活的用法。如要實(shí)現(xiàn)elemet-ui中一個可以快速布局el-form-item高階組件,將el-form-itemel-col的結(jié)合:

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.colAttrs,
    }
 }> 
    <el-form-item {
        ...{
            props: this.itemAtts,
        }
    }></el-form-item>
 </el-col>);
}

該高階組件可以傳遞兩種類型的屬性, 帶col-開頭的屬性,作用于el-col上面, 其他屬性作用于el-form-item組件上。

如果需要標(biāo)簽屬性透傳,將當(dāng)前組件的所有attrs傳遞給內(nèi)部組件(內(nèi)部組件也用v-bind="$attrs"),還需設(shè)置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>);
}

通過設(shè)置attrshigh-button接收到的所有標(biāo)簽設(shè)置傳遞給my-button中。如果不這樣做, 那么my-button中將接收不到任何屬性設(shè)置,因?yàn)橹粋鬟fprops,在high-button組件中對于沒有匹配high-buttonprops聲明的標(biāo)簽屬性都會被丟棄。

slot寫法

默認(rèn)插槽模板寫法:

<button>
    <slot></slot>
</button>

jsx的寫法:

<button>
    {this.$scopedSlots.default && 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 && this.$scopedSlots.default()}
</button>)

作用域插槽模板寫法:

<slot :isAdvancedPanelShow="isAdvancedPanelShow"></slot>

jsx寫法:

{this.$scopedSlots.default && this.$scopedSlots.default({
    isAdvancedPanelShow: this.isAdvancedPanelShow
})}

所有的插槽(this.$scopedSlots[${slotName}])在調(diào)用時, 都盡量判斷以下是否為空, 因?yàn)榭赡艽嬖谑褂媒M件時, 沒有傳遞插槽內(nèi)容.

動態(tài)組件名字

還記得官網(wǎng)怎么介紹createElement獲取js的完全編程能力嗎? 舉了一個根據(jù)不同的等級使用不同標(biāo)題的案例:

Vue.component('anchored-heading', {
  render: function (createElement) {
    return createElement(
      'h' + this.level, // 標(biāo)簽名稱
      this.$slots.default // 子節(jié)點(diǎn)數(shù)組
    )
  },
  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函數(shù)的第一個參數(shù)可以是一個 HTML 標(biāo)簽名、組件選項(xiàng)對象,或者resolve了上述任何一種的一個async函數(shù)。

動態(tài)組件編排

在實(shí)際開發(fā)中, 碰到一種場景, 有組件CompA, CompB, CompC 。如果是a情況,需要在當(dāng)前組件按照CompA, CompB, CompC順序展示, 如果是不是a情況, 則通過CompC, CompB, CompA來展示。jsx寫法為:

render(h) {
 // 假設(shè)組件A是需要特殊設(shè)置一些屬性的
 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>)

但在有些編輯器會報錯,因?yàn)樵?code>react不允許這樣寫:

Spread children are not supported in React.

在babel官方編輯器中嘗試

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

添加vue-jsx插件
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容