[開源] 從web端開發到app端開發也許只有一個Flutter MVVM的距離

相關文章 使用 Flutter MVVM 開發登陸功能  html

作爲一個開發人員,選擇一款駕輕就熟的開發框架對提升生產效率和愉悅的編碼體驗是尤其重要的。近兩年我從後端開發轉向web端開發,開發重心也由以前數據層面轉變爲現今的展示層面。web端有不少出色的開發框架,Vue.js、React、Angular、Ember.js 等等都深受廣大web端開發的喜好,也都是很是不錯的選擇,挑來選去在衆多開發框架中選擇了Angular。git

 

Angular

只因此選擇Angular是由於Angular中的不少理念對一個曾經的後端開發來講並不陌生,甚至還會帶有幾分親切,Module、依賴注入、守衛、provider等等,每一項都那麼熟悉。可是除了這些,最能吸引到個人更是她優雅的數據綁定功能,Angular的數據綁定「語法」很是簡潔、明瞭,就算是新手,掃幾眼也就懂了。使用起來也很是方便,幾乎就像操做js原生對象,簡單易懂。github

Angular中的數據綁定web

<h2>{{ title }}</h2>
<div *ngIf="status === 1">hello world!</div>
複製代碼

數據綁定是Angular的核心,它能夠大大簡化開發人員對頁面dom樹控制的複雜度,使咱們能夠從本來複雜的頁面操控中解脫出來。其實不光是Angular,Vue.js、React、Ember.js 等框架也都有相似實現,業界將這種經過數據綁定驅動視圖變化的模式稱之爲 MVVM(zh.wikipedia.org/wiki/MVVM)。後端

 

Flutter

要構建一個Flutter app,大部分工做就是構建各類widget樹(UI),widget樹結構其實很像html裏的dom樹,對於web端開發人員來講並不難理解。可是上手以後就會發現,對於widget樹的操控彷彿回到了html中的getElementById時代,即便是很簡單的widget變動操做,也都須要開發人員手動管理很是多的代碼邏輯,如若碰到多個widget變動的複雜場景,擺在開發人員面前的必然是更加繁重的代碼工做量。這對於我這樣懶慣了的Angular開發來講是無法接受的!〜bash

Flutter中實現widget變動大概須要以下幾個步驟app

  1. 建立一個從StatefulWidget繼承的類
  2. 建立一個對應的 Widget 的 state 類
  3. 編寫變動邏輯,並最終使用 setState() 更新到UI

 

Flutter MVVM

既然Flutter中的widget樹和html裏的dom樹很像,而web端各大框架又都能以數據綁定來簡化對dom樹的控制操做,那麼 在Flutter中能不能像web框架那樣經過數據綁定來簡化對widget樹的操控呢? 帶着這樣的疑問,嘗試着實現了一個Flutter的MVVM。框架

 

它大概能夠幫你解決Flutter開發過程當中以下幾個問題less

  • 我有選擇困難症,我不想選擇用StatelessWidget仍是StatefulWidget。
  • 我是一個懶人,當我變動widget(UI顯示)時,我不想每次都手動 setState
  • 我有潔癖,當我開發功能時,我但願各個環節職能可以更加清晰。
  • 最重要的,我但願我能從複雜的widget樹結構控制中解脫出來。

 

什麼?說了這麼多,不如看幾行代碼?dom

在項目中使用她須要以下幾個步驟

1. 在項目中添加依賴

找到項目中 pubspec.yaml 文件, 並在 dependencies 部分加入下面內容

mvvm: ^0.1.3
複製代碼

2. 添加包引用

在代碼頁中加入

import 'package:mvvm/mvvm.dart';
複製代碼

3. 建立視圖模型(ViewModel)

視圖模型類需從 ViewModel 類繼承, 並在構造方法中使用 propertyValue 方法建立須要綁定支持的屬性

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 相似的建立屬性的方法還有 propertyAdaptivepropertyAsync 用法詳見源碼中示例

4. 建立視圖(View)

視圖類需從 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(..)等,後續還能夠擴展更多,用法詳見源碼中示例

5. 應用視圖

// run
void main() => runApp(Demo1());
複製代碼

 

web端開發的小夥伴們是否是覺的 $.watchFor(..)$.ifFor(..) 等語法能更親切一些呢?其實這些就是前邊提到的數據綁定語法的相似實現了。

在這個Flutter的MVVM實現中,咱們將原有混在一塊兒的widget樹和邏輯數據,拆分爲視圖邏輯(ViewModel)與視圖展現(View)兩部分,並經過數據綁定在二者之間創建關聯,最終用視圖邏輯(ViewModel)結合數據綁定器驅動視圖(widget樹)變化。能夠看到示例中咱們在 View 類中能更加專一的處理視圖展現,全部與視圖邏輯相關的數據操做都由 ViewModel 來管理,在職責上有着清晰的劃分界限。

 

最後

MVVM模式由來已久,在不少展示層框架中都有應用,而且深受開發人員喜好。這個Flutter的實現還很簡陋,還有不少能夠擴展的地方,但相信她能愈來愈完善,也但願她能給你帶來編碼的快樂,感謝閱讀!

她是否是能拉近你與app端開發的距離呢?快來嘗試一下吧。。

 

相關文章

相關連接

相關文章
相關標籤/搜索