作爲一個開發人員,選擇一款駕輕就熟的開發框架對提升生產效率和愉悅編碼體驗是尤其重要的。近兩年我從後端開發轉向web端開發,開發重心也由以前數據層面轉變爲現今的展示層面。web端有不少出色的開發框架,Vue.js、React、Angular、Ember.js 等等都深受廣大web端開發的喜好,也都是很是不錯的選擇,挑來選去在衆多開發框架中選擇了Angular。html
只因此選擇Angular是由於Angular中的不少理念對一個曾經的後端開發來講並不陌生,甚至還會帶有幾分親切,Module、依賴注入、守衛、provider等等,每一項都那麼熟悉。可是,除了這些最能吸引到個人更是她優雅的數據綁定功能,Angular的數據綁定「語法」很是簡潔、明瞭,就算是新手,掃幾眼也就懂了。使用起來也很是方便,幾乎就像操做js原生對象,簡單易懂。git
Angular中的數據綁定
<h2>{{ title }}</h2> <div *ngIf="status === 1">hello world!</div>
數據綁定是Angular的核心,它能夠大大簡化開發人員對頁面dom樹控制的複雜度,使咱們能夠從本來複雜的頁面操控中解脫出來。其實不光是Angular,Vue.js、React、Ember.js 等框架也都有相似實現,業界將這種經過數據綁定驅動視圖變化的模式稱之爲 MVVM
(https://zh.wikipedia.org/wiki/MVVM)。github
要構建一個Flutter app,大部分工做就是構建各類widget樹(UI),widget樹結構其實很像html裏的dom樹,對於web端開發人員來講並不難理解。可是上手以後就會發現,對於widget樹的操控彷彿回到了html中的getElementById時代,即便是很簡單的widget變動操做,也都須要開發人員手動管理很是多的邏輯代碼。若是碰到多個widget變動的複雜場景,擺在開發人員面前的必然是更加繁重的工做量。若是要終日以這樣的方式寫Flutter代碼,估計我撐不過三天,這對於我這樣懶慣了的Angular開發來講是無法接受的!〜web
Flutter中實現widget變動大概須要以下幾個步驟
StatefulWidget
繼承的類Widget
的 state 類
既然Flutter中的widget樹和html裏的dom樹很像,而web端各大框架又都能以數據綁定(MVVM)來簡化對dom樹的控制操做,那麼 在Flutter中能不能像web框架那樣經過數據綁定(MVVM)來簡化對widget樹的操控呢? 帶着這樣的疑問,在我家二狗還沒睡醒的清晨,嘗試着實現了一個Flutter的MVVM。後端
它大概能夠幫你解決Flutter開發過程當中以下幾個問題app
什麼?說了這麼多,不如看幾行代碼?
在項目中使用她須要以下幾個步驟框架
找到項目中 pubspec.yaml
文件, 並在 dependencies
部分加入下面內容less
mvvm: ^0.1.3
在代碼頁中加入dom
import 'package:mvvm/mvvm.dart';
視圖模型類需從 ViewModel
類繼承, 並在構造方法中使用 propertyValue
方法建立須要綁定支持的屬性async
import 'package:mvvm/mvvm.dart'; import 'dart:async'; // define ViewModel class Demo1ViewModel extends ViewModel { Demo1ViewModel() { // define bindable propertyValue<DateTime>("time", initial: DateTime.now()); // start timer start(); } start() { Timer.periodic(const Duration(seconds: 1), (_) { // call setValue setValue<DateTime>("time", DateTime.now()); }); } }
與propertyValue
相似的建立屬性的方法還有propertyAdaptive
、propertyAsync
用法詳見源碼中示例
視圖類需從 View
類繼承, 並指定使用剛剛建立的視圖模型。重寫 Widget BuildCore(BuildContext)
方法,並在方法內使用 $
(ViewContext) 和 $Model
(ViewModel) 輔助屬性構建視圖 Widget
import 'package:mvvm/mvvm.dart'; import 'package:flutter/widgets.dart'; // define View class Demo1 extends View<Demo1ViewModel> { // call super Demo1() : super(Demo1ViewModel()); @override Widget buildCore(BuildContext context) { return Container( margin: EdgeInsets.symmetric(vertical: 100), padding: EdgeInsets.all(40), child: Column(children: [ // binding $.watchFor("time", builder: $.builder1((t) => Text( "${t.hour}:${t.minute}:${t.second}", textDirection: TextDirection.ltr))), // binding $.$ifFor("time", builder: $.builder0( () => Text("hello world!", textDirection: TextDirection.ltr)), valueHandle: (t) => t.second % 2 == 0) ])); } }
與$.watchFor(..)
相似的還有$.watch(..)
、$.if(..)
、$.cond(..)
、$.condFor(..)
、$.switch(..)
、$.switchFor(..)
等,後續還能夠擴展更多,用法詳見源碼中示例
// run void main() => runApp(Demo1());
web端開發的小夥伴們是否是覺的 $.watchFor(..)
、$.ifFor(..)
等語法能更親切一些呢?其實這些就是前邊提到的數據綁定語法的相似實現了。
在這個Flutter的MVVM實現中,咱們將原有混在一塊兒的widget樹和邏輯數據,拆分爲視圖邏輯(ViewModel)與視圖展現(View)兩部分,並經過數據綁定在二者之間創建關聯,最終用視圖邏輯(ViewModel)結合數據綁定器驅動視圖(widget樹)變化。能夠看到示例中咱們在 View
類中能更加專一的處理視圖展現,全部與視圖邏輯相關的數據操做都由 ViewModel
來管理,在職責上有着清晰的劃分界限。
MVVM模式由來已久,在不少展示層框架中都有應用,而且深受開發人員喜好。這個Flutter的實現還很簡陋,還有不少能夠擴展的地方,但相信她能愈來愈完善,也但願她能給你帶來編碼的快樂,感謝閱讀!
她是否是能拉近你與app端開發的距離呢?快來嘗試一下吧,期待你的答案。。