對比和分析幾個流行的前端框架

advence-liz發表於2019-04-11

JavaScript 發展歷程大概這麼個流程 script -> libary -> framework 一開始的關注重點是對 DOM 操作的封裝對,BOM 操作的封裝,對 JavaScript 語言的補全(陣列,字串,函式) 發展為現在關注重點變為如何快速便捷的開發健壯且易維護的APP也就是現在的 MVC or MVVM框架

knockout

幾乎是最早的前端 MVVM 框,MVVM最早於 2005 年被微軟的 WPF 和 Silverlight 的架構師 John Gossman 提出,並且應用在微軟的軟體開發中

微軟出品,使用函式偷龍轉鳳,最短編輯長度演算法實現 DOM 的同步,相容 IE6,實現高超,但原始碼極其難讀(引用自司徒正美,說道原始碼難讀其實也還好我當年也就讀了半年囧)

基本的繫結寫法如下

<div data-bind="visible: myValues().length > 0">
    You will see this message only when 'myValues' has at least one member.
</div>
Today's message is: <span data-bind="text: myMessage"></span>
<div>
    You've clicked <span data-bind="text: numberOfClicks"></span> times
    <button data-bind="click: incrementClickCounter">Click me</button>
</div>

var viewModel = {
  myValues: ko.observableArray([]), // Initially empty, so message hidden
  myMessage: ko.observable(), // Initially blank
  numberOfClicks: ko.observable(0),
  incrementClickCounter: function() {
    var previousCount = this.numberOfClicks()
    this.numberOfClicks(previousCount + 1)
  }
}
viewModel.myValues.push("some value") // Now visible
viewModel.myMessage("Hello, world!") // Text appears
複製程式碼

binding&component (自定義元件)

;<like-widget params="value: userRating" />

ko.components.register("like-widget", {
  viewModel: function(params) {
    // Data: value is either null, 'like', or 'dislike'
    this.chosenValue = params.value

    // Behaviors
    this.like = function() {
      this.chosenValue("like")
    }.bind(this)
    this.dislike = function() {
      this.chosenValue("dislike")
    }.bind(this)
  },
  template: '<div class="like-or-dislike" data-bind="visible: !chosenValue()">\
            <button data-bind="click: like">Like it</button>\
            <button data-bind="click: dislike">Dislike it</button>\
        </div>\
        <div class="result" data-bind="visible: chosenValue">\
            You <strong data-bind="text: chosenValue"></strong> it\
        </div>'
})
複製程式碼
;<div data-bind="yourBindingName: someValue"> </div>

ko.bindingHandlers.yourBindingName = {
  init: function(
    element,
    valueAccessor,
    allBindings,
    viewModel,
    bindingContext
  ) {
    // This will be called when the binding is first applied to an element
    // Set up any initial state, event handlers, etc. here
  },
  update: function(
    element,
    valueAccessor,
    allBindings,
    viewModel,
    bindingContext
  ) {
    // This will be called once when the binding is first applied to an element,
    // and again whenever any observables/computeds that are accessed change
    // Update the DOM element based on the supplied values here.
  }
}
複製程式碼

angular

MVC至少設計的時候是這樣的,不過隨著大家廣泛使用的更多人都傾向認為它是MVVM,後來官方乾脆寫成MVW whatever 你說是啥就是啥

google 出品,思想來自 flex,IoC, 髒檢測,自定義標籤,受限於繫結數量,一般不能超過 2000 個,入門容易上手難,大量避不開的概念(引用自司徒正

基本的繫結寫法

<div ng-controller="BoxCtrl">
    <div style="width: 100px; height: 100px; background-color: red;"
         ng-click="click()"></div>
    <p>{{ w }} x {{ h }}</p>
    <p>W: <input type="text" ng-model="w" /></p>
    <p>H: <input type="text" ng-model="h" /></p>
  </div>

複製程式碼
angular
  .module("app", [], angular.noop)
  .controller("BoxCtrl", function($scope, $element) {
    //$element 就是一個 jQuery 物件
    var e = $element.children().eq(0)
    $scope.w = e.width()
    $scope.h = e.height()

    $scope.click = function() {
      $scope.w = parseInt($scope.w) + 10
      $scope.h = parseInt($scope.h) + 10
    }

    $scope.$watch("w", function(to, from) {
      e.width(to)
    })

    $scope.$watch("h", function(to, from) {
      e.height(to)
    })
  })
複製程式碼

directive (自定義元件)

指令(directive)在Angular 官方文件中稱為HTML的DSL的擴充套件,指令可以分為兩種型別元件型指令(Component) & 裝飾型指令(Decorator)

  • 元件型指令主要是為了將來複雜而龐大的View分離,使頁面的View具有更強的可讀性和維護性,實現“高內聚低耦合”和“分離關注點”的有效手段。並且元件型指令不見得一定要程式碼複用 (複用是個大坑尤其在複雜而龐大的結構中為了複用而複用往往帶來的就是耦合) ,更多時候是讓頁面結構語義化,當你所做的一切都按照從優的設計原則時,當有需求變更的時候常常會意想不到容易擴充套件,這時興許你該感謝深思熟慮的自己。

  • 裝飾型指令就是給DOM元素新增修飾常見的有對DOM attr的操作,對樣式的操作,對事件的操作,對一些互動的操作(其實列的那些很有規律,就是DOM本該有的行為Angular封裝方式

<p color="red">有顏色的文字</p>
<color color="red">有顏色的文字</color>

var app = angular.module("Demo", [], angular.noop)

app.directive("color", function() {
  var link = function($scope, $element, $attrs) {
    $element.css("color", $attrs.color)
  }
  return { link: link, restrict: "AE" }
})
複製程式碼
<hello></hello>

angular.module("app",[]).directive("hello",function(){
                return{
                 restrict:'EA',
                 template:"<div><h3>hello world</h3></div>"
                };
            })
複製程式碼

vue

vue 形式上看起來就是借鑑上倆個框架的思想化為己用,並將其整合簡化,是一個非常易上手的作品(vue viewmodel 計算屬性看起來就是借鑑了knockout,元件的的封裝和繫結語法看起來就是借鑑了angular)

使用 Object.defineProperties 實現同步,實現精緻,但功能薄弱(引用自司徒正美關於功能薄弱如尤雨溪最開始的構想 Vue.js 是一個用來開發 web 介面的前端庫那確實功能不強,但是隨著 vue 生態的發展現在也是很強大的)

基本的繫結寫法

<div id="app">
  <div v-bind:class="{ active: isActive }"></div>
  <div v-bind:style="{ color: activeColor, fontSize: fontSize + 'px' }"></div>
   <input v-model="newTodo" v-on:keyup.enter="addTodo">
  <ul>
    <li v-for="todo in todos">
      <span>{{ todo.text }}</span>
      <button v-on:click="removeTodo($index)">X</button>
    </li>
  </ul>
</div>
複製程式碼
new Vue({
  el: "#app",
  data: {
    newTodo: "",
    todos: [{ text: "Add some todos" }]
  },
  methods: {
    addTodo: function() {
      var text = this.newTodo.trim()
      if (text) {
        this.todos.push({ text: text })
        this.newTodo = ""
      }
    },
    removeTodo: function(index) {
      this.todos.splice(index, 1)
    }
  }
})
複製程式碼

元件與指令(自定義元件)

;<div id="components-demo">
  <button-counter />
</div>

// Define a new component called button-counter
Vue.component("button-counter", {
  data: function() {
    return {
      count: 0
    }
  },
  template:
    '<button v-on:click="count++">You clicked me {{ count }} times.</button>'
})
複製程式碼
<input v-focus>

Vue.directive('focus', {
  // 當被繫結的元素插入到 DOM 中時……
  inserted: function (el) {
    // 聚焦元素
    el.focus()
  }
})
複製程式碼

react

ko,angular,vue 或多或少都跟 DOM Tree 有著曖昧的關係

react完全就是開啟的新世界的大門,React 以 JavaScript 為中心,一個 JSX element 就是一個 JavaScript 物件,你能對 “物件”做什麼,你就可以對 JSX 做什麼

  • react in patternA free book that talks about design patterns/techniques used while developing with React.

基本的繫結寫法和自定義元件

class Calculator extends React.Component {
  constructor(props) {
    super(props);
    this.handleChange = this.handleChange.bind(this);
    this.state = {temperature: ''};
  }

  handleChange(e) {
    this.setState({temperature: e.target.value});
  }

  render() {
    const temperature = this.state.temperature;
    return (
      <fieldset>
        <legend>Enter temperature in Celsius:</legend>
        <input
          value={temperature}
          onChange={this.handleChange} />

        <BoilingVerdict
          celsius={parseFloat(temperature)} />

      </fieldset>
    );
  }
}
複製程式碼

綜合對比

框架 相容性 DOMtree 雙向繫結 上手難度&學習曲線 元件化 綜述
ko ie6+ 曖昧 支援 依賴收集 上手容易學習曲線感覺不是那麼友好 不是很理想基本靠自覺 通過巧妙利用函式構建觀察者模式實現雙向繫結,開創先河瀏覽器相容性上無可匹敵
vue ie9+ 1.x 版本還是曖昧的,2.x之後支援虛擬dom基本就不愛了 支援 依賴收集 上手容易 學習曲線應該是最友好的 元件化比較方便 得易於 ECMASCRIPT 新的 API Object.defineProperties,更便捷高效的實現雙向繫結,使用是最容易的上手的
angular ie8+ 曖昧 支援 髒檢測 上手容易 學習曲線最陡峭深入難概念太多 元件化能力也還可以 跟其他幾個相比只有 angular 才能說是真正的框架,你想要的功能應有盡有,就連模組化都自己處理了,react 和 vue 如何不加上自己生態系統只是一個優秀前端介面庫
react ie9+ 分手了 不支援 上手容易 學習曲線這個我覺得不太好描述上限也高下限也低完全看你對程式語言的理解 元件化能力強,大大的提高的元件化的下限,你寫的程式碼只能是不理想的元件化或者元件化的程式碼 思維上的革命以JavaScript為核心,有最高的自由度和發揮空間

現在的前端框架一般具有的特徵

  • 操作 DOM 屬性 如:class ,disabled
  • 操作表單素 checkbox radio input ...
  • 列表渲染
  • 對瀏覽器事件處理機制的一個封裝,自動處理一些相容問題
  • 上下文管理一般都會一定程度依賴 DOM 結構(得到一種父子關係進而提供一種父子間的通訊方式),提供一個作用域劃分方式
  • 元件化 元件間通訊
  • 生命週期

相關文章