學Vue,就要學會vue JSX(三)

是時候使用JSX代替createElement

接着上面的講,當咱們看到上面用createElement去實現組件,太麻煩了,別說工做效率提升了,就是那些嵌套能夠嵌套正確就很讚了,因此咱們須要用JSX去簡化整個邏輯。當年我作項目的時候就遇到過這樣的狀況,嵌套太多,本身都快搞不明白了,在崩潰的邊緣。javascript

 methods: {
   $_handleInputUser(value) {
     this.formInline.user = value
   },
   $_handleChangeRegion(value) {
     this.formInline.region = value
   },
   $_handleSubmit() {}
 },
   /**
   *將 h 做爲 createElement 的別名是 Vue 生態系統中的一個通用慣例,實際上也是 JSX 所要求的。從 Vue 的 Babel 插件的 3.4.0   *版本開始,咱們會在以 ES2015 語法聲明的含有 JSX 的任何方法和 getter 中 (不是函數或箭頭函數中) 自動注入 
   *const h = this.$createElement,這樣你就能夠去掉 (h) 參數了。對於更早版本的插件,若是 h 在當前做用域中不可用,應用會拋錯。
  */
 render(h) {
     return (
       <ElForm inline model={this.formInline} class="demo-form-inline">
         <ElFormItem label="審批人">
           <ElInput
             value={this.formInline.user}
             onInput={this.$_handleInputUser}
             placeholder="審批人"
           ></ElInput>
         </ElFormItem>
         <ElFormItem label="活動區域">
           <ElSelect
             value={this.formInline.region}
             onChange={this.$_handleChangeRegion}
             placeholder="活動區域"
           >
             <ElOption label="區域一" value="shanghai"></ElOption>
             <ElOption label="區域二" value="beijing"></ElOption>
           </ElSelect>
         </ElFormItem>
         <ElFormItem>
           <ElButton type="primarty" onClick={this.$_handleSubmit}>
             查詢
           </ElButton>
         </ElFormItem>
       </ElForm>
     )
   }

 

看了上面的代碼,你們其實會發現用JSXtemplate的語法都屬於xml的寫法,並且也比較像,但實質上仍是有許多區別的,下面我將爲你們一一分析php

沒有v-model怎麼辦,還有其餘指令能夠用嗎?

當你選擇使用JSX的時候,你就要作好和指令說拜拜的時候了,在JSX中, 你惟一可使用的指令是v-show,除此以外,其餘指令都是不可使用的,有沒有感到很慌,這就對了。不過呢,換一個角度思考,指令只是Vue在模板代碼裏面提供的語法糖,如今你已經能夠寫Js了,那些語法糖用Js均可以代替了。html

v-model

v-modelVue提供的一個語法糖,它本質上是由 value屬性(默認) + input事件(默認)組成的。因此,在JSX中,咱們即可以迴歸本質,經過傳遞value屬性並監聽input事件來實現數據的雙向綁定vue

 export default {
   data() {
     return {
       name: ''
     }
   },
   methods: {
     // 監聽 onInput 事件進行賦值操做
     $_handleInput(e) {
       this.name = e.target.value
     }
   },
   render() {
     // 傳遞 value 屬性 並監聽 onInput事件
     return <input value={this.name} onInput={this.$_handleInput}></input>
   }
 }

 

經我測試,在新版腳手架vue-cli4中,已經默認集成了對v-model的支持,你們能夠直接使用`,若是你的項目比較老,也能夠安裝插件babel-plugin-jsx-v-model`來進行支持java

一樣的,在JSX中,對於.sync也須要用屬性+事件來實現,以下代碼所示:c++

 export default {
   methods: {
     $_handleChangeVisible(value) {
       this.visible = value
     }
   },
   render() {
     return (
       <ElDialog
         title="測試.sync"
         visible={this.visible}
         on={{ 'update:visible': this.$_handleChangeVisible }}
       ></ElDialog>
     )
   }
 }

 

v-if 與 v-for

在模板代碼裏面咱們經過v-for去遍歷元素,經過v-if去判斷是否渲染元素,在jsx中,對於v-for,你可使用for循環,array.map來代替,對於v-if,可使用if語句,三元表達式等來代替vue-cli

循環遍歷列表element-ui

 const list = ['java', 'c++', 'javascript', 'c#', 'php']
 return (
   <ul>
   {list.map(item => {
    return <li>{item}</li>
   })}
   </ul>
 )

 

使用條件判斷c#

 const isGirl = false
 return isGirl ? <span>小妹,哥哥教你寫Vue</span> : <span>鳥你幹啥</span>

 

v-bind

在模板代碼中,咱們通常經過 v-bind:prop="value":prop="value"來給組件綁定屬性,在JSX裏面寫法也相似babel

 render() {
   return <input value={this.name}></input>
 }

 

v-html 與 v-text

在說v-htmlv-text以前,咱們須要先了解一下Vue中的屬性,Vue中的屬性一共分爲三種,第一種是你們寫bug時候最經常使用的props,即組件自定義的屬性;第二種是attrs,是指在父做用域裏面傳入的,但並未在子組件內定義的屬性。第三種比較特殊,是domProps,經小編不徹底測試,在Vue中,domProps主要包含三個,分別是innerHTML,textContent/innerTextvalue

  • v-html: 在模板代碼中,咱們用v-html指令來更新元素的innerHTML內容,而在JSX裏面,若是要操縱組件的innerHTML,就須要用到domProps

     export default {
       data() {
         return {
           content: '<div>這是Heo寫的一篇新的文章</div>'
         }
       },
       render() {
         // v-html 指令在JSX的寫法是 domPropsInnerHTML
         return <div domPropsInnerHTML={this.content}></div>
       }
     }

     

  • v-text: 看了上面的v-html,你是否是當即就想到了v-textJSX的寫法domPropsInnerText,是的,你沒有想錯

     export default {
       data() {
         return {
           content: '這是Heo寫的一篇新的文章的內容'
         }
       },
       render() {
         return <div domPropsInnerText={this.content}></div>
       }
     }

     

    但實際上咱們不須要使用domPropsInnerText,而是將文本做爲元素的子節點去使用便可

     <div>{this.content}</div>

實際上,對於domProps,只有innerHTML才須要使用domPropsInnerHTML的寫法,其餘使用正常寫法便可

我還要監聽事件呢

監聽事件與原生事件

當咱們開發一個組件以後,通常會經過this.$emit('change')的方式對外暴露事件,而後經過v-on:change的方式去監聽事件,很遺憾,在JSX中你沒法使用v-on指令,但你將解鎖一個新的姿式

  render() {
     return <CustomSelect onChange={this.$_handleChange}></CustomSelect>
   }

 


 
 JSX`中,經過`on` + 事件名稱的大駝峯寫法來監聽,好比事件`icon-click`,在`JSX`中寫爲`onIconClick

有時候咱們但願能夠監聽一個組件根元素上面的原生事件,這時候會用到.native修飾符,有點絕望啊,修飾符也是不能用了,但好在也有替代方案,以下代碼

  render() {
     // 監聽下拉框根元素的click事件
     return <CustomSelect nativeOnClick={this.$_handleClick}></CustomSelect>
   }

 

監聽原生事件的規則與普通事件是同樣的,只須要將前面的on替換爲nativeOn

除了上面的監聽事件的方式以外,咱們還可使用對象的方式去監聽事件

   render() {
     return (
       <ElInput
         value={this.content}
         on={{
           focus: this.$_handleFocus,
           input: this.$_handleInput
         }}
         nativeOn={{
           click: this.$_handleClick
         }}
       ></ElInput>
     )
   }

 

事件修飾符

和指令同樣,除了個別的以外,大部分的事件修飾符都沒法在JSX中使用,這時候你確定已經習慣了,確定有替代方案的。

  • .stop : 阻止事件冒泡,在JSX中使用event.stopPropagation()來代替

  • .prevent:阻止默認行爲,在JSX中使用event.preventDefault() 來代替

  • .self:只當事件是從偵聽器綁定的元素自己觸發時才觸發回調,使用下面的條件判斷進行代替

     if (event.target !== event.currentTarget){
       return
     }
  • .enterkeyCode: 在特定鍵觸發時才觸發回調

     if(event.keyCode === 13) {
       // 執行邏輯
     }

除了上面這些修飾符以外,尤大大爲了照顧咱們這羣CV仔,仍是作了一點優化的,對於.once,.capture,.passive,.capture.once,尤大大提供了前綴語法幫助咱們簡化代碼

  render() {
     return (
       <div
         on={{
           // 至關於 :click.capture
           '!click': this.$_handleClick,
           // 至關於 :input.once
           '~input': this.$_handleInput,
           // 至關於 :mousedown.passive
           '&mousedown': this.$_handleMouseDown,
           // 至關於 :mouseup.capture.once
           '~!mouseup': this.$_handleMouseUp
         }}
       ></div>
     )
   }

 

對了,還有插槽

插槽就是子組件中提供給父組件使用的一個佔位符,插槽分爲默認插槽,具名插槽和做用域插槽,下面我依次爲您帶來每種在JSX中的用法與如何去定義插槽。

默認插槽

  • 使用默認插槽

使用element-uiDialog時,彈框內容就使用了默認插槽,在JSX中使用默認插槽的用法與普通插槽的用法基本是一致的,以下代碼所示:

  render() {
     return (
       <ElDialog title="彈框標題" visible={this.visible}>
         {/*這裏就是默認插槽*/}
         <div>這裏是彈框內容</div>
       </ElDialog>
     )
   }

 

  • 自定義默認插槽

    Vue的實例this上面有一個屬性$slots,這個上面就掛載了一個這個組件內部的全部插槽,使用this.$slots.default就能夠將默認插槽加入到組件內部

     export default {
       props: {
         visible: {
           type: Boolean,
           default: false
         }
       },
       render() {
         return (
           <div class="custom-dialog" vShow={this.visible}>
             {/**經過this.$slots.default定義默認插槽*/}
             {this.$slots.default}
           </div>
         )
       }
     }

     

具名插槽

  • 使用具名插槽

    有時候咱們一個組件須要多個插槽,這時候就須要爲每個插槽起一個名字,好比element-ui的彈框能夠定義底部按鈕區的內容,就是用了名字爲footer的插槽

  render() {
     return (
       <ElDialog title="彈框標題" visible={this.visible}>
         <div>這裏是彈框內容</div>
         {/** 具名插槽 */}
         <template slot="footer">
           <ElButton>肯定</ElButton>
           <ElButton>取消</ElButton>
         </template>
       </ElDialog>
     )
   }

 

  • 自定義具名插槽

在上節自定義默認插槽時提到了$slots,對於默認插槽使用this.$slots.default,而對於具名插槽,可使用this.$slots.footer進行自定義

 render() {
     return (
       <div class="custom-dialog" vShow={this.visible}>
         {this.$slots.default}
         {/**自定義具名插槽*/}
         <div class="custom-dialog__foolter">{this.$slots.footer}</div>
       </div>
     )
   }

 

做用域插槽

  • 使用做用域插槽

    有時讓插槽內容可以訪問子組件中才有的數據是頗有用的,這時候就須要用到做用域插槽,在JSX中,由於沒有v-slot指令,因此做用域插槽的使用方式就與模板代碼裏面的方式有所不一樣了。好比在element-ui中,咱們使用el-table的時候能夠自定義表格單元格的內容,這時候就須要用到做用域插槽

     data() {
         return {
           data: [
             {
               name: 'Heo'
             }
           ]
         }
       },
       render() {
         return (
           {/**scopedSlots即做用域插槽,default爲默認插槽,若是是具名插槽,將default該爲對應插槽名稱便可*/}
           <ElTable data={this.data}>
             <ElTableColumn
               label="姓名"
               scopedSlots={{
                 default: ({ row }) => {
                   return <div style="color:red;">{row.name}</div>
                 }
               }}
             ></ElTableColumn>
           </ElTable>
         )
       }

     

  • 自定義做用域插槽

    使用做用域插槽不一樣,定義做用域插槽也與模板代碼裏面有所不一樣。加入咱們自定義了一個列表項組件,用戶但願能夠自定義列表項標題,這時候就須要將列表的數據經過做用域插槽傳出來。

     render() {
         const { data } = this
         // 獲取標題做用域插槽
         const titleSlot = this.$scopedSlots.title
         return (
           <div class="item">
             {/** 若是有標題插槽,則使用標題插槽,不然使用默認標題 */}
             {titleSlot ? titleSlot(data) : <span>{data.title}</span>}
           </div>
         )
       }

     

ok。vue JSX 的重點就已經講完了。下面一篇文章來說一下注意的地方和總結。你們以爲對你有幫助的話能夠給我點個贊哦,推薦給更多的人看。

相關文章
相關標籤/搜索