深刻探討前端組件化開發

前端組件化開發,已經有多年的歷史了,不論是服務端渲染,仍是前端SPA,都有了比較成熟的組件化開發的方案。 隨着組件化開發的普及,前端社區中貢獻了不少不錯的前端組件,都提供開箱即用的方案,使得更好的發揮組件化的優點。 前端團隊內,若是有人對前端組件化的理解不夠深刻,就不能開發出好的組件,會給項目的維護帶來更大的成本。css


這幾年,從陷入 「React、Vue 和 Angular 哪一個性能好?」的爭論,到如今的各個框架(庫)的生態愈來愈完善,討論性能差距已經沒有價值了。而國內的前端娛樂圈,最火的就是 React 和 Vue 了,而 Angular 因爲歷史緣由,在國內的佔有率確實不高。前端

隨着前端生態 jade、less、scss、typeScript 和 webpack 等工具的完善,前端的組件化開發效率已經有了很大的提高。vue

特別是像 Ant Design、Element UI、iView 這些優秀的前端組件庫的流行,更是將組件化開發發揮到了極致。開發一個前端頁面已經變得很是的高效,特別是在作管理系統的頁面,腳手架搭建、添加依賴包、配置路由、建立頁面、引入組件,很快的就能夠構建一個系統。react

若是你須要 SEO,React 和 Vue 的 SSR 框架 Next.js 和 Nuxt.js 更是提供了開箱即用的集成方案,也使開發「同構頁面系統「(Google It)變得更加簡單。webpack

下面切入正題,深刻探討下前端組件。web

什麼是前端組件化開發

首先,咱們要搞明白什麼是前端組件化開發?vue-router

你應該遇到過,將一個頁面的幾百行,甚至上千行的代碼邏輯寫在一個 js 文件中的狀況。一般這種代碼都很難讀下去,更別說要維護起來,添加新功能,移除一些老功能了,由於你不知道改動一個地方,會不會出現意想不到的 bug。vuex

這個時候,你就須要利用組件化開發,拆分功能,封裝組件,單獨維護。 //在此我向你們推薦一個前端全棧開發交流圈:619586920 突破技術瓶頸,提高思惟能力 現代化前端框架一般都是實現 MVVM 的方案,數據層(M)和 視圖層(V)相互鏈接,同時變動,使得頁面交互保持高度的一致性。redux

若是你熟悉 Java,Python,Go 等後端開發語言,你應該對 package (包)的概念很熟悉,前端的組件化在概念上與後端的 package 很類似,只不過前端的組件涉及到更多的是展現和交互方面的邏輯。固然,前端組件與後端架構的微服務概念相似,能夠理解成一個組件就是一個服務組件,只提供某個服務。後端

前端組件化開發,就是將頁面的某一部分獨立出來,將這一部分的 數據層(M)、視圖層(V)和 控制層(C)用黑盒的形式所有封裝到一個組件內,暴露出一些開箱即用的函數和屬性供外部組件調用。

一個前端組件,包含了 HTML、CSS、JavaScript,包含了組件的模板、樣式和交互等內容,基本上涵蓋了組件的全部的內容,外部只要按照組件設定的屬性、函數及事件處理等進行調用便可,徹底不用考慮組件的內部實現邏輯,對外部來講,組件是一個徹底的黑盒。

組件能夠多層封裝,經過調用多個小組件,最後封裝成一個大組件,供外部調用。好比:一個 Input 輸入框 是一個組件,一個 Select下拉選擇框 也是一個組件,能夠用 form 在這兩個組件上包裝一層,就是一個 Form 的組件

有一些比較經常使用的前端組件,像 vue-router,vuex,react-router,redux,mobx 等,都是基於 Vue 和 React 的組件,它們只專一於 路由、狀態存儲 的工做,而且把這些事情作好。

只要利用好組件化開發,開發一個頁面,就像是搭積木同樣,將各個組件拼接到一塊兒,最後融合到一塊兒,就是一個完整的系統。

組件化開發的優勢

說到底,前端的組件化開發,能夠很大程度上下降系統各個功能的耦合性,而且提升了功能內部的聚合性。這對前端工程化及下降代碼的維護來講,是有很大的好處的。

耦合性的下降,提升了系統的伸展性,下降了開發的複雜度,提高開發效率,下降開發成本。 //在此我向你們推薦一個前端全棧開發交流圈:619586920 突破技術瓶頸,提高思惟能力 組件封裝的好,加班也少了,bug 也少了,就有更多時間喝喝咖啡、打打農藥了。:)

怎麼設計一個組件

既然前端組件化開發這麼好,那要怎麼設計一個好的組件呢?

通過屢次實踐,總結了一些組件設計時的要點。

專注

要想設計一個好的組件,組件也須要專注

設計組件要遵循一個原則:一個組件只專一作一件事,且把這件事作好

一個功能若是能夠拆分紅多個功能點,那就能夠將每一個功能點封裝成一個組件,固然也不是組件的顆粒度越小越好,只要將一個組件內的功能和邏輯控制在一個可控的範圍內便可。

舉個例子。頁面上有一個 Table 列表和一個分頁控件,就能夠將 Table 封裝爲一個組件,分頁控件 封裝成一個組件,最後再把 Table組件 和 分頁組件 封裝成一個組件。Table 組件還能夠再拆分紅多個 table-column 組件,及展現邏輯等。

可配置性

一個組件,要明確它的輸入和輸出分別是什麼。

組件除了要展現默認的內容,還須要作一些動態的適配,好比:一個組件內有一段文本,一個圖片和一個按鈕。那麼字體的顏色、圖片的規則、按鈕的位置、按鈕點擊事件的處理邏輯等,都是能夠作成可配置的。

要作可配置性,最基本的方式是經過屬性向組件傳遞配置的值,而在組件初始化的聲明週期內,經過讀取屬性的值作出對應的顯示修改。還有一些方法,經過調用組件暴露出來的函數,向函數傳遞有效的值;修改全局 CSS樣式;向組件傳遞特定事件,並在組件內監聽該事件來執行函數等。

在作可配置性時,爲了讓組件更加健壯,保證組件接收到的是有效的屬性、函數接收到的是有效的參數,須要作一些校驗。

一. 屬性的值的校驗

對屬性的值進行校驗,通常要考慮如下幾個方面。

1.屬性值的類型是不是有效的。若是某個屬性要求傳遞一個數組,那麼傳遞過來的值不是數組時,就要拋出異常,並給出對應的提示。

2.屬性是不是必填的。有的屬性的值,是組件內不可缺乏的時,就要是必填的,在組件初始化時要作是否傳遞的檢查,若是沒有傳遞,則須要拋出異常,並給出相應的提示。若是屬性不是必填的,能夠設定一個默認值,當屬性沒有被設置時,就使用默認值。

得益於 React、Vue 內部實現的屬性檢查,且這些屬性檢查會在組件初始化階段默認執行,你能夠很容易的給組件設置屬性的檢查。React 中可使用 React.PropTypes 進行類型檢查設置,Vue 中只須要給組件設置 props 便可。 //在此我向你們推薦一個前端全棧開發交流圈:619586920 突破技術瓶頸,提高思惟能力 在 React 中進行類型檢查:

// title.jsx (Title組件)
  import React, { Component, PropTypes } from 'react';
 
  export default class Title extends Component {
    constructor(props) {
      super(props);
    }
 
    static propTypes = {
      title: PropTypes.string.isRequired
    }
 
    render() {
      const { title } = this.props;
 
      return (
        <p>{ title }</p>
      )
    }
  }

在 Vue 中進行類型檢查:

// title.vue (Title組件)
  <template>
    <p>{{ title }}</p>
  </template>
 
  <script>
    export default {
      props: {
        title: {
          type: String,
          required: true
        }
      }
    }
  </script>

二. 函數的參數的校驗

函數的參數校驗,只要按照傳統的方法進行校驗便可。在函數內部頂部判斷參數的值和類型,若是不知足要求,則拋出異常,並給出相應的提示。

判斷一個函數的第一個必填,且爲 String 格式

// ES6 語法
  changeTitle(title) {
    if (typeof title !== 'string') {
      throw new Error('必須傳入一個 title,才能修改 title。')
    }
    // 知足條件,能夠進行修改
    this.title = title   // vue 語法
    this.setState({      // react 語法,修改state的值
      title
    })
  } //在此我向你們推薦一個前端全棧開發交流圈:619586920 突破技術瓶頸,提高思惟能力

##生命週期

一個組件,須要明確知道在生命週期的不一樣階段作該作的事。

初始化階段,讀取屬性的值,若是須要作數據和邏輯處理的話,在這個階段進行。

屬性值變化時,若是屬性發生變化,且須要對變化後的數據進行處理的話,在這個階段進行處理。

組件銷燬階段,若是組件已經建立了一些可能會對系統產生一些反作用的東西,能夠在這個階段進行清除。好比 timeInterval、timeout 等。

若是組件在渲染的時候報錯,須要展現錯誤信息。React v16 中提供了 componentDidCatch 生命週期函數,Vue v2.5 中提供了 errorCaptured 的鉤子函數。

React 中提供了一些生命週期函數:componentWillMount,componentDidMount,componentWillReceiveProps,shouldComponentUpdate,componentWillUpdate,componentDidUpdate,render,componentWillUnmount,componentDidCatch(React v16)。

Vue 中提供了一些生命週期函數:beforeCreate,created,beforeMount,mounted,beforeUpdate,updated,beforeDestroy,destroyed,errorCapture,errorCaptured(Vue v2.5)。

每一個生命週期的具體用法,請參考官方詳細文檔。

##事件傳遞

Vue 中傳遞事件很簡單,只須要在子組件內使用 this.$emit(‘event1’) 便可向外傳遞一個事件 event1,在父組件調用該子組件時,只須要監聽 event1 事件,並給出對應事件處理邏輯便可。

Vue中事件傳遞

Vue子組件定義 child-component.vue

Vue.component('child-component', {
  methods: {
    emitEvent() {
      this.$emit('event1', 'This is a event.')
    }
  },
  mounted() {
    this.emitEvent()
  }
}) //在此我向你們推薦一個前端全棧開發交流圈:619586920 突破技術瓶頸,提高思惟能力

Vue 父組件調用子組件

<template>
  <div>
    <child-component @event1="eventHandler" />
  </div>
</template>
 
<script>
  import childComponent from './child-component'
  export default {
    components: {
      childComponent
    },
    methods: {
      eventHandler(event) {
        console.log(event)
      }
    }
  }
</script>

而在 React 中,官方沒有給出組件間的事件傳遞解決方案,這也是 React 中比較坑的一點。不過,仍是可使用其餘方式來實現。

React 中,父組件可使用 props 向子組件傳值,而子組件向父組件傳值,須要在父組件內定義函數並經過屬性傳遞給子組件,在子組件內經過調用該屬性對應的函數,傳入參數,傳遞給父組件內的函數,並在父組件的該函數中作邏輯的處理。

React 子組件定義 child-component.js

class ChildComponent extends React.Components {
  render() {
    return (
      <button onClick={ 
        () => {
          this.props.clickHandler('This is a click')
        }
      }></button>
    )
  }
}

React 父組件調用子組件

import ChildComponent from './child-component'
//在此我向你們推薦一個前端全棧開發交流圈:619586920 突破技術瓶頸,提高思惟能力 
class ParentComponent extends React.Components {
  clickHandler(message) {
    console.log(message)
  }
 
  render() {
    return (
      <child-component 
        clickHandler={ this.clickHandler.bind(this) } 
        />
    )
  }
}

前端組件化開發的實踐,是一個很長的過程,堅持並持續優化,帶動系統總體的優化。

結語

感謝您的觀看,若有不足之處,歡迎批評指正。

相關文章
相關標籤/搜索