如何设计一个ToC的弹窗

news2024/11/19 20:43:38

本文主要分享了如何设计一个具有高可扩展性的弹窗功能。

本设计参考了优惠券功能的设计思路,有兴趣的朋友可以看看优惠券的分享:如何设计一个可扩展的优惠券功能_java优惠券系统设计-CSDN博客

一、需求介绍

假如你的项目需要实现以下弹窗,你会怎么去实现?

需求:

1.展示1张图片,点击图片后跳转到另外1个页面(支持H5、小程序、其他小程序),有个关闭按钮,点击关闭按钮停留在当前页面

2.该弹窗功能提供给运营通过管理后台进行配置

3.弹窗频率需要有所控制,比如1天1次,有优先级,比如运营配置了3个弹窗,不能同时弹,需要按优先级每次进入页面的时候才弹(参考某团的体验)

4.支持灵活配置弹窗条件,比如地域属性、平台属性、时间属性、指定某些用户、用户来源等

5.在配置弹窗过程中有些变量属性,需要运行时才能确定,比如跳转链接中增加当前登录用户ID或者token作为参数

二、数据库设计(存储设计好坏往往决定一个功能日后的可维护、可扩展)

1.错误的表设计(按需求一一列举各种条件作为表结构的字段)

id

有效期

图片url

H5链接

小程序链接频率控制

优先级

条件1

条件2

...

条件n

1

2023-09-24

https://image.com/aa/bb.jpg

/page/mini

1次/天

99

ios

深圳市

相信很多朋友都是这样设计弹窗表的,这种表设计非常大的问题就是每次需要增加1个新的弹窗条件的话就要新增1个字段,非常不利于功能扩展。

2.正确的表设计(抽象区分‘配置数据’和‘弹窗条件’)

配置数据:使用1个字段,以json结构进行存储,可以做到灵活增加数据或改变数据,配置数据不涉及数据过滤,所以不涉及性能问题

id

有效期

优先级

背景图json

1

2023-09-24

99

{"imgUrl":"https://image.com/aa/bb.jpg","type":"redirct_mini","value":"/page/mini"}

弹窗条件:由列式转化为行式存储,增加条件不需要增加字段,而是加1行数据

id

popup_id

条件

条件值

1

1

条件1

1次/天

2

1

条件2

ios

3

1

条件3

深圳市

核心设计思想:

1.把数据库表的列式条件转化为行式条件,比如 where a=? and b=?,转化为2行数据作为条件(当然转化后不再是sql能表达的)

2.运用设计模式(类似责任链模式)把1中的行式条件转化为一段代码,可简单可复杂,通过关联关系来做到可插拔

3.完整的表结构设计(remark、create_time、update_time是固定字段)
CREATE TABLE `mk_popup_pop_condition` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',
  `bean_name` varchar(32) NOT NULL DEFAULT '' COMMENT 'bean名称(PopCondition的实现类)',
  `descrpition` varchar(255) DEFAULT NULL COMMENT '描述',
  `remark` varchar(255) DEFAULT NULL COMMENT '备注',
  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  PRIMARY KEY (`id`) USING BTREE,
  UNIQUE KEY `uniq_beanname` (`bean_name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='弹窗条件';

CREATE TABLE `mk_popup` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',
  `begin_time` datetime NOT NULL COMMENT '有效期开始时间',
  `end_time` datetime NOT NULL COMMENT '有效期结束时间',
  `status` varchar(8) NOT NULL DEFAULT '' COMMENT '状态(off:下架,on:上架)',
  `priority` int(11) NOT NULL DEFAULT '0' COMMENT '优先级(值越大,优先级越高)',
  `title` varchar(32) NOT NULL DEFAULT '' COMMENT '标题',
  `text` varchar(128) NOT NULL DEFAULT '' COMMENT '文案',
  `bg_img` varchar(255) NOT NULL DEFAULT '' COMMENT '背景图json数据',
  `close_btn` varchar(255) NOT NULL DEFAULT '' COMMENT '关闭按钮json数据',
  `remark` varchar(255) DEFAULT NULL COMMENT '备注',
  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  PRIMARY KEY (`id`) USING BTREE,
  KEY `idx_begintime` (`begin_time`),
  KEY `idx_endtime` (`end_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='弹窗';

CREATE TABLE `mk_popup_condition` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',
  `popup_id` int(11) NOT NULL COMMENT 'mk_popup.id',
  `pop_condition` varchar(32) NOT NULL DEFAULT '' COMMENT '弹窗条件(bean名称,mk_popup_pop_condition.bean_name)',
  `pop_condition_value` varchar(255) DEFAULT '' COMMENT '弹窗条件值',
  `remark` varchar(255) DEFAULT NULL COMMENT '备注',
  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  PRIMARY KEY (`id`),
  KEY `idx_popupid` (`popup_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='弹窗-弹窗条件';

CREATE TABLE `mk_popup_log` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',
  `business_type` varchar(64) NOT NULL DEFAULT '' COMMENT '业务类型(popup:mk_popup,user_popup:mk_user_popup)',
  `business_id` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '业务ID',
  `user_id` int(11) NOT NULL DEFAULT '0' COMMENT 'bu_user_info.id',
  `deviceid` varchar(64) NOT NULL DEFAULT '' COMMENT '设备号',
  `remark` varchar(255) DEFAULT NULL COMMENT '备注',
  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  PRIMARY KEY (`id`) USING BTREE,
  KEY `idx_userid` (`user_id`),
  KEY `idx_deviceid` (`deviceid`),
  KEY `idx_businessid_businesstype` (`business_id`,`business_type`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户弹窗记录';

表说明:

mk_popup_pop_condition:主要是记录有哪些弹窗条件,管理后台中配置弹窗时有用

mk_popup:弹窗配置,运营配置数据就往这里写数据

mk_popup_condition:某个弹窗的弹窗条件(1对多),条件组合配置就是利用该表

mk_popup_log:用户弹窗记录,用于控制弹窗频率

数据样例说明:

弹窗配置

弹窗条件

1) 弹窗1只有1个条件FrequencyCondition,可以理解为只控制弹窗频率为2次/天

2) 弹窗2有3个条件,需要符合场景为小程序首页,地域属性为深圳才弹,并且控制弹窗频率为1次/天

三、代码设计

1.抽象弹窗条件,定义一个接口,其子类对应mk_popup_pop_condition的数据

PopParam说明:

2.核心代码(PopService)中提供1个方法‘用户最优的弹窗’(此处代码过多,只贴核心部分,完整的可以通过gitee查看源码)

设计思想:

1.查询有效期内上架的所有弹窗(按优先级倒排,找到第1个就是最优的了),遍历每个弹窗的多个弹窗条件,判断有1个条件不满足就放弃该弹窗,进入下一个判断

2.运行时替换一些配置的参数,简单的如{userId},复杂的参数就实现ReplaceParam接口,下文有响应结果demo

tips:此处利用CompletableFuture优化性能,实现了多线程并发判断每个弹窗条件,只要有1个条件不满足就立马返回。

3.如何新增1种弹窗条件?

实现接口PopCondition,重写canPop方法,以下为‘场景’弹窗条件的代码

把Bean名称配置到弹窗条件表mk_popup_condition即可使用该条件,无需新增其他代码,也不改动主流程代码。

4.Controller固定入口

5.API定义

前端将弹窗封装成1个公共组件,只需请求固定接口/popup/best即可,在需要弹窗的页面直接引用该组件

入参:

字段

说明

sence

前端每个页面定义1个唯一值

经纬度

非固定参数,可不传

地域信息

非固定参数,可不传

渠道信息

非固定参数,可不传

...

非固定参数,可不传

响应:

字段

说明

model

前端渲染模板定义,需要与前端协商,不同的值代表不同的渲染模板

title

标题,本来想用于背景图的标题,但其实可以把标题设计到背景图中

text

文案,同标题

bgImg

背景图JSON,存储背景图位置的数据和动作

bgImg.imgUrl

背景图

bgImg.type

点击背景图做什么?(close:关闭,api:请求API,subscribe:订阅消息,redirect_http:跳转http链接,redirect_mini:跳转小程序链接,redirect_other_mini:跳转其他小程序链接)

bgImg.value

点击背景图做什么携带的信息

closeBtn

关闭按钮JSON,存储关闭按钮位置的动作(一般都是关闭,也可以做一些骚操作,比如点击关闭按钮跳转到某个页面,或者没有关闭按钮,一定要点击背景图)

popupLogId

弹窗记录ID,本设计中查询到弹窗就会往mk_popup_log插入记录,而不是用户看到弹窗才记录,如果需要了解用户是否有真正看到弹窗,需要与前端协商一起实现,这个ID可以作为下个api的传参

示例:

https://domain.com/popup/best?sence=mini_home&cityCode=440300

四、需求升级

1.点击图片后不跳转到另外1个页面,而是实现特殊逻辑(如拉起小程序订阅消息)

解:需要前端协作实现,增加bgImg.type的定义值,数据通过bgImg.value返回给前端

2.点击图片后不跳转到另外1个页面,而是切换到下一张图片,点击后下一张图片后才跳转页面(比如发优惠券,第一张图片展示立即领取,点击后请求api进行发券,随后切换至去使用的图片,点击后再跳转到对应用券页面)

解:增加下一步操作设计,next结构与最外层的响应一样,类似递归结构

3.图片位置除了背景图,还需要展示其他的信息,比如新人礼包弹窗展示优惠券(需要实现ReplaceParam来完成)

1)实现接口ReplaceParam,bean名称为参数名,重写replace方法,以下为‘新人券包’的demo代码

2)配置demo(即bg_img字段值),{newUserCoupon}是一个动态参数,运行过程中替换掉:

{
    "imgUrl": "{\"imgUrl\":\"https://img.domain.com/aaa.png\",\"newUserCoupon\":{newUserCoupon}}",
    "type": "api",
    "value": "https://domain.com/api/coupon/recive?id=8"
}

问:imgUrl为什么要配置为json字符串?

答:灵活运用固定字段响应数据给到前端,不同业务场景可定义不同的字段返回,只要跟前端约定好即可

数据响应示例:

4.在运行时给用户做一些弹窗埋点,比如完成某个事件后给用户埋一个弹窗,用户下次进入应用就给他弹

解:增加1张表mk_user_popup,字段与mk_popup差不多,但是不需要配置mk_popup_condition,因为这种弹窗只弹1次已经能满足需求,如有特殊需求也可以特殊设计

CREATE TABLE `mk_user_popup` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',
  `user_id` int(11) NOT NULL COMMENT 'bu_user_info.id',
  `begin_time` datetime NOT NULL COMMENT '有效期开始时间',
  `end_time` datetime NOT NULL COMMENT '有效期结束时间',
  `status` varchar(8) NOT NULL DEFAULT '' COMMENT '状态(off:下架,on:上架)',
  `priority` int(11) NOT NULL DEFAULT '0' COMMENT '优先级(值越大,优先级越高)',
  `title` varchar(32) NOT NULL DEFAULT '' COMMENT '标题',
  `text` varchar(128) NOT NULL DEFAULT '' COMMENT '文案',
  `bg_img` varchar(255) NOT NULL DEFAULT '' COMMENT '背景图json数据',
  `close_btn` varchar(255) NOT NULL DEFAULT '' COMMENT '关闭按钮json数据',
  `remark` varchar(255) DEFAULT NULL COMMENT '备注',
  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  PRIMARY KEY (`id`) USING BTREE,
  KEY `idx_userid` (`user_id`),
  KEY `idx_userid_begintime` (`user_id`,`begin_time`),
  KEY `idx_userid_endtime` (`user_id`,`end_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户弹窗';

PopService中增加以下代码

tips:还有些步骤型的逻辑,每步骤都有1个弹窗,比如进行到第1步,给用户埋了1个弹窗,但用户一直没有进入应用,后面流转到第2步了,又埋了1个弹窗。此时如果用户进入应用,就会先后看到2个弹窗,其实第1步的弹窗对于用户来说已经没有意义了(造成不好的用户体验),直接给用户弹第2步的弹窗即可。所以可以设计取消弹窗的操作,在埋第2步弹窗的同时把第1步弹窗取消掉。

扩展思考:

1.弹窗做成不同的表现形式,比如提示框效果,过一段时间自动消失

2.弹窗自动关闭,比如倒计时n秒后自动关闭

怎么样?如果你觉得有用的话,还不快快收藏起来!!!

附:涉及的代码目录

github:https://github.com/897665787/springcloud-template

gitee:springcloud-template: 一个基于springcloud netflix微服务框架,记录了关于微服务开发的一些最佳应用,欢迎大家学习指导。

springcloud-template

└── template-tool

     └──controller

          └── PopupController -- 最优弹窗查询API

     └── popup

          └── PopCondition -- 抽象定义使用条件

          └── PopParam -- 弹窗条件参数

          └── PopService -- 弹窗查询的核心代码

          └── ReplaceParam -- 参数替换接口

          └── condition -- 弹窗条件实现类(条件就新增到这下面)

               └── FrequencyCondition -- 弹窗频率

               └── PushAreaCondition -- 推送地区

               └── ... -- 其他弹窗条件

          └── param -- 参数替换实现类(复杂条件就新增到这下面)

               └──NewUserCouponReplaceParam  -- 新人券包

               └── ... -- 其他参数替换

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1095001.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

排序算法-合并排序法(MergeSort)

排序算法-合并排序法(MergeSort) 1、说明 合并排序法(MergeSort)是针对已排序好的两个或两个以上的数列(或数据文件),通过合并的方式将其组合成一个大的且已排好序的数列(或数据文…

debian9换源存在的问题

今天租借了云服务器搭建了debian9,给apt-get换源过程中出现了很多问题,主要有两个问题: 问题1: sudo apt-get update 0% [Working]问题2: W: The repository http://mirrors.aliyun.com/debian stretch Release doe…

软考网工选择题易错总结(2020下~2022下)

目录 2020下半年 2021上半年 2021年下半年 2022上半年 2022下半年 2020下半年 15、在卫星通信中,通常采用的差错控制机制为(15)。 A.停等 ARQ B.后退 N 帧 ARQ C.选择重发 ARQ D.最大限额 ARQ 答案&#xff1…

Golang基础学习笔记

Golang基础学习笔记 1、下载安装 1.1、下载 Golang下载地址:https://golang.google.cn/dl/ 1.2、安装 1.3、环境变量 # GOPATH D:\GolandProjects# GOPROXY https://mirrors.aliyun.com/goproxy# 启用Go模块支持 go env -w GO111MODULEon1.5、验证安装/配置 1.…

Premiere pro

操作 1.音乐淡入淡出 窗口 效果 音频过度 交叉淡化 指数淡化 拖动到首尾音频上2.手机视频序列设置 3.视频转场淡入淡出 选中视频 在视频连接处 交叉溶解

家居行业如何打破获客困局?2023重庆建博会现场,智哪儿AI营销第一课给出了答案

10月12日-14日,2023中国(重庆)建筑及装饰材料博览会(简称:2023中国重庆建博会)正在重庆国际博览中心如火如荼地进行。「智哪儿」携手2023中国重庆建博会主办方共同主办的《2023家居行业AI营销第一课&#x…

【quartus13.1/Verilog】swjtu西南交大:计组课程设计

实验目的: 通过学习简单的指令系统及其各指令的操作流程,用 Verilog HDL 语言实 现简单的处理器模块,并通过调用存储器模块,将处理器模块和存储器模块连接形成简 化的计算机核心部件组成的系统。 二. 实验内容 1. 底层用 Verilog…

推荐《金田一少年事件簿》

天树征丸原作,佐藤文也作画的漫画 金田一少年事件簿 播报编辑讨论7上传视频 《金田一少年事件簿》是一部日本推理漫画。早期原作为金成阳三郎(后担任剧本),原作为天树征丸(前原案),由漫画家佐…

【Python小项目之Tkinter应用】【实用工具】实现手写签名器,可选线条粗细,支持清空、撤销、恢复功能,可将写好的签名保存成图片

文章目录 前言一、实现思路二、关键代码三、完整代码总结同系列项目文章:前言 老规矩,先看效果: 在手写签名窗口中,用户可以选择线条粗细来签名,点击清空按钮可以清空画布,点击撤销按钮可以撤销一笔,点击恢复按钮可以撤销上一步进行的清空或撤销操作,点击保存按钮可以…

java案例RSA分段加密解密,签名验签,公钥加密私钥解密,私钥加密公钥解密,解密乱码怎么解决

一. 原理 非对称加密算法是一种密钥的保密方法。 非对称加密算法需要两个密钥:公开密钥(publickey:简称公钥)和私有密钥(privatekey:简称私钥)。公钥与私钥是一对,如果用公钥对数据进行加密,只…

Docker基础操作命令演示

Docker中的常见命令,可以参考官方文档:https://docs.docker.com/engine/reference/commandline/cli/ 1、常见命令介绍 其中,比较常见的命令有: 命令说明文档地址docker pull拉取镜像docker pulldocker push推送镜像到DockerReg…

Googleplay近期大量开发者二次验证问题与解决思路

近期谷歌play更新风控,开发者需要进行二次验证。9月份后大部分的开发者账号不论新老大部分都触发了二次验证风控,笔者目前整理了两个方向的解决方案。 老账号目前解决方案可以通过上传护照、身份证明、驾驶证或者租赁合同、水电费账单、信用卡账单、电话…

了解华为交换机路由器的基本命令

什么是CLI:使用户与设备交互的界面,用户输入对应的命令,设备会回复我们输入的内容,回车车后设备会执行对应命令,达到管理、配置、查看的目的。 CLI界面分为三种操作视图: 用户试图:设备登陆后…

基于阿基米德优化优化的BP神经网络(分类应用) - 附代码

基于阿基米德优化优化的BP神经网络(分类应用) - 附代码 文章目录 基于阿基米德优化优化的BP神经网络(分类应用) - 附代码1.鸢尾花iris数据介绍2.数据集整理3.阿基米德优化优化BP神经网络3.1 BP神经网络参数设置3.2 阿基米德优化算…

Java代码获取当天最晚时间写入数据库自动变为下一天的00:00:00

背景 有个需求要求将用户上传的年/月/日格式时间转为当天最晚时间23:59:59,例如上传2023/10/15,转换为2023/10/15 23:59:59,并将其存入数据库,数据库字段类型为datetime。 部分代码如下: public static Date getEndO…

游戏设计模式专栏(九):用装饰模式定制化游戏元素

点击上方亿元程序员关注和★星标 引言 大家好,我是亿元程序员,一位有着8年游戏行业经验的主程。 本系列是《和8年游戏主程一起学习设计模式》,让糟糕的代码在潜移默化中升华,欢迎大家关注分享收藏订阅。 装饰模式是一种结构性设…

Qt6开发的网络通信工具(支持TCP和UDP)

1. 页面展示 1.2 通信展示 1.2.1 UDP 通信显示 注意:前面的R表示时接收消息,S表示的是发送消息。 1.2.2 TCP通信显示 注:勾选服务器后,出现客户端连接列表,可以群发消息和私发消息。 3. 程序下载 应用程序免费下载&a…

(2022|CVPR,无语言模型,StyleGAN2,CLIP,图文特征对齐)LAFITE:迈向文本到图像生成的无语言训练

LAFITE: Towards Language-Free Training for Text-to-Image Generation 公众号:EDPJ(添加 VX:CV_EDPJ 或直接进 Q 交流群:922230617 获取资料) 目录 0. 摘要 1. 简介 2. 相关工作 3. LAFITE:一种无…

JDBC技术(java数据库连接技术)

引入:USB技术介绍 USB,是英文Universal Serial Bus(通用串行总线)的缩写,是一个外部总线标准,用于规范与外部设备的连接和通讯 USB是一个技术统称,有三部分组成 第一部分:USB的规范和…

深度学习电脑配置

目录 你真的需要这么一块阵列卡 你真的需要这么一块阵列卡 如何从硬件上保证数据安全?以下面这个 阵列卡 为例,它可以给硬盘组建磁盘阵列,其中用的比较多的是 RAID1 和 RAID5 。