開開森森學前端之函式式元件和JSX

_Dreams發表於2019-05-05

前言

我們接著上篇學習完render函式,下面我們來看下Vue中的函式式元件 這也是Vue進階中一個重要的知識點,下面我們一起來學習下吧(我也不是很熟?,有錯誤就請指正)

元件封裝階段

我們先封裝一個簡單的元件,叫做list

程式碼如下:

<template>
  <ul>
    <li v-for="(item, index) in list" :key="`item_${index}`"></li>
  </ul>
</template>
<script>
export default {
  name: 'List',
  props: {
    list: {
      type: Array,
      default: () => []
    }
  }
}
</script>
複製程式碼

簡單封裝後,裡面li裡面的內容我們先不管!

我們再新建一個叫做render的元件 我們把剛剛的list元件引入到render元件裡

<template>
  <div>
    <list :list="list"></list>
  </div>
</template>
<script>
import List from '../component/list'
export default {
  data () {
    return {
      list: [
        { name: lili},
        { name: Dreams}
      ]
    }
  },
  components: {
    List
  }
}
</script>
複製程式碼

接下來,我們回到list元件裡完善下li標籤裡面的內容

<li v-for="(item, index) in list" :key="`item_${index}`">
<span>{{ item.name }}</span>
</li>
複製程式碼

這樣我們就把剛剛render元件裡傳遞進來的list資料給list元件使用並且渲染出了名字,這裡我們用span標籤包裹了,那麼如果我們想更多的讓使用者個性化,比如使用者想用什麼標籤包裹就用什麼標籤包裹,怎麼做呢?

那麼這裡我們就可以使用render函式,然後讓使用者通過render函式自己去定義,來看下怎麼寫

這裡我們回到render元件,把render函式通過v-bind傳遞到list裡去

render元件的程式碼:
<template>
  <div>
    <list :list="list" :render="renderFunc"></list>
  </div>
</template>
<script>
import List from '../component/list'
export default {
  data () {
    return {
      list: [
        { name: lili},
        { name: Dreams}
      ]
    }
  },
  components: {
    List
  },
  methods:{
      renderFunc(h){
         return h('i',{
            style:{
                color:'pink'
            }
         },'???') 
      }
  }
}
</script>
複製程式碼

上面我們想使用i標籤包裹,且字型顏色為粉紅色,但這裡我們打問號的地方他的值是多少呢?怎麼來呢,因為list中他是通過v-for迴圈的, 那麼我們想知道當前迴圈的這個值是多少,那麼這裡我們就要用到一個元件叫做:函式式元件

函式式元件開始

那麼接著上面,我們先建立一個render-dom.js 程式碼如下

export default {
  functional: true,//必須這樣寫才是一個函式式元件
  props: {
    name: String,
    renderFunc: Function
  },
  render: (h, ctx) => {
    //???
  }
}
複製程式碼

那麼有人會問了,函式式元件有什麼作用?

一般而言,我們只給它傳入一些資料,它不做任何響應式的操作,不監聽傳遞給他的狀態,它也沒有生命週期,它只是一個接收引數的函式,當設定functionaltrue時,它是一個沒有狀態的元件,但是當你把他引入到其他vue元件中去用的時候,vue會把它做相關處理,上面我們寫了一個render函式,vue會用render函式裡的邏輯,把裡面返回的節點做渲染!

接著我們回到list元件,在props裡接收父元件(render元件)傳遞過來的render函式

props處新增程式碼:

render: {
      type: Function,
      default: () => {}
}
複製程式碼

接下來,我們把函式式元件再完善下

把剛剛render方法裡的邏輯完善下就是

render: (h, ctx) => {
   return ctx.props.renderFunc(h,ctx.props.name)
}
複製程式碼

返回的render其實就是使用者傳進來的那個render ctx他其實就指代當前的上下文,那麼我們就可以用ctx獲取到屬性裡的renderFunc

接下來繼續到list元件裡使用renderDom函式式元件

模板中新增:
<li v-for="(item, index) in list" :key="`item_${index}`">
    <span v-if="!render">{{ item.number }}</span>
    <render-dom v-else :render-func="render" :name="item.name"></render-dom> 
</li>
script引入:
import RenderDom from '../component/render-dom'
components: { //註冊元件
    RenderDom 
},
複製程式碼

這裡邏輯就是如果使用者傳入了render,我們就是用傳入的render渲染,否則預設span

接下來我們回到render元件裡把剛剛的render函式完善下:

renderFunc(h,name){
     return h('i',{
        style:{
            color:'pink'
        }
     },name) 
}
複製程式碼

那麼這裡的name其實就是函式式元件返回的name,所以這裡我們直接使用name

那麼這樣我們就完成了可以讓使用者自己定義這個文字該怎麼樣展現!render配合函式式元件就是這麼靈活!

那麼大家應該也發現了,render加函式式元件其實非常繁瑣!那麼有沒有什麼東西可以簡化呢? 其實是有的,那就是JSX!

JSX

JSX是React最先提出的,那麼後來Vue也做了相關支援!他的本質其實就是在js中寫html標籤和一些特定的語法,最終呢他會把jsx轉換成render函式去渲染。

接下來我們回到render元件裡把剛剛的render函式修改下:

之前template是這樣的:
<list :list="list" :render="renderFunc"></list>
之前js是這樣的:
renderFunc(h,name){
     return h('i',{
        style:{
            color:'pink'
        }
     },name) 
}
修改之後的template:
<list :list="list" :render="renderFunc" :style="{color:'red'}"></list>
修改之後的js:
renderFunc(h,name){
     return (
        <i style={{color:'red'}}>{name}</i>
     )
}
複製程式碼

這裡要注意了,在jsx中,變數要用花括號包起來!裡面是一個物件,然後又有一個花括號.因為name也是變數,所以也需要使用花括號包起來!

這樣就完成了和剛剛render函式一樣的功能!

如果我們想給i標籤繫結一個事件,我們應該怎麼繫結?

methods:{
    renderFunc(h,name){
     return (
        <i on-click={this.handleClick} style={{color:'red'}}>{name}</i>
     )
    },
    handleClick(event){
        console.log(event)
    }
}
複製程式碼

這裡還要注意,繫結事件必須是on-開頭

那麼普通的渲染標籤我們會了,那麼如果渲染一個元件呢?

渲染元件

那麼這裡假設我們這裡有一個元件CountTo(看過上上篇文章的小夥伴應該知道)元件

我們把他引入到render元件(看過上篇文章的小夥伴應該知道這個元件)中.再寫一遍!

我們這裡需要修改之前的一些程式碼:

render元件中修改後的:(函式式元件和list裡需要做一部分修改,我相信大家可以的,就不羅列相關程式碼了)

<template>
  <div>
    <list :list="list" :style="{color: 'red'}"></list>
  </div>
</template>
<script>
import List from '_c/list'
import CountTo from '_c/count-to'
export default {
  data () {
    return {
      list: [
        { number: 100 },
        { number: 45 }
      ]
    }
  },
  components: {
    List
  },
  methods: {
    renderFunc (h, number) {
      return (
        <CountTo nativeOn-click={this.handleClick} on-on-animation-end={this.handleEnd} endVal={number} style={{color: 'pink'}}></CountTo>
      )
    },
    handleClick (event) {
      // console.log(event)
    },
    handleEnd () {
      // console.log('end!')
    }
  }
}
</script>
複製程式碼

我們如果是在render或者jsx裡寫的元件是不需要進行註冊的!

那麼這裡我們也使用了JSX做了相同的事情。其實這裡還可以使用作用域插槽做同樣的事情,這篇文章我們主要講JSX和函式式元件,所以就不再舉插槽相關的程式碼哦,有興趣的可以下去自己試試!

總結

本篇文章我們一起學習了render+函式式元件,最終我們完成了之前的需求,但過程還是比較繁瑣的,結尾我們也提到了JSX的解決方案, 感興趣的小夥伴可以關注我,大家一起學習vue中比較難理解的知識點哦!

各位大佬,如果發現文中的錯誤,請指正,我會及時修改!

感謝大佬們能在百忙中能閱讀完這篇文章!

再次總結

相信大家看完這篇文章後再去看vue文件就不會覺得那麼吃力了!大家共勉!

相關文章