作为一个开发人员,选择一款驾轻就熟的开发框架对提升生产效率和愉悦编码体验是尤其重要的。近两年我从后端开发转向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端开发的距离呢?快来尝试一下吧,期待你的答案。。