gnosis23 / hello-world-blog

还是 issues 里面写文章方便
https://bohao.work
0 stars 0 forks source link

声明式UI #112

Open gnosis23 opened 2 years ago

gnosis23 commented 2 years ago

导语

经常听说这个 声明式UI(Declarative UI),它的定义是什么? 相对的还有 命令式UI(Imperative UI) ,它们的区别是什么呢?

定义

找了几篇文章,这篇 the-shift-to-declarative-ui 介绍的比较清楚:对于声明式UI

You describe what the UI should look like for a given state, and the framework figures out how to do it using sensible defaults and context.

Flutter - Introduction to declarative UI 这篇也有类似的描述:

In the declarative style, view configurations (such as Flutter’s Widgets) are immutable and are only lightweight “blueprints”. To change the UI, a widget triggers a rebuild on itself (most commonly by calling setState() on StatefulWidgets in Flutter) and constructs a new Widget subtree.

总结下就是:声明式UI 是一种描述 UI 的范式,用户负责提供描述 UI 结构的定义,框架负责组件渲染、生命周期、状态管理等等工作。

命令式UI 则需要用户自己管理组件的渲染、生命周期等等

例子

Flutter

这个 Flutter 官网的例子,很好的解释了 命令式UI声明式UI 的区别

比如要从左边这个界面切换到右边的界面

image

命令式会这么写:

// Imperative style
b.setColor(red)
b.clearChildren()
ViewC c3 = new ViewC(...)
b.add(c3)

而声明式会这么写:

// Declarative style
return ViewB(
  color: red,
  child: ViewC(...),
)

声明式不要去考虑如何转换颜色,如何清除子结点。只需要描述对应状态下应该如何显示界面

SwiftUI

再来看看 SwiftUI 官网的例子,描述了如何创建一个列表界面:

image

gnosis23 commented 2 years ago

Dart

这些框架为了简化声明式UI,所使用的语言都需要一些语法糖。比如 dart 语言。

optional named parameters 可选命名参数

构造函数里的参数前可以带个名字

import 'dart:math';

class Rectangle {
  int width;
  int height;
  Point origin;
  Rectangle({this.origin = const Point(0, 0), this.width = 0, this.height = 0});

  @override
  String toString() =>
      'Origin: (${origin.x}, ${origin.y}), width: $width, height: $height';
}

void main() {
  print(Rectangle(origin: const Point(10, 20), width: 100, height: 200));
  print(Rectangle(origin: const Point(10, 10)));
  print(Rectangle(width: 200));
  print(Rectangle());
}

optional new/const

// Before Dart 2
Widget build(BuildContext context) {
  return new Container(
    height: 56.0,
    padding: const EdgeInsets.symmetric(horizontal: 8.0),
    decoration: new BoxDecoration(color: Colors.blue[500]),
    child: new Row(
      ...
    ),
  );
}

// After Dart 2
Widget build(BuildContext context) =>
  Container(
    height: 56.0,
    padding: EdgeInsets.symmetric(horizontal: 8.0),
    decoration: BoxDecoration(color: Colors.blue[500]),
    child: Row(
      ...
    ),
  );