从web端开发到app端开发也许只有一个Flutter MVVM的距离

作为一个开发人员,选择一款驾轻就熟的开发框架对提升生产效率和愉悦编码体验是尤其重要的。近两年我从后端开发转向web端开发,开发重心也由以前数据层面转变为现今的展示层面。web端有不少出色的开发框架,Vue.js、React、Angular、Ember.js 等等都深受广大web端开发的喜好,也都是很是不错的选择,挑来选去在众多开发框架中选择了Angular。html

 

Angular

只因此选择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

要构建一个Flutter app,大部分工做就是构建各类widget树(UI),widget树结构其实很像html里的dom树,对于web端开发人员来讲并不难理解。可是上手以后就会发现,对于widget树的操控仿佛回到了html中的getElementById时代,即便是很简单的widget变动操做,也都须要开发人员手动管理很是多的逻辑代码。若是碰到多个widget变动的复杂场景,摆在开发人员面前的必然是更加繁重的工做量。若是要终日以这样的方式写Flutter代码,估计我撑不过三天,这对于我这样懒惯了的Angular开发来讲是无法接受的!〜web

Flutter中实现widget变动大概须要以下几个步骤
  1. 建立一个从StatefulWidget继承的类
  2. 建立一个对应的 Widget 的 state 类
  3. 编写 widget 变动逻辑,并最终使用 setState() 更新到UI

 

Flutter MVVM

既然Flutter中的widget树和html里的dom树很像,而web端各大框架又都能以数据绑定(MVVM)来简化对dom树的控制操做,那么 在Flutter中能不能像web框架那样经过数据绑定(MVVM)来简化对widget树的操控呢? 带着这样的疑问,在我家二狗还没睡醒的清晨,尝试着实现了一个Flutter的MVVM。后端

 

它大概能够帮你解决Flutter开发过程当中以下几个问题app

  • 我有选择困难症,我不想选择用StatelessWidget仍是StatefulWidget。
  • 我是一个懒人,当我变动widget(UI显示)时,我不想每次都手动 setState
  • 我有洁癖,当我开发功能时,我但愿各个环节职能可以更加清晰。
  • 最重要的,我但愿我能从复杂的widget树结构控制中解脱出来。

 

 

什么?说了这么多,不如看几行代码?

 

在项目中使用她须要以下几个步骤框架

1. 在项目中添加依赖

找到项目中 pubspec.yaml 文件, 并在 dependencies 部分加入下面内容less

mvvm: ^0.1.3

 

2. 添加包引用

在代码页中加入dom

import 'package:mvvm/mvvm.dart';

 

3. 建立视图模型(ViewModel)

视图模型类需从 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 相似的建立属性的方法还有 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端开发的距离呢?快来尝试一下吧,期待你的答案。。

 

相关连接

相关文章
相关标签/搜索