JS開發(fā)者值得一看的Flutter入門

本文將從一個Javascript開發(fā)者角度介紹:Flutter的初衷印蔗,它與React Native的區(qū)別酵紫,還會通過對比JavaScript來介紹Dart語言特性告嘲。如果你需要了解如何搭建環(huán)境,請參考官網(wǎng) => 開始使用Flutter

What is Flutter?

英 [?fl?t?(r)] , v. 飄動奖地;(鳥或昆蟲)鼓翼橄唬;飛來飛去;n. 振動参歹;

Flutter是 Google 于 2015 年 5 月 3 日推出的免費(fèi)開源跨平臺開發(fā)框架仰楚,可以快速開發(fā) Android 和 iOS 應(yīng)用,同時也將是未來的 Google Fuchsia OS 下開發(fā)應(yīng)用的主要技術(shù)框架犬庇。未來的 Flutter 的開發(fā)不僅僅局限于移動跨平臺游桩,目前已經(jīng)支持 Web 開發(fā)剃根、后端開發(fā)黔姜、PC 桌面應(yīng)用開發(fā)(內(nèi)測中)沃暗、嵌入式開發(fā)......

有些同學(xué)說檩禾,“React Native我都沒用過因妙,F(xiàn)lutter我也不想去掌握”.
一開始我學(xué)習(xí)React Naive的時候也有這個疑慮钠导,轉(zhuǎn)眼現(xiàn)在已經(jīng)開發(fā)了兩年的React Native項(xiàng)目了÷运現(xiàn)在學(xué)習(xí)Flutter沒有那么大的抵觸,因?yàn)檎莆樟艘粋€跨平臺客戶端開發(fā)解決方案后再學(xué)習(xí)另外一個赤赊,你就會知道哪些是核心知識點(diǎn),學(xué)起來更有目的性煞赢,學(xué)習(xí)效率會更高抛计;就好比你掌握Vue之后去學(xué)習(xí)React一樣.

學(xué)習(xí)一門技術(shù)的目的不應(yīng)該只是會用,而是理解它的原理和特性照筑,掌握其精髓方可舉一反三吹截。不要說“什么Angular,React凝危,老夫只用jQuery!”, 比如掌握了數(shù)據(jù)驅(qū)動視圖的那種單一數(shù)據(jù)流轉(zhuǎn)的設(shè)計(jì)思路波俄,你也可以通過約定再jQuery或任何框架里面應(yīng)用。

比如學(xué)習(xí)Flutter不僅是了解如何用它開發(fā)一個app, 而是要獲得一個跨平臺UI解決方案的原理和經(jīng)驗(yàn).

Flutter vs React Native

Flutter說的跨平臺那些優(yōu)點(diǎn)React Native也有蛾默,為什么不用React Native懦铺?

技術(shù) 性能&體驗(yàn) 開發(fā)成本 學(xué)習(xí)成本 熱更新
Flutter 接近原生 single 新語言Dart “不能”
React Native 一般 single 對js開發(fā)者友好 可以
web single JavaScript 可以
Native Double(Android & iOS) java & OC 不能

當(dāng)年React Native就是為了解決web性能差,Native開發(fā)成本大的問題支鸡,看Flutter也是這樣的目的冬念,那么我們?yōu)槭裁捶且獙W(xué)習(xí)新的語言呢趁窃?

主要還是因?yàn)镕lutter的性能要優(yōu)于React Native,我們從實(shí)現(xiàn)原理看下二者的區(qū)別.

在 Android 和 iOS 上急前,默認(rèn)情況下 Flutter 和 React Native 都需要一個原生平臺的
Activity / ViewController 支持醒陆,且在原生層面屬于一個載體頁(單頁面應(yīng)用), 而它們之間最大的不同點(diǎn)其實(shí)在于 UI 構(gòu)建.

React Native 是一套 UI 框架裆针,默認(rèn)情況下 React Native 會在 Activity 下加載 JS 文件刨摩,然后運(yùn)行在 JavaScriptCore 中解析 Bundle 文件布局,最終堆疊出一系列的原生控件進(jìn)行渲染世吨。
簡單來說就是 通過寫 JS 代碼配置頁面布局码邻,然后 React Native 最終會解析渲染成原生控件,如 <View> 標(biāo)簽對應(yīng) ViewGroup/UIView另假,<Image> 標(biāo)簽對應(yīng) ImageView/UIImageView 等像屋。

Flutter 中絕大部分的 Widget 都與平臺無關(guān), 開發(fā)者基于 Framework 開發(fā) App 边篮,而 Framework 運(yùn)行在 Engine 之上己莺,由 Engine 進(jìn)行適配和跨平臺支持,F(xiàn)lutter 甚至不使用移動平臺的原生控件戈轿, 而是使用自己 Engine 來繪制 Widget (Flutter的顯示單元)凌受,而 Dart 代碼都是通過 AOT 編譯為平臺的原生代碼,所以 Flutter 可以 直接與平臺通信思杯,不需要JS引擎的橋接胜蛉。同時 Flutter 唯一要求系統(tǒng)提供的是 canvas,以實(shí)現(xiàn)UI的繪制色乾。

所以可以得出誊册,F(xiàn)lutter渲染UI的方式效率高,沒有與Native原生組件通信過程暖璧,可參考下面的對比圖:


RN和Flutter的UI渲染流程對比圖(原創(chuàng))

組件(Widget)是Flutter應(yīng)用程序用戶界面的基本構(gòu)建塊案怯。不僅按鈕、輸入框澎办、卡片嘲碱、列表這些內(nèi)容可作為Widget,甚至將布局方式局蚀、動畫處理都視為Widget麦锯。所以Flutter具有一致的統(tǒng)一對象模型:Widget。

如果Widget需要根據(jù)用戶交互或其他因素進(jìn)行更改琅绅,則該Widget是有狀態(tài)的扶欣。例如,如果一個Widget的計(jì)數(shù)器在用戶點(diǎn)擊一個按鈕時遞增,那么該計(jì)數(shù)器的值就是該Widget的狀態(tài)宵蛀。當(dāng)該值發(fā)生變化時昆著,需要重新構(gòu)建Widget以更新UI。

Flutter中的狀態(tài)和React中的狀態(tài)概念一致术陶。React的核心思想是組件化的思想凑懂,應(yīng)用由組件搭建而成,而組件中最重要的概念是State(狀態(tài)),State是一個組件的UI數(shù)據(jù)模型梧宫,是組件渲染時的數(shù)據(jù)依據(jù)接谨。Flutter程序的運(yùn)行可以認(rèn)為是一個巨大的狀態(tài)機(jī),用戶的操作塘匣、請求API和系統(tǒng)事件的觸發(fā)都是推動狀態(tài)機(jī)運(yùn)行的觸發(fā)點(diǎn)脓豪,觸發(fā)點(diǎn)通過調(diào)用setState方法推動狀態(tài)機(jī)進(jìn)行響應(yīng)。

Widget狀態(tài)的生命周期(原創(chuàng))

另外忌卤,F(xiàn)lutter開發(fā)中扫夜,大部分樣式跟React Native一樣是駝峰命名的屬性。

TextStyle bold24Roboto = TextStyle(
  color: Colors.white,
  fontSize: 24,
  fontWeight: FontWeight.w900,
);

其他詳細(xì)的請參考官網(wǎng), 在此不展開詳述了驰徊。

Dart 和 JavaScript

Dart 語言特性介紹沒有比官網(wǎng)跟標(biāo)準(zhǔn)的了:Dart 開發(fā)語言概述笤闯,在此,作為一個javascript開發(fā)者棍厂,從javascript語言使用習(xí)慣上颗味,挑幾個相對有趣的區(qū)別聊聊。

假設(shè)你已經(jīng)粗略看過一遍Dart的語言概述了牺弹,那么你會了解到Dart是需要編譯的浦马。編譯的過程中會有一些限制;比如张漂,語句末尾的';'是必須的晶默,否則在編譯過程會報(bào)錯。這不同于js的語法校驗(yàn)鹃锈,比如eslint, tslint等是可選的荤胁,而Dart不是。

類型

盡管 Dart 是強(qiáng)類型語言屎债,但是在聲明變量時指定類型是可選的,因?yàn)?Dart 可以進(jìn)行類型推斷垢油。
Dart 可以描述類型的關(guān)鍵字有:int, double, bool, String, var, void, dynamic或類名盆驹。
如果像js一樣不適應(yīng)不初始化一個變量的類型, Dart會在編譯過程報(bào)錯.

name = 'Mike'; // js允許,但Dart報(bào)錯

不確定的類型可以使用var, 但var實(shí)際上是編譯期拋給開發(fā)者使用的“語法糖”滩愁,一旦被編譯躯喇,就會編譯到對應(yīng)的類型.

var name = 'Mike'; 
// 等同于 String name = 'Mike';

而有沒有編譯器不能確定類型的變量呢?比如第三方庫的,網(wǎng)絡(luò)接口返回的變量廉丽,這樣不確定的變量可以使用dynamic關(guān)鍵字來顯示的描述這種情況倦微。

import 'abc';

dynamic x = abc();

而dynamic被編譯后,實(shí)際是一個 object類型正压,
只不過編譯器會對dynamic類型進(jìn)行特殊處理欣福,
讓它在編譯期間不進(jìn)行任何的類型檢查,而是將類型檢查放到了運(yùn)行期焦履。

筆者認(rèn)為dynamic是真不知道什么類型拓劝;var是懶得去聲明它是什么類型,交給編譯器嘉裤,但也有可能是編譯期不能確定郑临,而在運(yùn)行期才能確定的變量類型。

另外屑宠,未賦值的變量在js中對應(yīng)值是undefined, 而在Dart中厢洞,所有未初始化的變量的初始值為null。這是因?yàn)镈art將所有值都視為對象典奉。但是如果不用var, dynamic定義時, 不賦值會在編譯時報(bào)錯躺翻。

final x; // Error: The final variable must be initialized.

const x;  // Error: The const variable must be initialized.

void x; // 不報(bào)錯
print(x); // Error: This expression has type 'void' and can't be used.

var x; // 不報(bào)錯
print(x); // null

在 JavaScript 中,1 或者任何非空對象都相當(dāng)于 true秋柄。

// JavaScript
var myNull = null;
if (!myNull) {
  console.log('null is treated as false');
}
var zero = 0;
if (!zero) {
  console.log('0 is treated as false');
}

在 Dart 中获枝,只有布爾類型值 true 才是 true。

// Dart
var myNull = null;
if (myNull == null) {
  print('use "== null" to check null');
}
var zero = 0;
if (zero == 0) {
  print('use "== 0" to check zero');
}

常量

如果你不想更改一個變量骇笔,可以使用關(guān)鍵字 final 或者 const 修飾.其中final跟js中的const用法相同省店,運(yùn)行時只能賦值一次,不能被更改笨触,準(zhǔn)確說是運(yùn)行時常量懦傍。
const在Dart中是編譯時常量,必須在編譯時確定其值, const 變量同時也是 final 的.

 const PI = 3.1415926;
 const y = PI * 3; // 編譯通過

 const x = Random().nextInt(10); // 編譯報(bào)錯
 
 final z =  Random().nextInt(10); // 編譯通過
  • final: adj. 最終的芦劣;不可更改的;
  • constant: adj. 不變的粗俱;恒定的;

函數(shù)

定義方式虚吟,沒有function關(guān)鍵字寸认。雖然高效 Dart 指南建議在公開的 API 上定義返回類型,不過即便不定義串慰,該函數(shù)也依然有效偏塞。
但是如果聲明void, 就在編譯過程中做引用校驗(yàn)。

fooo1(){}
print(fooo1()); // 輸出null

void fooo2(){}
print(fooo2()); // 編譯時報(bào)錯邦鲫, Error: This expression has type 'void' and can't be used.

參數(shù)的定義方式跟js相同灸叼,也可以用{}來定義命名參數(shù)神汹,另外Dart支持使用[]定義可選參數(shù).

void foo2(String name, [String sex]){
  print(name);
}
foo2(); // 編譯報(bào)錯,提示缺少參數(shù)name

箭頭函數(shù), 閉包的用法跟js相同古今。

斷言 assert

js沒有斷言, 斷言有什么用屁魏?
在開發(fā)過程中,可以在條件表達(dá)式為 false 時使用 - assert(條件, 可選信息); - 語句來打斷代碼的執(zhí)行捉腥。

// 確保變量值小于 100氓拼。
assert(number < 100, '變量值不符合條件'); // 如果number 小于100,會拋出異常

assert的作用有些類似if/else條件語句但狭,但是assert只在開發(fā)環(huán)境披诗,生產(chǎn)環(huán)境不會執(zhí)行斷言。
斷言可以用于比較重要的調(diào)試代碼立磁,這樣不用像條件語句那樣的調(diào)試代碼必須要在在運(yùn)行前刪除呈队。
其實(shí)js中也有斷言:console.assert,在不符合條件時打印:

console.assert(a === 3, "a 的值不是3唱歧!");

接口宪摧、抽象類

interface已經(jīng)被Dart從關(guān)鍵字列表中移除, 意味著Dart沒有接口概念,如果你希望創(chuàng)建一個接口颅崩,可以使用抽象類. 抽象類不能被實(shí)例化几于,只能被繼承, 從而像接口一樣約束了子類。

abstract class PopCompnent{
  show(){
    print('顯示彈窗');
  }
}

繼承沿后、Mixin

Dart使用extends關(guān)鍵字繼承類沿彭,只支持單繼承,如果需要多繼承尖滚,可以使用Mixin方式喉刘。
Mixin 是一種在多重繼承中復(fù)用某個類中代碼的方法模式。Dart使用 with 關(guān)鍵字并在其后跟上 Mixin 類的名字來使用 Mixin 模式:

class Programer extends Person with Employee {
  // ···
}

定義一個類繼承自 Object 并且不為該類定義構(gòu)造函數(shù)漆弄,這個類就是 Mixin 類睦裳,除非你想讓該類與普通的類一樣可以被正常地使用,否則可以使用關(guān)鍵字 mixin 替代 class 讓其成為一個單純的 Mixin 類:

mixin Employee {
  int salary = 999999;
  //...
}

可以使用關(guān)鍵字 on 來指定哪些類可以使用該 Mixin 類撼唾,比如有 Mixin 類 A廉邑,但是 A 只能被 B 類使用,則可以這樣定義 A:

mixin CompanyEmployee on Employee {
  // ···
}

包管理

Dart 生態(tài)系統(tǒng)使用packages來管理軟件倒谷,使用 Pub 包管理工具 來獲取 Dart 包蛛蒙。在 Pub 上,可以找到公開可用的包渤愁。相當(dāng)于javascript的npm.
pubspec 是一個名為 pubspec.yaml 的文件宇驾,文件位于應(yīng)用的根路徑;它相當(dāng)于npm中的package.json.

異步

async 和 await 關(guān)鍵字用于同步的寫法實(shí)現(xiàn)異步編程猴伶。js中,async寫在function前,Dart中他挎,async寫在方法體{}前.

函數(shù)體中使用await的話筝尾,函數(shù)必須用async修飾,否則js, dart都會報(bào)錯办桨。反之筹淫,如果函數(shù)已經(jīng)用async修飾,不管有無await, js也會返回promise對象呢撞;而Dart也會返回Future對象.

Future被用來表示在未來才能知道結(jié)果的類损姜,和js中的Promise類似。dart提供了對異步的支持殊霞,核心類包括Future和Stream摧阅,都位于dart:async包下.

import 'dart:async';

Future<String> fetchMessage() async => 'hello world';

fetchMessage().then((value){
    print(value);
},onError: (e) {
    print("onError: \$e");
}).catchError((e){
    print("catchError: \$e");
});

Dart相比JavaScript更像TypesScript,其他特性在此就不展開多說了绷蹲。
如果你對上一部分中Dart這些特性有所好奇棒卷,想自己動手試試的話,可以使用在線運(yùn)行Dart:dartpad, dartpad國內(nèi)版.

參考

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末比规,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子拦英,更是在濱河造成了極大的恐慌蜒什,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,816評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件疤估,死亡現(xiàn)場離奇詭異灾常,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)做裙,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,729評論 3 385
  • 文/潘曉璐 我一進(jìn)店門岗憋,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人锚贱,你說我怎么就攤上這事仔戈。” “怎么了拧廊?”我有些...
    開封第一講書人閱讀 158,300評論 0 348
  • 文/不壞的土叔 我叫張陵监徘,是天一觀的道長。 經(jīng)常有香客問我吧碾,道長凰盔,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,780評論 1 285
  • 正文 為了忘掉前任倦春,我火速辦了婚禮户敬,結(jié)果婚禮上落剪,老公的妹妹穿的比我還像新娘。我一直安慰自己尿庐,他們只是感情好忠怖,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,890評論 6 385
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著抄瑟,像睡著了一般凡泣。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上皮假,一...
    開封第一講書人閱讀 50,084評論 1 291
  • 那天鞋拟,我揣著相機(jī)與錄音,去河邊找鬼惹资。 笑死贺纲,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的布轿。 我是一名探鬼主播哮笆,決...
    沈念sama閱讀 39,151評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼汰扭!你這毒婦竟也來了稠肘?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,912評論 0 268
  • 序言:老撾萬榮一對情侶失蹤萝毛,失蹤者是張志新(化名)和其女友劉穎项阴,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體笆包,經(jīng)...
    沈念sama閱讀 44,355評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡环揽,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,666評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了庵佣。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片歉胶。...
    茶點(diǎn)故事閱讀 38,809評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖巴粪,靈堂內(nèi)的尸體忽然破棺而出通今,到底是詐尸還是另有隱情,我是刑警寧澤肛根,帶...
    沈念sama閱讀 34,504評論 4 334
  • 正文 年R本政府宣布辫塌,位于F島的核電站,受9級特大地震影響派哲,放射性物質(zhì)發(fā)生泄漏臼氨。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,150評論 3 317
  • 文/蒙蒙 一芭届、第九天 我趴在偏房一處隱蔽的房頂上張望储矩。 院中可真熱鬧感耙,春花似錦、人聲如沸椰苟。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,882評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽舆蝴。三九已至,卻和暖如春题诵,著一層夾襖步出監(jiān)牢的瞬間洁仗,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,121評論 1 267
  • 我被黑心中介騙來泰國打工性锭, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留赠潦,地道東北人。 一個月前我還...
    沈念sama閱讀 46,628評論 2 362
  • 正文 我出身青樓草冈,卻偏偏與公主長得像她奥,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子怎棱,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,724評論 2 351