VUE高階------使用JSX語法【轉載】

什麼是JSX?

JSX就是Javascript和XML結合的一種格式。React發明了JSX,利用HTML語法來建立虛擬DOM。當遇到<,JSX就當HTML解析,遇到{就當JavaScript解析.javascript

對於h參數

h 做爲 createElement 的別名是 Vue 生態系統中的一個通用慣例,實際上也是 JSX 所要求的。從 Vue 的 Babel 插件的 3.4.0 版本開始,咱們會在以 ES2015 語法聲明的含有 JSX 的任何方法和 getter 中 (不是函數或箭頭函數中) 自動注入 const h = this.$createElement,這樣你就能夠去掉 (h) 參數了。對於更早版本的插件,若是 h 在當前做用域中不可用,應用會拋錯。
vue

安裝

npm install @vue/babel-preset-jsx @vue/babel-helper-vue-jsx-merge-props複製代碼

修改.babelrc配置

{
  "presets": ["@vue/babel-preset-jsx"]
}複製代碼

使用render函數和jsx

// item.vue
<script>
   export default {
       name: "item",
       props:{
         id:{
           type:Number,
           default:1
         }
       },
     render(h){
         const hText=` <h${this.id}>${this.$slots.default[0].text}</h${this.id}> `
       return <div domPropsInnerHTML={hText}></div>
     }
   }
</script>複製代碼

再加上父組件來控制props的值。父組件不作對比還用傳統的template格式java

// list.vue
<template>
 <div> <h-title :id="id">Hello World</h-title> </div> </template>

<script>
 import Title from './item'

 export default {
   components: {
     "h-title":Title
   }
 }
</script>複製代碼


沒了v-if,v-for,v-model怎麼辦?

  • v-if
render(){
       return (
         <div> {this.show?'是':'否'} </div>
       )
     }複製代碼

寫三元表達式只能寫簡單的,那麼複雜的還得用if/elsegit

render(){
        let ifText
        if(this.show){
            ifText=<p></p>
        }else{
            ifText=<p></p>
        }
        return (
          <div> {ifText} </div>
        )
      }
複製代碼
  • v-for
data(){
        return{
          show:false,
          list:[1,2,3,4]
        }
      },
      render(){
        return (
          <div> {this.list.map((v)=>{ return <p>{v}</p> })} </div>
        )
      }複製代碼

在jsx中{}中間是沒辦法寫if/for語句的只能寫表達式,因此就用map來當循環,用三元表達式來當判斷了github

  • v-modelnpm

<script>
    export default {
        name: "item",
      data(){
        return{
          show:false,
          list:[1,2,3,4],
          text:'',
        }
      },
      methods:{
        input(e){
          this.text=e.target.value
        }
      },
      render(){
        return (
          <div> <input type="text" value={this.text} onInput={this.input}/> <p>{this.text}</p> </div> ) } } </script>複製代碼

怎麼用自定義組件?

很簡單,只須要導入進來,不用再在components屬性聲明瞭,直接寫在jsx中好比數組

<script>
  import HelloWolrd from './HelloWorld'
    export default {
      name: "item",
      render(){
        return (
            <HelloWolrd/>
        )
      }
    }
</script>複製代碼

事件,class,style,ref等等怎麼綁定?

來看下面的寫法bash

render (h) {
  return (
    <div // normal attributes or component props. id="foo" // DOM properties are prefixed with `domProps` domPropsInnerHTML="bar" // event listeners are prefixed with `on` or `nativeOn` onClick={this.clickHandler} nativeOnClick={this.nativeClickHandler} // other special top-level properties class={{ foo: true, bar: false }} style={{ color: 'red', fontSize: '14px' }} key="key" ref="ref" // assign the `ref` is used on elements/components with v-for refInFor slot="slot"> </div>
  )
}複製代碼

上面有個地方須要注意,當給自定義組件綁定事件時用nativeOnClick,而模板格式是用@click.native,另外當用到給函數式組件綁定事件時就有點小坑了下面說。babel

JSX中的函數式組件

函數式組件無狀態,無this實例,下面是vue文檔中提到的一段話:dom

由於函數式組件只是一個函數,因此渲染開銷也低不少。然而,對持久化實例的缺少也意味着函數式組件不會出如今 Vue devtools 的組件樹裏。

我我的理解由於沒了狀態(data),少了不少響應式的處理,還有生命週期等過程會提升速度和減小內存佔用吧?

函數式組件也能夠在模板格式中用只須要這樣

<template functional>

</template複製代碼

那jsx中的函數式組件呢?也很簡單隻需增長配置functional: true就能夠了 那函數式組件沒有了this 實例怎麼綁定事件怎麼獲取props呢?

組件須要的一切都是經過上下文傳遞,包括:

  • props : 提供全部 prop 的對象
  • children: VNode 子節點的數組
  • slots: 返回全部插槽的對象的函數
  • data:傳遞給組件的數據對象,並將這個組件做爲第二個參數傳入 createElement

上面我只列舉了部分屬性,這些是非函數式組件的東西,對於函數式組件 vue 增長了context對象,須要做爲render(h,context) 第二個參數傳入,this.$slots.default更新爲context.children props本來是直接掛在this上的,如今變爲context.props掛在了context.props上。this.data變爲了context.data

須要注意的是對於函數式組件,沒有被定義爲prop的特性不會自動添加到組件的根元素上,意思就是須要咱們手動添加到組件根元素了,看個例子吧

//父組件
 ...省略無關代碼
 render(){
      return (
        <Item data={this.data} class="large"/> ) } //Item.vue組件 export default { functional:true, name: "item", render(h,context){ return ( <div class="red" > {context.props.data} </div> ) } }複製代碼

上面代碼期待的是.large類名傳入到了Item的根元素上,可是其實沒有。咱們須要增長點東西

// Item.vue
export default {
    functional:true,
      name: "item",
      render(h,context){
        return (
          <div class="red" {...context.data}> {context.props.data} </div>
        )
      }
    }複製代碼

注意到,經過展開運算符把全部的屬性添加到了根元素上,這個context.data就是你在父組件給子組件增長的屬性,他會跟你在子元素根元素的屬性智能合併,如今.large類名就傳進來了。這個頗有用,當你在父組件給子組件綁定事件時就須要這個了。下面說一個關於綁定事件的小坑

向 createElement 經過傳入 context.data 做爲第二個參數,咱們就把 my-functional-button 上面全部的特性和事件監聽器都傳遞下去了。事實上這是很是透明的,那些事件甚至並不要求 .native 修飾符

上面是vue官網的一段話,然而我看了一遍就忽略了一句很重要的話,就是最後一句,他說不須要.native修飾符了?好先看代碼

// 父組件
 methods:{
      show(){
        alert('你好')
      }
    },
    render(){
      return (
        <Item data={this.data} onNativeClick={this.show} class="large"/> ) }複製代碼

上面代碼乍一看沒毛病,自定義組件用onNativeClick嘛,結果就是不會彈窗。唉,最後讀了幾遍剛纔vue文檔中的解釋,才發現原來函數式組件不須要.native修飾符,對於template格式確定一下就反應過來了,可是jsx的話,好吧,把上面的onNativeClick從新改成onClick就行了。

現有項目哪些功能能夠用jsx代替呢?

這個其實跟最開始我例舉的例子很像。我在項目中用它來幹掉了滿屏的v-if/v-else 因爲個人業務是pad上的,需求是一套試卷有幾十道題目,要求一屏只顯示一道題目,點擊下一題顯示下一個題,思路也比較簡單:

  1. 用一個num變量表示當前正在展現的題目索引
  2. 每次點擊下一題按鈕時num++
  3. 用v-if來判斷 num===1,num===2這樣來決定展現哪一個。

這一寫,模板裏面好多啊,因爲咱們的題目每道題的模板可能都不同,因此沒辦法循環,只能手寫所有。以前考慮過用動態組件來切換,可是放棄了,由於沒有if直觀啊。

下面看怎麼用jsx優化一下

//父組件
  export default {
    name: "list",
    data() {
      return {
       data:'我是函數式組件',
        id:1,
         tests:{
          1:<div><span>第一道題</span></div>,
          2:<div><section>第二道題</section></div>,
          3:<div><p>第三道題</p></div>
        }
      }
    },
    methods:{
      next(){
        ++this.id
      }
    },
    render(){
      return (
       <div> <Item data={this.tests[this.id]} class="large"/> <button onClick={this.next}>下一題</button> </div> ) } }複製代碼

上面每道題目的結構都不一致

//子組件,只接受數據展現,用函數式組件
<script>
  export default {
  functional:true,
    name: "item",
    render(h,context){
      return (
        <div class="red" {...context.data}> {context.props.data} </div>
      )
    }
  }
</script>複製代碼

上面沒有用任何if/else判斷就完成了功能,這裏用jsx我以爲比較合適,不知道各位大佬有什麼其餘思路?

最後

這是轉載一位大佬的博客

做者:SuperMan一路向北
來源:掘金
著做權歸做者全部。商業轉載請聯繫做者得到受權,非商業轉載請註明出處。
相關文章
相關標籤/搜索