在Vue中使用JSX的正確姿式(有福利)

姿式很重要,末尾有福利html

vue-antd-ui開源了一段時間後,收到了一些反饋,尤爲是Form組件上線後,不少用戶對JSX的使用感到迷惑和不習慣,爲此專門介紹下Vue JSX的使用姿式及注意事項。vue

Form組件的自動收集校驗功能須要在JSX下使用,固然若是不須要自動收集校驗,你依然可使用templatereact

Vue 推薦在絕大多數狀況下使用template來建立你的HTML。然而在一些場景中,你真的須要 JavaScript 的徹底編程的能力,就須要使用render函數,它比 template 更接近編譯器。可是複雜的render函數書寫異常痛苦,好在官方提供了一個Babel 插件,能夠將更接近於模板語法的JSX轉譯成JavaScript。git

使用過React的同窗對JSX確定不陌生,可是Vue的JSX寫法和React的仍是有一些區別。github

React中父子之間傳遞的全部數據都是屬性,即全部數據均掛載在props下(style, className, children, value, onChange等等)。編程

Vue則否則,僅僅屬性就有三種:組件屬性props,普通html屬性attrs,Dom屬性domPropsbabel

接下來咱們經過一個示例來詳細解釋他們的區別:antd

本文代碼可在codesandbox查看運行dom

const ButtonCounter = {
  name: "button-counter",
  props: ["count"],
  methods: {
    onClick() {
      this.$emit("change", this.count + 1);
    }
  },
  render() {
    return (
      <button onClick={this.onClick}>You clicked me {this.count} times.</button>
    );
  }
};

export default {
  name: "button-counter-container",
  data() {
    return {
      count: 0
    };
  },
  methods: {
    onChange(val) {
      this.count = val;
    }
  },
  render() {
    const { count, onChange } = this;
    return (
      <div>
        <ButtonCounter
          style={{ marginTop: "10px" }}
          count={count}
          type="button"
          onChange={onChange}
        />
        <ButtonCounter
          style={{ marginTop: "10px" }}
          count={count}
          type="button"
          domPropsInnerHTML={`hello ${this.count}.`}
          onChange={onChange}
        />
      </div>
    );
  }
};
複製代碼

組件屬性props:指組件聲明的屬性,即上述示例中聲明的props: ['count']ide

普通html屬性attrs: __指組件未聲明的屬性,即上述示例中的type="button",該屬性默認會直接掛載到組件根節點的上,若是不須要掛載到根節點,可聲明 inheritAttrs: false

Dom屬性domProps:指的Dom屬性,如上述示例中的innerHTML,它會覆蓋組件內部的children, 這類屬性咱們通常不多使用到。

一樣事件屬性也分了兩種:on nativeOn

那麼問題來了,組件是如何區分各種屬性的呢?

答:正則則則...... 😶,babel-plugin-transform-vue-jsx插件會經過正則匹配的方式在編譯階段將書寫在組件上屬性進行「分類」。 onXXX的均被認爲是事件,nativeOnXXX是原生事件,domPropsXXX是Dom屬性。

class,staticClass,style,key,ref,refInFor,slot,scopedSlots這些被認爲是頂級屬性,至於咱們屬性聲明的props,以及html屬性attrs,不須要加前綴,插件會將其統一分類到attrs屬性下,而後在運行階段根據是否在props聲明來決定屬性歸屬(即屬於props仍是attrs)。

在編譯階段經過正則來區分,畢竟不是很嚴謹,那麼根據以上分類規則會有哪些問題呢?

第1、屬性分類是編譯階段進行的分類,那麼對於動態屬性如何劃分分類?

在React中全部屬性都是頂級屬性,直接使用{...props}就能夠了,可是在Vue中,你須要明確該屬性所屬的分類,如一個動態屬性value和事件change,你可使用以下方式(延展屬性)傳遞:

const dynamicProps = {
  props: {},
  on: {},
}
if(haValue) dynamicProps.props.value = value
if(hasChange) dynamicProps.on.change = onChange
<Dynamic {...dynamicProps} />
複製代碼

固然你能夠混合着使用:

<Dynamic {...dynamicProps} style="color: red"/>
複製代碼

先別高興太早,若是你沒有深刻使用過Vue JSX,不建議你使用混合方式,由於Vue會對其進行屬性合併,至於合併的規則官方也並無詳細的文檔,文檔中有一處示例,我在這再舉一個例子:

const dynamicProps2 = { on: { change: onChange2 } };
<Dynamic {...{ on: { change: onChange1 } }} {...dynamicProps2} onChange={onChange3} /> 複製代碼

上例中的onChange一、onChange二、onChange3都會觸發,而你想要的可能僅僅是onChange3。其它屬性的合併規則我就不一一列舉了,總之,我不建議你使用混合方式,除非你及你的團隊其餘小夥伴對其規則瞭解的足夠透徹。

注:理想狀況你不該該須要動態屬性,在業務開發中也比較少的使用動態屬性,但若是你嘗試開發一些通用性比較強的組件,就很難逃過動態屬性的使用。

第2、若是聲明的屬性就是onXXX怎麼處理?

首先我不建議你這麼作,但若是真的須要,你必須明確該屬性的分類,以下所示:

<div>
    <Dynamic value="獲取到value,然而並不能獲取到onXXX" onXXX="😶" /> <Dynamic {...{ props: { onXXX: "獲取到onXXX,但不建議使用" } }} /> </div> 複製代碼

第3、函數式組件的props如何處理?

關於函數式組件的相關概念可查看官方文檔,文檔中有以下一段內容:

注意:在 2.3.0 以前的版本中,若是一個函數式組件想要接受 props,則 props 選項是必須的。在 2.3.0 或以上的版本中,你能夠省略 props 選項,全部組件上的屬性都會被自動解析爲 props。

propsattrs之間存在着很微妙的關係,在普通組件中,只要明確聲明的屬性會被劃分到props分類中,剩下的均在attrs中。而對於函數式組件,只要省略了props選項,傳參時不論是否明確分類,最終context.props獲取到的都是所有屬性,若是你須要獲取明確的分類狀況,能夠在context.data下查看。 總之,在函數式組件中,推薦省略props選項。

第4、指令是否還可用?

很不幸的告訴你,大多數指令並不能在JSX中使用,對於原生指令,只有v-show是支持的。 大部分指令在JSX中可使用表達式來替代,如:條件運算符(?:)替代v-ifarray.map替代v-for 對於自定義的指令,可使用以下方式使用:

const directives = [
  { name: 'my-dir', value: 123, modifiers: { abc: true } }
]

return <div {...{ directives }}/> 複製代碼

更多Vue JSX的知識,能夠查看官方文檔。

總結:

說了那麼多,其實只要記住一點,儘可能使用明確分類的方式傳遞屬性,而不是要babel插件幫你分類及合併屬性。

最後彙報下vue-antd-ui的進度,目前組件數量48個,相較react版,還有List、TreeSelect、Metion、Carousel沒有開發,再過去的一段時間裏,咱們更多的去完善組件單元測試,測試覆蓋率83%,單測數量610個,接下來測試依然是咱們的主要工做。

質量永遠要比數量重要的多。

歡迎star,歡迎pr。

福利環節:

本人蔘與翻譯的React書籍(React Quickly,中文名:快速上手React編程)即將上市,現有樣書4本,爲了答謝支持vue-antd-ui的用戶,使用者可到該issue下按照規範(需截圖)回覆後私信我地址,郵費自理,先到先得,數量有限,敬請諒解。

相對深刻淺出系列,該書更加適合初學者入門,若是你是Vue開發者,想要快速的學習React及周邊技術(Redux、GraphQL、Jest等),我想這本書應該是不二之選。

相關文章
相關標籤/搜索