概述

随着flutter的普及,Dart语法逐渐被使用起来,Dart是Google开发的一门编程语言。

主要应用方向:移动开发、DartVM 命令行程序(Server 端)、浏览器(前端)。

Dart的应用

Dart有如下几个应用方向:

移动开发

是众多 Dart 开发者开始接触学习 Dart 语言的原因。这个移动开发的核心是叫做 Flutter 的一个框架,它使用Dart + C++ + Skia 开发,对外提供了完全不依赖系统平台的 Widget 的能力,只通过自绘图形的方式工作,因此具有极其优秀的跨平台性。

服务端

DartVM :就是写服务端的应用。比如写个 http 的服务,对应用提供 api ,都是及其简单的事情。

web开发

Google 发布的 Dart 2,重新定义了对这门语言的新认知:Dart 是针对 Web 和移动客户端开发进行独特优化的语言

Dart主要是替换了JavaScript,用Dart来做JavaScript这部分工作,但浏览器不能直接识别,需要用Dart2js 编译器将Dart语言编译成js运行。除了编译器之外,Dart Web平台还提供了核心库,对DOM访问以及从Dart 调用JavaScript的交互操作。

接下来我们主要看下web端的项目的开发。

web环境搭建和应用

  1. 手动安装

    下载地址:http://www.gekorm.com/dart-wi...

  2. 配置环境变量
    dart-sdkbin路径添加到path环境变量中
  3. vscode中安装Code Runner插件,来调试我们的dart代码
  4. 安装webdevstagehand

    pub global activate webdev

    pub global activate stagehand

  5. 创建一个Dart项目:

    stagehand web-simple

  6. 获取依赖包:

    pub get

项目运行:

命令行运行项目:

webdev serve

image-20200324195121923

项目构建

如果想将dart文件编译转为js文件,使用webdev build 命令来构建一个版本,该命令使用dart sdk自带的dart2js这个工具来将dart文件编译为js文件:

image-20200325104842431

web技术的应用主要包括js对html文档元素的事件处理和css对文档样式的修饰;

文档元素的操作

Dart提供了dart:html库来操作DOM中的对象和元素。基于控制台的应用程序无法使用dart:html库。要在Web应用程序中使用HTML库,请导入dart:html,如果需要支持所有的html5的api,还需额外引用dart:web_audiodart:svgdart:web_gl等。

获取文档元素:

image-20200324203959615

Parent和Child

// 获取当前文档元素的父元素
var oDiv = document.querySelector("#con");
print(oDiv.parent.tagName);//DIV
print(oDiv.parent.id);//textContainerId

children和childNodes都可以得到子元素,不同的地方在于children返回的是List<Element>,因此可以方便的使用这些Element对象的属性和方法,而childNodes返回的是Node列表,可以对节点作具体操作:

// 获取子元素:
var body = document.querySelector('body');
body.children.forEach((el) => print(el.tagName));
body.childNodes.forEach((el) => print(el));

HtmlElement

dart:html中,所有东西都是结构化的,并使用类进行分类如:BodyElementDivElementParagraphElementInputElement 等;

document中所有的HTML元素都继承自HtmlElement;HtmlElement包含了所有元素通用的方法和属性如:innerHtml、id、click等;

元素的创建:

var oDiv = querySelector("#con");
//创建输入框
var input = new InputElement()
  ..id = 'input'
  ..name = 'input'
  ..type = 'text'
  ..placeholder = ''
  ..width = 100;
oDiv.nodes.add(input); //同时append多个对象需使用addAll([])

//创建p标签
var oP = new ParagraphElement();
oP..id = 'text'
    ..text = 'Paragraph Element!'
    ..title = 'ParagraphElement';
oDiv.nodes.add(oP);

var div = new DivElement() //实例化一个Element并设置属性
    ..id='div_id'
    ..text = ' Replacement element';
text.replaceWith(div);//替换元素
//如果想删除元素:text.remove();

事件管理

添加事件的关键语法为:element.on['event'].listenlisten()函数返回的是StreamSubscription
可以调用pauseresumecancel函数暂停、重新开始、取消监听;

// 获取元素并绑定输入框的onchange事件,新增list
import 'dart:html';

InputElement toDoInput;
UListElement toDoList;
ButtonElement deleteAll;

void main() {
  toDoInput = querySelector('#to-do-input');
  toDoList = querySelector('#to-do-list');
  toDoInput.onChange.listen(addToDoItem);
}

void addToDoItem(Event e) {
  var newToDo = new LIElement();
  newToDo.text = toDoInput.value;
  toDoInput.value = '';
  toDoList.children.add(newToDo);
}
// 创建元素并添加点击事件
void addToDoItem(Event e) {
  var newToDo = new LIElement();
  newToDo.text = toDoInput.value;
  newToDo.onClick.listen((e) => newToDo.remove());
  toDoInput.value = '';
  toDoList.children.add(newToDo);
}

对样式的处理

有如下两种处理方式:

1、对css样式的操作都集中到了CssClassSet类中:

// 创建一个button元素,并且绑定点击事件,点击按钮触发样式改变
var oBtn = new ButtonElement()
  ..id = 'btn'
  ..text = 'button'
  ..onClick.listen((event) {
    container.classes
    ..clear()
    ..add('error');
    oP.text = 'msgtip';
  });

oBtn.classes.toggle('enlarge');

2、同js语言有相同的处理方式,如:element.style.color = '#fff';

网络请求

关于如何请求网络资源和数据,客户端通常使用HttpRequest类提供的getString()方法请求服务器资源;

const  path = 'myData.json';
HttpRequest.getString(path).then((String fileContents) {
  print(fileContents.length); }).catchError((error) { 
  print(error.toString()); 
});

对于异步解决方案,Dart提供了Future对象,它的作用跟js中的Promise相似,它们都是异步编程的解决方案:

Future<void> makeRequest(Event _) async {
  const path = 'https://XXXX';
  try {
    final jsonString = await HttpRequest.getString(path);
    processResponse(jsonString);
  } catch (e) {   
  }
}

void processResponse(String jsonString) {
  for (final portmanteau in json.decode(jsonString)) {
    wordList.children.add(LIElement()..text = portmanteau as String);
  }
}

web应用框架

Web是Dart的核心平台之一,让我们用更加规范严格的代码去进行web开发,对于比较简单的web应用,我们可以使用dart-to-javascript来快速的编译代码;但是对于比较复杂的web应用,官方推荐:

与更高级别的Web应用程序框架一起使用,许多同时支持Web和移动应用程序都是使用FlutterFlutter Web支持构建的。Dart Web平台支持AngularDart,Flutter Web支持和其他Dart Web应用程序框架。

当前有一些第三方库已经支持用Dart开发,像目前比较流行的react、vue、angular等,这些js库目前都已经推出了dart版本,例如:

LibraryPackagesNotes
AngularDartangularAngular的Dart版本,对于支持事件处理和依赖注入等功能的复杂应用程序很有用。
JavaScript interopjs支持从Dart代码调用JavaScript库。
Material Designmd_core, m4d_components基于Material Design的模块
ReactreactDart版react.js
VuevueDart版vue.js

除此之外还有许多第三方dart包,可以在pub.dev官网https://pub.flutter-io.cn/,...

目前,如果用Dart去开发我们的web应用,存在的最大的问题就是dart2js之后文件的体积大小了,dart2发布以来,项目默认开启“tree-shaking”,构建命令增加“--minify”,已经相较于上一版本压缩后的体积已经有了很大的提升。在今后的实际开发前,我们还需要不断的不关注dart官方代码的更新和优化。

以上内容是 Dart在web端的应用,如果深入的用Dart进行项目开发,还需要去学习Dart的基础语法,下面我们来看下Dart的语言特性。

语言特性

强类型语言,必须声明,在编译阶段会检查类型,避免运行时报错,支持var声明(无类型),众所周知,JavaScript 是一门弱类型的语言,而 Dart 是强类型的语言,同时也支持一些弱类型,Dart 中弱类型有var, Object 以及dynamic

  1. Dart所有的东西都是对象, 即使是数字numbers、函数function、null也都是对象,所有的对象都继承自Object类。
  2. Dart动态类型语言, 尽量给变量定义一个类型,会更安全,没有显示定义类型的变量在 debug 模式下会类型会是 dynamic(动态的)。
  3. Dart 在 running 之前解析你的所有代码,指定数据类型和编译时的常量,可以提高运行速度。
  4. Dart 支持顶级方法 (例如 main()),同时还支持在类中定义函数。 (静态函数和实例函数)。 你还可以在方法中定义方法 (嵌套方法或者局部方法)。
  5. 没有初始化的变量都会被赋予默认值 null。
  6. final和const都是常量声明,前者是使用时才申请内存,后者是编译时就先占内存,二者影响不大

常用的数据类型

  1. String
  2. Numbers (int,double)
  3. Booleans(bool)
  4. Lists (也被称之为 arrays)
  5. Maps

变量与常量

声明变量类型:int double String List

  1. var 声明完数据类型,后期不能被修改
  2. dynamic代表未定义类型,会推断所有属性和方法,数据类型可动态变,规避了校验,可能会引入bug
  3. final 使用时常量,用时才申请内存
  4. const 编译时常量,先占内存

    示例代码:

    void main() {
    
        //1、声明完数据类型,后期不能被修改
        var a = 'ahaha'; //var 声明会自动识别数据类型
        // a = 123;  //会报错,类型不一致
    }

dart一切皆对象

 Object password = 123;
    password = 1;

dynamic代表未定义类型,会推断所有属性和方法,数据类型可动态变,规避了校验,可能会引入bug

dynamic as = 'halou';
as = 12;
print( as);
//print( ab.length ); //object不具备length,编译阶段就会报错提示

String job = '你好';
bool result =123<110;
List list = [1,3,5,7,9];

//final 使用时常量,用时才申请内存
//const 编译时常量,先占内存
const aw = 'good';
//aw = 'bad'; //不能被重新赋值

函数

每个应用程序都必须有一个顶层main()函数,它可以作为应用程序的入口点。函数必须要有返回值,加上void声明表示函数不需要有返回值。

示例代码:

String getUserName(){
  return 'xiaomi';
}

// Dart中每个应用程序都必须有一个顶级main()函数,该函数作为应用程序的入口点。
// (函数必须要返回值 ,加上void声明表示函数不需要返回值)
void main() {
    //return 'haha'; //此时返回会报错
    String username = getUserName();
    print(getPersonInfo('122'));
    print(addAge(1));
    
}

String getPersonInfo(String userId){
    Map userInfo = {'122':'张三'};
    return userInfo[userId];
}

可选参数 不加可选的话,参数不传会报错

int addAge( int age1,[int age2=10]){
    return age1+age2;
}

支持箭头函数

void printNumber(num number) =>
     print('The number is $number.');

· 普通类
· 抽象类
Dart抽象类主要用于定义标准,子类可以继承抽象类,也可以实现抽象类接口。

1、抽象类通过abstract 关键字来定义

2、Dart中的抽象方法不能用abstract声明,Dart中没有方法体的方法我们称为抽象方法。

3、如果子类继承抽象类必须得实现里面的抽象方法

4、如果把抽象类当做接口实现的话必须得实现抽象类里面定义的所有属性和方法。

5、抽象类不能被实例化,只有继承它的子类可以。

6、接口:使用implements关键字,一般使用抽象类定义接口。

示例代码:

void main() {  
   var p = new Person(10,'小米');
   p.sayHello();   
}
class Person {
   int age;
   String name;
   //构造函数 实例化时自动触发
   Person(int age,String name){
     this.name = name;
     this.age = age;
   }
   void sayHello(){
     print('my name is ${this.name}');
   }
}

//子类继承父类,拥有父类的属性和方法
class Worker extends Person{
  int number;
  //构造函数 super继承父类的构造器 并对自身构造器进行拓展
  Worker(int age, String name,int number) : super(age, name){
    this.number = number;
  }
  //父类同名方法的覆盖
  void sayHello(){
    super.sayHello(); //调用父类的sayhello
    print('my number is ${this.number}');
  }

}

接口的实现(implements)

如果有一个Class A,你想让类B拥有A的API,但又不想拥有A里的实现,那么你就应该把A当做接口,类B implements 类A:

/*一个类实现多个接口:*/
abstract class A{
  String name;
  printA();
}

abstract class B{
  printB();
}

class C implements A,B{  
  String name; 
  printA() {
    print('printA');
  }
  printB() {
    // TODO: implement printB
    return null;
  }
}

void main(){
  C c=new C();
  c.printA();
}

泛型

泛型就是解决类 接口 方法的复用性,以及对不特定数据类型的支持(数据校验),默认泛型标识就是一个大写的T,也可以写其他的;
Dart 泛型类、泛型接口:

//泛型类
class PrintClass<T>{
  List list=new List<T>();
  void add(T value){
    this.list.add(value);
  }
  void printInfo(){
    for( var i=0;i<this.list.length;i++ ){
      print(this.list[i]);
    }
  }
}

void main(){
  //泛型函数
  getData<String>('你好');
  //泛型类
  PrintClass p = new PrintClass<int>();
  p.add(1);
}

泛型方法:

//泛型方法
T getData<T>(T value){
  return value;
}

pub包管理

Dart的软件包管理器是pub。托管软件包的存储库可以在 https://pub.dartlang.org/ 找到;
每个Dart应用程序都有一个pubspec.yaml文件,包含了项目依赖包配置(类package.json)。
操作命令:
pub get:获取应用程序依赖的所有包。
pub upgrade:将所有依赖项升级到较新版本。
pub build:构建应用

Dart中的库主要有三种:

1、我们自定义的库:

import 'lib/mylib1.dart' as lib1;

2、系统内置的库:

import 'dart:math;
import 'dart:io';
import 'dart:convert';

3、pub包管理系统中的库:

import 'package:dio/dio.dart';

载入第三方库:

1)需要载入第三方库我们是需要在 pubspec.yaml 文件中声明需要引用的库;
2)使用 pub get 进行拉取;
3)调用:import 'package:dio/dio.dart'; // Dio 一个很强大的网络请求库;

小结

以上就是对Dart的一个入门级讲解,对于web端:(1)因为dart语言设计的问题,它并不属于脚本语言,需要借助dart2js将代码转为js,效率并不高,(2)另外,dart的库相对js来说比较少,而ts可以直接使用js的库。虽然dart也能调用js,但用起来不太方便;

但是对于移动端,虽然Dart目前生态还不是很完善,但是随着Flutter的广泛推广,相信它也会很快得到应用,在开发过程中如果使用到一些类库,可以去查询相应的api。


林之夏
9 声望0 粉丝