Vue 2.x折騰記 - (20) JSX在業務中的具體實踐以及跟React書寫的差別化

前言

Vue JSX:讓Vue支持JSX來書寫代碼的一個開發構建依賴。css

最近已經到1.0 正式版了,稍微梳理下,就落實到具體業務去嘗試。vue

更多的姿式能夠看上面倉庫的README,這裏只說說我用到的。react

差別化

這裏僅僅列出我寫這篇文章時候腦海能回憶起來的git

React

寫JSX很天然,畢竟是自家倡導的github

  • 類名須要作classname
  • props的傳遞能夠直接 {...props}
  • 節點的傳遞,經過{props.children} 渲染
  • 支持空節點包括同級節點, <><child/><child2/></>
  • 支持花括號直接遍歷數組生成節點,{list.map(item=>(<a {...item.props}/>)}
  • 函數式組件支持很是好

Vue

可以支持部分vue獨有的特性,好比拿到computed, 指令及自定義事件;數組

其餘的寫法上和react差很少,具體一些特性以下:app

  • 類名依舊能夠直接class,其餘對象和數組的支持跟react大同小異
  • props的快速傳遞須要包括到attrs
    • 如果要快速傳遞全部父級props, {...{attrs:this.$attrs}}
      • $attrs會彙總除了class和style以外的全部props
  • 節點的傳遞能夠經過slots,好比最多見的具名<div>{this.$slots.default}</div>
    • 傳遞變量(scope-slots),父用this.$scopedSlots.default這類來傳遞一個對象
  • 同級節點不支持,必須最外層有包裹層
  • 不支持花括號內直接遍歷(我用的時候會報錯),單獨抽離出一個函數式組件
  • 函數式組件支持模板和js兩種寫法,簡單的用法基本和react一致

代碼體現

自定義事件

結合第二個栗子就能串起來函數

<script>
import png_default_scan_avatar from '@assets/cert/face_cert/scan_avatar.png';
import CertFooter from '../components/CertFooter';
export default {
  components: {
    CertFooter
  },
  name: 'face_cert',
  methods: {
    nextStep(isClick) {
      if (isClick) {
        console.log('11');
      }
      // 下一步驗證
      // this.$router.push({ name: 'cert_step4' });
    }
  },
  render() {
    const DefaultScanAvatar = () => {
      return (
        <div class="default-scan-avatar"> <div class="default-scan-avatar__desrc">請正對手機,確保光線充足</div> <img class="default-scan-avatar__img" src={png_default_scan_avatar} /> </div> ); }; return ( <div class="face-cert-page"> <DefaultScanAvatar /> <cert-footer text={'開始刷臉'} disabled={false} on-button-click={e => this.nextStep(e)} /> </div> ); } }; </script> <style lang="scss" scoped> .face-cert-page { background-color: #fff; height: 100%; .default-scan-avatar { margin-top: 54px; margin-bottom: 148px; &__desrc { font-size: 36px; color: #333; text-align: center; margin-bottom: 127px; } &__img { display: block; height: 350px; width: 350px; margin: 0 auto; } } .cert-footer { .next-wrapper { width: 626px; margin: 0 auto; } } } </style> 複製代碼

{...props}及slot的體現

<script>
export default {
  name: 'CertFooter',
  methods: {
    btnClick() {
      // 點擊了按鈕
      this.$emit('button-click', true);
    }
  },
  render() {
    return (
      <div class="cert-footer"> <div class="cert-footer__btn" onClick={this.btnClick}> <ns-button {...{ attrs: this.$attrs }} /> </div> <safe-tips /> {this.$slots.default} </div> ); } }; </script> <style lang="scss" scoped> .cert-footer { width: 100%; &__btn { width: 626px; margin: 0 auto; } } </style> 複製代碼

常規用法

<script>
export default {
  props: {
    cardinfo: {
      type: Object,
      default: function() {
        return {
          title: '銀行名字',
          type: '卡類型',
          cardnumber: ['3432', '*****', '*****', '4232']
        };
      }
    },
    defaultCard: {
      type: Boolean,
      default: false
    }
  },
  render() {
    const { cardinfo } = this.$props;

    const CardNumber = ({ props }) => {
      return props.list.map((item, index) => {
        return (
          <div class="bankcard__card--number-field" key={index}>
            {item}
          </div>
        );
      });
    };
    return (
      <div class="bankcard">
        <div class="bankcard__title">
          {cardinfo.title}
          {this.defaultCard ? (
            <div class={['bankcard__btn', 'bankcard__btn--disabled']}>默認</div>
          ) : (
            <div class={['bankcard__btn', 'bankcard__btn--setDefaultCard']} onClick={() => this.$emit('change', true)}>
              設爲默認
            </div>
          )}
        </div>
        <div class="bankcard__card--type">{cardinfo.type}</div>
        <div class="bankcard__card--number">
          <CardNumber list={cardinfo.cardnumber} />
        </div>
      </div>
    );
  }
};
</script>

<style lang="scss" scoped>
.bankcard {
  margin: 30px 0;
  background-color: #fff;
  box-shadow: 1px 1px 7px rgba(79, 123, 234, 0.31);
  width: 100%;
  border-radius: 5px;
  padding: 56px 44px;
  .bankcard__title {
    font-size: 36px;
    color: #333;
    @include flex(row, space-between, center);
  }
  .bankcard__btn {
    font-size: 14px;
    color: #333;
    padding: 5px 10px;
    border-radius: 5px;
    cursor: pointer;
    &--disabled {
      background-color: rgba(211, 208, 208, 0.66);
      color: #989393;
    }
    &--setDefaultCard {
      border: 1px solid #989393;
      &:active {
        color: #4f7aea;
        border: 1px solid #4f7aea;
      }
    }
  }
  .bankcard__card--type {
    padding-top: 11px;
    font-size: 25px;
    color: #666;
  }
  .bankcard__card--number {
    margin-top: 50px;
    @include flex(row, flex-start, center);
    cursor: pointer;
    font-size: 36px;
    .bankcard__card--number-field {
      height: 30px;
      line-height: 30px;
      &:not(:first-child) {
        margin-left: 50px;
      }
    }
  }
}
</style>

複製代碼

總結

Vue jsx 對自定義組件的v-model和複雜的指令目前是無解,直接會報錯;flex

因此遇到這種狀況,我仍是選擇template的寫法來實現對應的業務需求;ui

整體來講仍是挺實用的,一些狀況下寫起來舒服不少。

vue jsx 這個開發依賴解析還有待完善,坐等對vue自身特性更完美的支持。

目前如果基於vue cli3構建的項目能夠直接使用,無需手動去配置相關依賴。

有不對之處請留言,會及時修正,謝謝閱讀。

相關文章
相關標籤/搜索