一周落地京东E卡春节多端营销玩法

三个问题

  1. 快速交付项目:CodMi-M 方案应用

  2. 多端交互方案输出

  3. 多人无缝协作探索

首先,用一张图了解产品需求

因为本次需求只有一周的开发时间,且开发与视觉稿同步输出,我们需要投入多个人同时进入开发,所以把需求吃透,把模块拆分好,这对我们能否如期交付项目非常重要。

在进入开发前,我们尝试画了一张图(借鉴 DDD 的统一语言)——辅助分工及每个节点的同学快速check;同时把已知风险点很直接地展示给产品侧。

其中左侧部分是投放端和可适配能力,红色部分是我们预知的风险;右侧部分将整个产品的交互流转做了拆解,并在节点交互中提供了技术方案。

经过这样的拆解,在开发中每个同学只需要关注自己的部分,及需要适配的能力,就可以了。

小程序交互跳转逻辑

接下来我们从各端的实现来看看,怎么一周快速交付项目吧。

H5 主活动页面的实现

关注解决问题1. 快速交付项目:CodMi-M 方案应用

CodMi-M的应用

CodMi-M 是我们基于近两年的移动端开发,总结出来一套移动端 H5 的通用解决方案。

它基于脚手架 CodMi,关注应用层部分的封装,整合了站内常用的 sdk 和 api 封装,使开发者更聚焦业务逻辑。

在本次项目中,H5 部分的开发借助 CodMi-M,快速构建了活动页面。

CSS Modules 的应用

有的时候我们写的样式,不经意间就会影响到其他样式的CSS,但是我们却没有及时的发现。又或者在我们编写样式时,却怎么也不生效,莫名其妙发生覆盖的现象等。诸如此类的问题,在我们的项目逐渐扩大,参与的开发人员越来越多的情况下,会让人越来越绝望。

所以,我们采用CSS Modules的方式处理,尽量避免这些问题。

import styles from "./style.module.scss";
const RedEnvelope = () => {
return (
 <div className={styles.envelopeCover}>xxx</div>
)
}
export default RedEnvelope;
复制代码

但这样写,有的小伙伴会说了:

  • 每次需要使用驼峰式来进行命名

  • 每次引用styles对象去书写样式太麻烦了

  • CSS modules 和 全局css类混合在一起会很难管理

  • 引用没定义的CSS modules也不会出现警告

ok,这么说也确实有点不太方便,那这里我带大家再次升级一下。

使用react-css-modules来解决上面css modules的问题
import React from 'react';
import CSSModules from 'react-css-modules';
import styles from './table.css';

class Table extends React.Component {
    render () {
        return <div styleName='table'>
            <div styleName='row'>
                <div styleName='cell'>A0</div>
                <div styleName='cell'>B0</div>
            </div>
        </div>;
    }
}

export default CSSModules(Table, styles);
复制代码

这样的话,通过我们使用react-css-modules:

  • 不必再强制使用驼峰式了

  • 无需在styles每次使用CSS模块引用该对象

  • 当引用未定义的CSS模块会收到警告

  • 全局 CSS 和 CSS 模块之间有明显的区别,例如:

<div className='global-css' styleName='local-module'></div>
复制代码

组件化管理及组件实现

组件化管理虽然是老生常谈的话题了,但确是极其重要的,尤其在项目工期紧且多人协作开发的过程中。

首先把页面先拆分成了5个独立组件,5个组件基本上互不影响。这样整个红包活动,只需要在首页配置好具体的组件入口即可,负责具体某个楼层的同学便可以随时进入开发阶段。

获奖者列表组件的实现

例如获奖者列表组件便独立开发,而且完全独立自主进行设计。

为了提供活动的氛围感和互动感,在产品形态上设计了获奖者列表,每次进入页面加载获奖者前100位进行滚动。本次需求中的获奖者列表采用无缝滚动方式实现。

目前无缝滚动的算法是将原有数据复制一份,当滚动到复制数据区域时,将滚动重置为初始状态,例如:

Winner
======
Winner
======
复制代码

在上述例子中,’======’包裹的范围我们称之为可视区,超过其包裹范围则内容不可见。上例中是仅有 1条有效数据的滚动状态,由于仅有 1 条数据,我们对这一条数据进行复制,当滚动到AB的复制数据且css 滚动效果结束,我们要马上重置滚动状态为初始状态:

======
Winner
======
Winner
复制代码

本次需求获奖者列表的可视区域仅有一条数据展示,所以我们可以仅将数据列表的第一条数据追加到尾部。

[0,1,2,3,4] // 原始数据列表
[0,1,2,3,4,0] // 复制后的数据列表
复制代码

接下来是实现动效,动效的实现主要借助 setTimeout 和 css transtion:

// tsx
<div onTransitionEnd={handleTransitionEnd}>
  [0,1,2,3,4,0].map(item => <div>item</div>)
<div>

// js
const transitionTimer = () => {
  const delayTime = 2000;
  window.setTimeout(() => {
    // 计算 tranformY 的值
    const y = calculateTranformY();
    // 设置到 style 上
    setTranformYToCSS(y);
  }, delayTime);
};
const handleTransitionEnd = () => {
  if (isNeedResetTransition()) {
    resetTransition();
  }
  transitionTimer();
};
复制代码

常量的提取

整个红包项目逻辑上最复杂的也就是活动状态和用户状态的区分匹配了,用户状态分为:初始状态、助力状态、可开奖状态和已开奖状态。活动状态分为:初始状态、进行中状态、结束状态和异常状态。

而我们要做的就是根据每一个不同的用户状态和每一个不同的活动状态,匹配出不同的页面状态,那么整个项目在设计上就需要提前思考好。

由于不同的框架组件,可能都需要进行状态匹配,这里首先要做的就是对于常量先进行提取,封装在最外层,各组件可以随时调用。

// common/constants.ts
export const USER_STATUS = {
  InitialUserStatus: 1, // 初始状态
  HelpUserStatus: 2, // 助力状态
  CompleteUserStatus: 3, // 可开奖状态
  EndsUserStatus: 4 // 已开奖状态
};
export const STATUS = {
  ProgressStatus: 2, // 进行中状态
  EndsStatus: 4, // 结束状态
  ErrorStatus: 5, // 异常状态
};
复制代码

这样不仅减少了组件中一大堆令人看不懂的数字,提高了维护性和可读性。而且组件之间调用相同的常量状态,较少因为笔误,将状态匹配书写错误。

小程序的实现

本次需求有礼小程序中无新增页面,但需要在现有若干界面中进行改造,需要控制部分元素的显示与否、部分界面新增相关楼层等;同时考虑到春节活动的用户量及用户体验,需要对首页中多tab商品楼层加载缓慢导致首页卡顿问题进行修复。

  1. 梳理需求及代码的过程,也是综合考虑新增楼层标识的过程

前后端同时进入开发,在开发前的综合考虑以及接口沟通至关重要。

由于部分界面需要根据礼品卡的标识新增不同的楼层,有些楼层只需判断是否为春晚红包活动,而有些还需要区分普通主题还是活动期间的主题,此时就需要前后端在开发前一起综合考虑礼品卡的标识,之后根据标识各自进入开发。

  1. 新增功能类似,对方法进行封装而不是粘贴复制

多个新增楼层涉及到页面跳转,此时不是在页面间粘贴复制而是对方法进行了封装以兼容不同的情况。

function gotoActivity(url) {
  let jumpUrl = url;
  if (jumpUrl && jumpUrl.indexOf("http") == -1) {
    jumpUrl = `https:${jumpUrl}`;
  }
  if (jumpUrl) {
    let url = '/pages/login/wv-common/wv-common?h5_url=' + encodeURIComponent(jumpUrl)
    wx.navigateTo({
      url,
    });
  }
}
复制代码
  1. 通过微信开发者工具自带的mock功能模拟接口数据以减轻后期接口联调压力。

多端交互的实现

关注解决问题2: 多端交互方案输出

本次视觉稿时间和前端时间部分重合,正好可以利用此空档做多端交互的调研方案。整个流转里有两个主体,1是H5活动页,用来引流;2是京东有礼小程序里的拼手气页面,即主体页面。

从图中拆解为以下几步:

  1. 从JD APP的“H5活动页”直接跳转到京东有礼小程序“拼手气页面“;
  2. 从JD APP的“H5活动页”分享到微信会话框;
  3. 从微信会话框打开微信小程序,并定位到京东有礼小程序里的 H5 活动页;【在第二步中,只要设置好小程序id和路径,微信会处理这次的跳转。】
  4. 从微信京东有礼小程序里的 H5 活动页,打开有礼小程序“拼手气页面”。

同时复用老的批量绑卡的逻辑,以及实现有礼小程序里的登录态的打通。

我们这里关注多端交互的实现方法。

跳转1. 从JD APP的“H5活动页”直接跳转到京东有礼小程序“拼手气页面“

因为原生与H5之间有时需要主动交互,例如H5去使用调用原生的功能(比如拍照等),原生去唤起通知H5事件等,所以这里我们借助京东商城WebView,来为我们的红包活动的H5提供了丰富的定制化的能力。

export const gotoMP = (id: string) => {
  //跳转至小程序
  const u = navigator.userAgent;
  let jsonParams = {
    businessType: "jumpToMiniProgram", //string类型,固定字段,必须是这个
    callBackName: "cb", //string类型,h5用来接收callback的方法名称,如h5想在window.callback(jsonStr) 方法中接收回调,此项传值为"window.callback"
    params: {
      username: "gh_xxx", //填小程序原始id(有礼小程序)
      path: `pages/xx/xx?id=${id}`, //拉起小程序页面的可带参路径,不填默认拉起小程序首页
      miniProgramType: 0, //可选。打开开发版,体验版或正式版
    },
  };
  const jsonString = JSON.stringify(jsonParams);
  if (!!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/)) {
    //iOS
    window.webkit.messageHandlers.JDAppUnite.postMessage({
      method: "notifyMessageToNative",
      params: jsonString,
    });
  } else {
    //Android
    window.JDAppUnite && window.JDAppUnite.notifyMessageToNative(jsonString);
  }
};
复制代码

这段代码基本可以拿去直接使用,完成从JD APP 跳转到 小程序的实现。几点注意:

  1. 这里要区分好iOS的环境和Android环境,两者调用方式存在差异。

  2. 跳转到微信小程序的jsonParams对象下的params中,有个miniProgramType属性。这里0是跳转到线上开发版,2是跳转到体验版

  3. 对于ts的警告Property 'webkit & JDAppUnite' does not exist on type 'Window & typeof globalThis',我们需要在xxx.d.ts中进行全局interface Window的声明。

跳转2. 从JD APP的“H5活动页”分享到微信会话框

这里我们借助京东App的分享组件@jmfe/jm-jdshare,来为我们的H5 页面提供简洁的客户端分享接口。

此jnpm不仅支持分享,也支持京口令的功能,感兴趣的童靴可以去查看下:npm.m.jd.com/package/@jm…

import jdShare from "@jmfe/jm-jdshare";
jdShare.setShareInfo({
  title: "快来!你即将错过1888元京东E卡!",
  content: "好友心意专递 速来领取",
  url: window.location.href,
  img: "https://img10.360buyimg.com/imagetools/jfs/t1/175484/6/25230/10720/61d3e626Eac21a76e/de6be01ec69895cd.jpg",
  /**
    * 以下非必填
    */
  channel: "Wxfriends",
  callback: null,
  clickcallback: null,
  qrparam: null,
  keyparam: null,
  timeline_title: "",
  showFriendList: "",
  /**
    * 以下是小程序参数与上面的参数没有关联
    */
  mpId: "gh_xxx",
  mpIconUrl:
    "https://img12.360buyimg.com/imagetools/jfs/t1/101710/27/20890/155471/61e52ebdE1e249fe6/e70a71969319eaa7.jpg",
  mpPath: `pages/login/wv-xx/wv-xx?h5_url=${encodeURIComponent(
    window.location.href.replace("#/", "&source=YLWX"),
  )}`,
  mpType: "0",
  /**
    * 以下是分享有礼参数
    */
  // incentiveBizType: "1",
  // incentiveBizId: "INCENTIVEBIZID_DEMO",
});
复制代码

同样,这段代码也是可以直接拿去使用的一段代码片段。需要注意的是:分享到微信小程序的卡片中,有个mpType属性。为0,点击卡片进入到线上开发版,为2进入到体验版。

跳转3. 从微信京东有礼小程序里的 H5 活动页,打开有礼小程序“拼手气页面”

这里我们借助微信官方的web-view,来作为承载网页的容器。其作为开放能力,官方也是给我们提供了相关的方法(wx.miniProgram.navigateTo)。

这里要注意:跳转的路径最前面要有/,亲测如果没有/的话,根本就跳转不过去。

// <script type="text/javascript" src="https://res.wx.qq.com/open/js/jweixin-1.3.2.js"></script>

// javascript
export const toGiftMiniProgram = (id:string)=>{
  wx.miniProgram.navigateTo({url:`/pages/xx/xx?id=${id}`})
}
复制代码

半路杀进项目,如何快速了解并响应需求?

关注解决问题3:如何快速加人,且加人后是+1>2的效果。

首先一定是“好的设计+组件化模块管理”,这个前边打好了基础,不再赘述。

在这部分重点说说新同学半路进入项目的工作与体验。

项目了解

本次项目排期较为紧张,初始参与人员较少。为保证进度正常,半路增加开发人员介入。首先要做的是快速了解项目背景、视觉设计进度、关键节点(开发、提测、上线)等基础信息。

可能的问题及解决思路

本次开发负责活动页面底部两个banner 列表的渲染,数据来源于ace接口。拿到任务首先把握几个点:

  1. 任务涉及范围,对于前端开发人员,需要了解对接的产品需求、视觉设计、数据接口及测试用例。例如本次开发任务为独立的两个banner渲染,且数据只依赖于ace接口,不涉及同后端人员交接,对于这种逻辑独立、数据依赖程度低的需求,那么我们可以立即投入开发。

  2. 对应prd、视觉稿开发进度。如果流程不清楚、视觉稿经常变动或者可能以后修改。那么就要积极和产品视觉沟通,确认逻辑、视觉稿。并做好兜底。

  3. 页面还是组件。对于项目而言,整体架构的映射可以体现在路由设计上,开发者需要自己确认当前逻辑单独存放在页面还是作为组件被其它页面引用。例如两个banner列表,只需要写成组件即可。

  4. 人员沟通。 对接人员的效率和信息可靠程度决定了开发进展。如必须,可以通过线下会议室联合开发的方式提升沟通效率。

总结

从DDD借鉴统一语言的方式以图的形式展示出来,和CodMi-M通用方案在本次中起到了关键作用;在功能实现时,预留slot,方便集成多组件的接入,也方便多人支持项目,且压力较小。

同时,在项目里,沉淀了多种组件的实现,及交互跳转的方案。

最重要的是,能在1周内交付项目,对未来交付此类项目也做了一些技术沉淀和思考。

在此感谢组内小伙伴对于本文章的共同协作~

猜你喜欢

转载自juejin.im/post/7085310702428094477
今日推荐