路由规范(含点击属性规范)

[toc]

路由规范

一、路由地址规范

1、路由/点击操作类型

序号 操作类型标识 操作类型描述 场景举例
1 openPage 页面跳转 发布内容按钮
2 popupWindow 弹出弹窗 查看物流按钮
3 popupToast 弹出Toast 催一催按钮

路由操作,常与按钮点击结合在一起,所以我们顺便约定【点击按钮的属性规范】。

2、点击按钮的属性与类规范

2.1、背景/场景示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// 页面跳转
{
"action_type": "route",
"action_name": "发布内容",
"action_value": "appScheme://openPage?pageName=PublishPage&title=123"
}

// 弹出弹窗
{
"action_type": "popup",
"action_name": "查看物流",
"action_value": "appScheme://popupWindow?windowName=LookLogisticsWindow&uid=123&goodId=456
}

// 弹出Toast
{
"action_type": "toast",
"action_name": "催一催",
"action_value": "appScheme://popupToast?toastName=common&title=Error&message=something_wrong
}


// 其他(点击发起其他请求)
{
"action_type": "custom",
"action_name": "删除订单"
}

2.2、点击属性类规范

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
// 基类
enum TapType {
route,
popup,
toast,
custom,
}

abstract class BaseTapModel {
final String? id; // 可用来作为埋点的id
final TapType? actionType;
final String? actionValue;
BaseTapModel({this.id, this.actionType, this.actionValue});
}

// 有 文字/图片
class OnTapModel extends BaseTapModel {
final String? actionName;
final String? actionImageUrl; // 用于支持图片
final String? selectedActionName;
final String? selectedActionImageUrl;

OnTapModel({
String? id,
TapType? actionType,
String? actionValue,
this.actionName,
this.actionImageUrl,
this.selectedActionName,
this.selectedActionImageUrl,
}) : assert(actionName != null || actionImageUrl != null),
super(
id: id,
actionType: actionType,
actionValue: actionValue,
);
}

// 有 badge
enum BadgeType {
dot, // 原点
number, // 数字
}

class BadgeButtonModel extends OnTapModel {
final BadgeType badgeType;
final int? badgeCount;

BadgeButtonModel({
String? id,
TapType? actionType,
String? actionValue,
String? actionName,
String? actionImageUrl,
String? selectedActionName,
String? selectedActionImageUrl,
this.badgeType = BadgeType.dot,
this.badgeCount,
}) : super(
id: id,
actionType: actionType,
actionValue: actionValue,
actionName: actionName,
actionImageUrl: actionImageUrl,
selectedActionName: selectedActionName,
selectedActionImageUrl: selectedActionImageUrl,
);
}

路由解析

三、WebUrl 的解析与构造

使用WebUrl解析的方法

1
2
3
4
5
6
7
8
// 解析方法如下:
/// 获取指定web地址的所有参数
static Map<String, dynamic>? getAllParamsFromWebUrl(String webUrl, {bool paramToObjectIfOK = false});

/// 将字符串value按需求转成 string 或者 object(如果可以转的情况下)
static dynamic getValueFromWebParamValueString(String value, {bool paramToObjectIfOK = false});

// 构造方法如下:

解析方法详细内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
import 'dart:convert';

import 'package:flutter/foundation.dart';

class WebUrlUtil {
/// 获取指定web地址的所有参数
///
/// [webUrl]:要获取参数的地址。
///
/// [paramToObjectIfOK]:一个布尔值,指示是否将参数值转换为对象(如果可能)。默认为false。
///
/// 返回包含地址参数的Map对象,其中参数名作为键,参数值作为值。
///
/// 例如:https://www.baidu.com/?a=1&b=2
/// 返回:{a: 1, b: 2}
static Map<String, dynamic>? getAllParamsFromWebUrl(
String webUrl, {
bool paramToObjectIfOK = false,
}) {
var paramStartIndex = webUrl.indexOf('?');
if (paramStartIndex == -1) {
return null;
}

Map<String, dynamic> paramMap = {};
var str = webUrl.substring(paramStartIndex + 1);
var strs = str.split('&');

for (var i = 0; i < strs.length; i++) {
var keyValueComponent = strs[i].split('=');
var key = keyValueComponent[0];
String value = keyValueComponent[1];
dynamic element = getValueFromWebParamValueString(
value,
paramToObjectIfOK: paramToObjectIfOK,
);

paramMap[key] = element;
}

return paramMap;
}

/// 将字符串value按需求转成 string 或者 object(如果可以转的情况下)
///
/// [value]:要处理的参数的值。
///
/// [paramToObjectIfOK]:一个布尔值,指示是否将参数值转换为对象(如果可能)。默认为false。
///
/// 返回参数值的处理结果。
static dynamic getValueFromWebParamValueString(
String value, {
required bool paramToObjectIfOK,
}) {
try {
value = Uri.decodeComponent(value);
} catch (error) {
// value = value;
debugPrint("不用解码");
}

if (paramToObjectIfOK != true) {
return value;
}

dynamic element; // 如果 json.decode 成功,返回类型会变化,所以需另声明变量
try {
element = json.decode(value);
} catch (error) {
element = value;
}
return element;
}
}

构造方法详细内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
import 'dart:convert';

import 'package:flutter/foundation.dart';

class WebUrlUtil {
static String addH5CustomParams(
String newString,
Map<String, dynamic> h5Params,
) {
for (String h5ParamKey in h5Params.keys) {
var h5ParamValue = h5Params[h5ParamKey]; // 类型不一定是String
if (h5ParamValue == null) {
continue;
}
late String h5ParamEncodeValue;
if (h5ParamValue is String) {
// h5ParamEncodeValue = h5ParamValue;
h5ParamEncodeValue =
Uri.encodeComponent(h5ParamValue); // 要编码,否则即使是字符串,但是含中文时候,也会出错
} else {
// String h5ParamParamString = h5ParamValue.toString();
// String h5ParamParamString =
// FormatterUtil.convert(h5ParamValue, 0); // 使用此行来修复json字符串没有引号的问题
String h5ParamParamString = jsonEncode(
h5ParamValue); // 使用此行来修复json字符串没有引号的问题,且避免使用FormatterUtil.convert时候的换行问题
h5ParamEncodeValue = Uri.encodeComponent(
h5ParamParamString); // 要编码,否则url,在app中的webView无法识别(虽然在goole chrome或safari上可以识别)
}

String extraString = "$h5ParamKey=$h5ParamEncodeValue";
if (newString.contains('?')) {
newString += "&$extraString";
} else {
newString += "?$extraString";
}
}
return newString;
}
}

End