乐趣区

关于javascript:项目实战弹出广告任意页面展示

最近接到一个需要,产品经理心愿能新增弹窗广告,广告可依据后盾配置在利用任意页面弹出展现。当后盾扭转以后页面广告次数、链接或者指标页后,以后页面数据批改,不影响其余页面数据

例如后盾设置“首页”呈现广告 1 次,“我的”页面广告呈现 3 次,用户进去后敞开了“首页”广告 1 次,敞开了“我的”页面广告 2 次。此时退出利用,后盾将“首页”广告设置为 2 次,那么该用户“首页”广告重置为 2 次,“我的”页面广告仍为 1 次(3 – 2)

需要剖析

后端返回的数据必然是个数组,每个对象中会有 指标页(展现的页面 ), 跳转链接 总呈现的次数 三参数。前端要对数据进行解决:

  • 当本地没有数据时(第一次进入),将总呈现次数赋值给一参数 firstTotalTimes(记录原总呈现次数)
  • 当本地有数据(非第一次进入)

    1. 将本地存储中的 firstTotalTimes 革除,返回值赋值为 removeLocalTotalTimeList
    2. 将 removeLocalTotalTimeList 与 申请返回的数据 advertisementList 进行比照

      • 相等,阐明后盾数据没有扭转,查看你本地存储中的总呈现次数是否大于 0,大于则展现广告
      • 不相等,阐明后盾批改了数据,这里还要剖析,只重置批改处页的,未修改的中央不做解决

笔者用的框架是 umi3,其中有 wrappers 概念,即一个配置路由的高阶组件封装,在 umi.conf 中加上后,任何页面都要先通过这一道。要害代码如下:

useEffect(() => {dispatch({ type: 'common/fetchGetPopUpAdvertisementList'}).then((resData: any) => {if (resData?.resultCode === "S00000") {if (!localStorage.advertisementList) {const addFirstTotalTimes = resData.advertisementList.map((item: any) => {
                item.firstTotalTimes = item.totalTimes
                return item;
            })
            localStorage.advertisementList = JSON.stringify(addFirstTotalTimes);
        }

        const localAdvertisementList = JSON.parse(localStorage.advertisementList)

        const cloneLocalAdvertisementList = JSON.parse(JSON.stringify(localAdvertisementList))

        const removeLocalTotalTimeList = cloneLocalAdvertisementList.map((item: any) => {
            delete item.firstTotalTimes
            return item
        })
        if (_.isEqual(removeLocalTotalTimeList, resData.advertisementList)) {console.log('相等')
            localAdvertisementList.filter((item: any) => {if (item.targetUrl.indexOf(history.location.pathname) > -1) {if (item.firstTotalTimes > 0) {setAdItem(item)
                    }
                }
            })
        } else {console.log('不相等')
            const cloneList = JSON.parse(JSON.stringify(resData.advertisementList));
            for (let i = 0; i < cloneList.length; i++) {for (let j = 0; j < cloneLocalAdvertisementList.length; j++) {if (_.isEqual(cloneList[i].pkId, cloneLocalAdvertisementList[j].pkId)) {if (_.isEqual(cloneList[i], cloneLocalAdvertisementList[j])) {cloneList[i].firstTotalTimes = localAdvertisementList[j].firstTotalTimes
                        } else {cloneList[i].firstTotalTimes = cloneList[i].totalTimes
                        }
                    }
                }
            }
            localStorage.advertisementList = JSON.stringify(cloneList);
            cloneList.filter((item: any) => {if (item.targetUrl.indexOf(history.location.pathname) > -1) {if (item.firstTotalTimes > 0) {setAdItem(item)
                        setIsShow(true)
                    }
                }
            })
        }
    }
                                                                     })
}, [])

难点

JS 的数据可变性

第一个坑点在 JS 的数据是可变的,所以要对其数据进行深拷贝,才不会影响到其余数据,这里我用了最简略的深拷贝:JSON.parse(JSON.stringify)

const cloneLocalAdvertisementList = JSON.parse(JSON.stringify(localAdvertisementList),
)

判断后盾那个数据批改

在之前表述中曾经表明,当本地存储和申请过去的数据不统一时要判断,哪要做重置,哪些页面则维持原状。这就要对两个数组进行比照,最简略的办法就是做双循环(On2).

const cloneList = JSON.parse(JSON.stringify(resData.advertisementList));,深拷贝后盾返回数据,这样对 cloneList 进行解决时就不会影响到原数据。cloneLocalAdvertisementList 则是本地的存储

if (_.isEqual(cloneList[i].pkId, cloneLocalAdvertisementList[j].pkId)),pkId 是广告惟一标识,先辨认数组中的每一个对象,这是一一对应的,再判断 if (_.isEqual(cloneList[i], cloneLocalAdvertisementList[j])),比照对象中的值,如果是 true,即齐全相等,阐明后盾数据没有变动,那就将本地存储中的 firstTotalTimes 赋值给 cloneList 上的 firstTotalTimes。如果是 false,阐明后盾曾经批改,就把 firstTotalTimes 重置为本次拉取数据中的 totalTimes

const localAdvertisementList = JSON.parse(localStorage.advertisementList)
const cloneLocalAdvertisementList = JSON.parse(JSON.stringify(localAdvertisementList))
 ...
const cloneList = JSON.parse(JSON.stringify(resData.advertisementList));
for (let i = 0; i < cloneList.length; i++) {for (let j = 0; j < cloneLocalAdvertisementList.length; j++) {if (_.isEqual(cloneList[i].pkId, cloneLocalAdvertisementList[j].pkId)) {if (_.isEqual(cloneList[i], cloneLocalAdvertisementList[j])) {cloneList[i].firstTotalTimes = localAdvertisementList[j].firstTotalTimes
                } else {cloneList[i].firstTotalTimes = cloneList[i].totalTimes
            }
        }
    }
}

以上,就是对这次我的项目的外围代码,当然,还要思考到 App 端关上和 微信关上的差别,以及当未登录状态下的去登录后数据的更新等等,但这些能够通过监听登录来判断(useEffect 依赖数据)实现

总结

这次被数据可变性坑了,通过 debugger 来排查

双循环在理论我的项目中用的次数不多,所以对此做记录

退出移动版