vue-referral组件化

referral组件化方案

更新记录

2021-6-2

  • 暂时不用考虑通过配置展示组件

Overview

旧的 referral banner

https://docs.google.com/document/d/1Q5HFbfxmQsHNvaT–AKhdMuytENR7wanN5mrKakQ-1s/edit#

这次的需求

https://www.figma.com/file/ijyJNacQsmcCeGwf9UEIxO/AB-Test-Referral-Entrance-Post-Booking-Touchpoints?node-id=0%3A1

目前的 referral api

https://docs.google.com/document/d/13J8nulRH685vAgfn4FgSYNynp22V8MvSu6FHO1x7Ppk/edit#

Project diagram

  • referral banner api 提供原始数据
  • configure data 提供如何展示
  • 组件模版

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
// configure data
const componentJson = {
meta: {
componentCode: "post-review-referral",
platform: "node", // node email vue android ios
scope: "post-review",
apiUrl: "",
},
layout: {
direction: "column", // row column
mainAxisSpace: "space-around", // flex-start | flex-end | center | space-between | space-around
crossAxisAlignment: "flex-start", // flex-start | flex-end | middle

layoutType: "container", // container item
background: "",
sizeInfo: {
type: "responsive", // responsive 时,value为宽高比
ratio: "600/180",
minHeight: 100,
maxHeight: 200,
},
styles: {}, // box model + render related style, fontsize color ...
itemList: [
{
itemType: "text",
sourceType: "api", // api, i18n
dataField: "get.sub_title",

layoutType: "item", // container item
background: "",
sizeInfo: {
type: "static", // static 时,value为宽度
width: "352px", // px / %
height: "72px",
},
styles: {}, // box model + render related style, fontsize color ...
}, {
itemType: "button",
sourceType: "i18n", // api, i18n
source: "ctaText",

layoutType: "item", // container item
background: "",
sizeInfo: {
type: "static", // static 时,value为宽度
width: "352px", // px / %
height: "72px",
},
styles: {}, // box model + render related style, fontsize color ...
}
],
},
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// raw data
{
// 邀请用户,被邀请人下单成功后,自己能得到优惠描述
"get": {
"title": "xxx",
"sub_title": "xxxx",
"amount_desc": "¥ 10.1 OFF"
},
// 被邀请人,能得到的优惠描述
"give": {
"title": "xxx",
"sub_title": "xxxx",
"amount_desc": "$123 OFF" // 如果 en_US 后面会拼接 OFF,历史逻辑 先保留
},
"special_clause": "xxxxxx" // 中国用户特殊的展示逻辑,历史逻辑,保留
}

此需求包括 nodenewweb, email render, app(android/ios) 等不同平台,也可以兼容未来可能需要兼容的 vue,nuxt 等项目框架

Compatible with node new web service

首先先介绍下 nodenewweb 服务的基本情况,为了方便描述,下面称这个服务为 new web 项目。

我们的组件化方案将在 koa 中引入 mkt 组件包并且注册组件,其中 mkt 组件包提供所需要的 html string generator,然后在想要引用 mkt 组件的模版中引入组件模版,下面我们详细说一下在 new web 中如何集成 mkt 组件。

hello world

1
2
3
4
5
6
7
8
9
10
11
12
// hbs_helper
var referralBanner = require('../../../../mkt-components/referral-banner')

// 注册组件
hbs.registerHelper('referralBanner', function() {
return referralBanner
})
//email_review.html
<div class="review_top"></div>
<div class="review_box"></div>
// 引用组件
{{{referralBanner}}}

define props

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
// referral-banner-component.js
function renderReferralBanner(scope, outerReferralData) {
return `
<div class="review_bottom" style="line-height: 1; height: 100px; background: #dfdfdf;">
this is for referal banner
这个banner在<span>${scope}</span>显示
恭喜你 由于你定了活动${outerReferralData},现在邀请好友吧
</div>
<style>
.review_bottom {
font-size: 22px;
}
</style>`;
};

module.exports = renderReferralBanner
// hbs_helper
hbs.registerHelper('referralBanner', function(scope, outerReferralData) {
return referralBanner(scope, outerReferralData)
})
//email_review.html
<div class="review_top"></div>
<div class="review_box"></div>
// 引用组件
{{{referralBanner 'completeReview' booking_data.activity_name}}}

这里我们的组件需要外界提供参数,scope 来确定是在哪里显示的 feferral banner, 以及活动名字, 最终的显示效果。

inte with JSON

为了提供未来的灵活性和根据 api 下发数据以及展示,从而真正的减少代码发布,通过 admin 管理新的需求,我们需要根据 JSON 来确定如何展示数据。

mweb/web

对 mweb 和 web 分别提供组件

Compatible with email renderer service

email renderer 和 new web 类似,邮件客户端解析样式的能力比较弱,前端经常需要用 table 布局,需要把 flex 布局解析成客户端可以理解的 table。

Compatible with app

这部分暂时不在这个文档里面讨论

Project strcture

针对 node 层场景做 playground,待完善

优化方向

问:目前针对 new web 或者 nuxtnodenewweb 服务,需要写两套代码,探索一套代码编译生成不同包, 答:

  1. 一个问题是,提供给 new web 的是一个 html string provider(返回 html string 的函数), 提供给 nuxtnodenewweb 的是一个 vue component,两者有很大的不同。vue 的语法比 handlebars 强大非常多

比如 new web 包的占位符主要是组件的入参

vue component 包的占位符可能是入参,还有可能是 computed, method 等各种形式

举例在 vue component 包的模版可能是

1
2
3
4
5
6
7
8
9
10
hello {computedVariabl}

props: {
scope
},
computed: {
computedVariabl() {
return scope + 'computedVariable'
}
}

这样在 new web 服务中实际上无法识别除了入参之外的其他参数的(只能识别到 props)

所以暂时得针对不同的服务写不同的代码

  1. 还有一种可能的方案是,我们限制项目中 vue component 的能力,比如我们规定不能使用 computed
1
2
3
4
5
6
7
8
9
// vue component
hello {scope}

props: {
scope
},
// 不能在模版中使用props以外的变量
// new web
hello ${scope}

这样的话我们的代码就可以在 new web 和 vue 中同时运行,但是这样会减少很多 vue 的功能和灵活度

如何在 new web 项目中对外通信

如何减少样式冲突?