feat:推广页点击联系我们展示企业微信二维码

This commit is contained in:
gwokwong 2024-09-24 17:12:26 +08:00
parent 8c8c5b04d5
commit 977cf61b50
4 changed files with 312 additions and 59 deletions

117
public/site/css/ad.css vendored
View File

@ -8,6 +8,7 @@
background-position: center;
background-repeat: no-repeat;
}
header .ad {
width: 100vw;
height: 0;
@ -54,6 +55,7 @@ header .ad .ad-content .ad-close {
background: rgba(0, 0, 0, 0.2);
transition: all 0.3s;
}
header .ad .ad-content .ad-close:hover {
background: rgba(0, 0, 0, 0.15);
}
@ -438,3 +440,118 @@ footer.ad-footer .footer-layout {
grid-template-columns: repeat(1, 1fr);
}
}
.ad-dialog {
position: fixed;
z-index: 10000;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: none;
}
.ad-dialog.show {
display: flex;
justify-content: center;
align-items: center;
}
.ad-dialog .ad-dialog-backdrop {
position: absolute;
z-index: 10010;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: #0000001f;
}
.ad-dialog .ad-dialog-wrapper {
z-index: 10020;
min-height: 200px;
min-width: 200px;
max-width: 320px;
max-height: 480px;
background-color: #fff;
border-radius: 16px;
padding: 24px;
box-shadow: 0px 4px 16px 8px #00000014;
display: flex;
flex-direction: column;
}
.ad-dialog .ad-dialog-wrapper .ad-dialog-header {
display: flex;
justify-content: center;
align-items: center;
flex-grow: 0;
flex-shrink: 0;
padding: 8px 12px;
}
.ad-dialog .ad-dialog-wrapper .ad-dialog-header .ad-dialog-header-img {
height: 240px;
width: 240px;
background-image: url(../img/side_nav_wechat.png);
background-size: cover;
background-position: center;
background-repeat: no-repeat;
}
.ad-dialog .ad-dialog-wrapper .ad-dialog-content {
display: flex;
justify-content: center;
align-items: center;
flex-grow: 1;
flex-shrink: 0;
padding: 8px 12px;
font-size: 14px;
color: #727570;
}
.ad-dialog .ad-dialog-wrapper .ad-dialog-footer {
display: flex;
justify-content: center;
align-items: center;
flex-grow: 0;
flex-shrink: 0;
padding: 8px 12px;
}
.ad-dialog .ad-dialog-wrapper .ad-dialog-footer .ad-dialog-footer-btn {
width: 100%;
height: 40px;
padding: 10px 16px 10px 16px;
border-radius: 8px;
background: linear-gradient(
104.43deg,
#ff7155 1.18%,
#ef3e56 46.98%,
#ee61d4 93.24%
);
border: none;
font-size: 16px;
font-weight: 500;
line-height: 20px;
text-align: center;
color: #fff;
cursor: pointer;
}
.ad-dialog .ad-dialog-wrapper .ad-dialog-footer .ad-dialog-footer-btn:hover {
background: linear-gradient(
-104.43deg,
#ff7155 1.18%,
#ef3e56 46.98%,
#ee61d4 93.24%
);
}

View File

@ -27,6 +27,22 @@
</head>
<body>
<div class="ad-dialog">
<div class="ad-dialog-backdrop"></div>
<div class="ad-dialog-wrapper">
<div id="ad-dialog-header" class="ad-dialog-header">
<div id="ad-dialog-header-img" class="ad-dialog-header-img"></div>
</div>
<div id="ad-dialog-content" class="ad-dialog-content">
Please scan the QR code to add our WeChat customer service representative for purchase
</div>
<div class="ad-dialog-footer">
<button id="ad-dialog-footer-btn" class="ad-dialog-footer-btn">Got it</button>
</div>
</div>
</div>
<div id="layout" class="ad-wrapper">
<!-- 同意cookie弹框 -->
<div id="cookieConsent">

222
public/site/js/ad.js vendored
View File

@ -28,6 +28,8 @@ document.addEventListener("DOMContentLoaded", function () {
fetchAdIntro(language);
manageAnimate();
handleDialog();
} else {
// 如果不是广告页面,插入广告样式表并获取广告栏
insertAdStylesheet();
@ -370,8 +372,7 @@ async function handleAdPlanPlans(plans) {
const planItemEl = document.createElement("div");
planItemEl.className = `plan-item ${plan.activated ? "active" : ""
}`;
planItemEl.innerHTML =
`
planItemEl.innerHTML = `
<div class="plan-item-title">
<span>${plan.title}</span>
</div>
@ -382,12 +383,14 @@ async function handleAdPlanPlans(plans) {
${plan.price.payment ?? ""}
</span>
</span>
<span class="plan-item-price-original ${plan.price.isPrice ? "price" : ""}">
<span class="plan-item-price-original ${plan.price.isPrice ? "price" : ""
}">
${plan.price.original ?? ""}
</span>
</div>
<div class="plan-item-button">
<a href="${plan.button.href}" ${plan.button.target === "_blank" ? 'target="_blank"' : ""}>
<a href="${plan.button.href}" ${plan.button.target === "_blank" ? 'target="_blank"' : ""
}>
<button class="btn-primary">
${plan.button.label}
</button>
@ -395,21 +398,24 @@ async function handleAdPlanPlans(plans) {
</div>
<div class="plan-item-description">
<ul class="plan-item-description-list">
${plan.features.map((feature) => {
const iconUrl = feature.icon.data
? getMediaUrl(feature.icon)
: "../img/ad/checked.svg";
return `
${plan.features
.map((feature) => {
const iconUrl = feature.icon.data
? getMediaUrl(feature.icon)
: "../img/ad/checked.svg";
return `
<li class="plan-item-description-item">
<i class="plan-item-description-item-icon">
<img src="${iconUrl}" alt="${feature.title}" />
</i>
<span class="plan-item-description-item-content ${feature.activated ? "" : "disabled"}">
<span class="plan-item-description-item-content ${feature.activated ? "" : "disabled"
}">
${feature.text}
</span>
</li>
`;
}).join("")}
})
.join("")}
</ul>
</div>
`;
@ -420,16 +426,26 @@ async function handleAdPlanPlans(plans) {
"animate__faster",
"animate__delay-1s"
);
couldAdPlanElAnimate[`${plan.id}`] = false
planItemEl.addEventListener("animationend", () => {
planItemEl.classList.remove("animate__backInUp", "animate__faster", "animate__delay-1s")
couldAdPlanElAnimate[`${plan.id}`] = true
}, { once: true })
couldAdPlanElAnimate[`${plan.id}`] = false;
planItemEl.addEventListener(
"animationend",
() => {
planItemEl.classList.remove(
"animate__backInUp",
"animate__faster",
"animate__delay-1s"
);
couldAdPlanElAnimate[`${plan.id}`] = true;
},
{ once: true }
);
await new Promise((resolve) => {
setTimeout(resolve, 150);
});
}
overridePlanButton();
}
}
@ -493,8 +509,7 @@ async function handleAdIntroIntros(intros) {
? getMediaUrl(intro.cover)
: `../img/ad/intro-card-img${intro.priority + 1}.svg`;
introItemEl.className = "ad-intro-item";
introItemEl.innerHTML =
`
introItemEl.innerHTML = `
<div class="ad-intro-item-header">
<img src="${barUrl}" alt="intro-bar" />
</div>
@ -514,13 +529,19 @@ async function handleAdIntroIntros(intros) {
"animate__zoomIn",
"animate__delay-1s"
);
couldAdIntroElAnimate[`${intro.id}`] = false
couldAdIntroElAnimate[`${intro.id}`] = false;
introItemEl.addEventListener("animationend", () => {
introItemEl.classList.remove("animate__zoomIn", "animate__delay-1s")
couldAdIntroElAnimate[`${intro.id}`] = true
}, { once: true })
introItemEl.addEventListener(
"animationend",
() => {
introItemEl.classList.remove(
"animate__zoomIn",
"animate__delay-1s"
);
couldAdIntroElAnimate[`${intro.id}`] = true;
},
{ once: true }
);
await new Promise((resolve) => {
setTimeout(resolve, 150);
});
@ -535,8 +556,7 @@ function handleError(error) {
// 插入广告栏元素
function insertAdBarElement() {
const adBarHTML =
`
const adBarHTML = `
<div id="ad" class="ad">
<div class="ad-content">
<div class="ad-content-left">
@ -620,63 +640,73 @@ function manageAnimate() {
window.addEventListener("scroll", () => {
throttle(() => {
console.log("scroll")
detectAdPlanEl()
detectAdIntroEl()
}, 200)
detectAdPlanEl();
detectAdIntroEl();
}, 200);
});
}
const couldAdPlanElAnimate = {}
const couldAdIntroElAnimate = {}
const couldAdPlanElAnimate = {};
const couldAdIntroElAnimate = {};
function detectAdPlanEl() {
const adPlanEl = document.querySelector(".ad-plan")
const adPlanEl = document.querySelector(".ad-plan");
if (isElementOutOfViewport(adPlanEl)) {
const els = document.querySelectorAll(".plan-item")
const els = document.querySelectorAll(".plan-item");
for (const el of els) {
couldAdPlanElAnimate[`${el.id}`] = true
couldAdPlanElAnimate[`${el.id}`] = true;
}
return
return;
}
const _couldAdPlanElAnimate = Object.values(couldAdPlanElAnimate).every(Boolean)
const _couldAdPlanElAnimate =
Object.values(couldAdPlanElAnimate).every(Boolean);
if (!_couldAdPlanElAnimate) return;
if (isElementPartiallyInViewport(adPlanEl)) {
const els = document.querySelectorAll(".plan-item")
const els = document.querySelectorAll(".plan-item");
for (const el of els) {
el.classList.add("animate__flipInX")
couldAdPlanElAnimate[`${el.id}`] = false
el.addEventListener("animationend", () => {
el.classList.remove("animate__flipInX")
}, { once: true })
el.classList.add("animate__flipInX");
couldAdPlanElAnimate[`${el.id}`] = false;
el.addEventListener(
"animationend",
() => {
el.classList.remove("animate__flipInX");
},
{ once: true }
);
}
return
return;
}
}
function detectAdIntroEl() {
const adIntroEl = document.querySelector(".ad-intro")
const adIntroEl = document.querySelector(".ad-intro");
if (isElementOutOfViewport(adIntroEl)) {
const els = document.querySelectorAll(".ad-intro-item")
const els = document.querySelectorAll(".ad-intro-item");
for (const el of els) {
couldAdIntroElAnimate[`${el.id}`] = true
couldAdIntroElAnimate[`${el.id}`] = true;
}
return
return;
}
const _couldAdIntroElAnimate = Object.values(couldAdIntroElAnimate).every(Boolean)
const _couldAdIntroElAnimate = Object.values(couldAdIntroElAnimate).every(
Boolean
);
if (!_couldAdIntroElAnimate) return;
if (isElementPartiallyInViewport(adIntroEl)) {
const els = document.querySelectorAll(".ad-intro-item")
const els = document.querySelectorAll(".ad-intro-item");
for (const el of els) {
el.classList.add("animate__zoomIn")
couldAdIntroElAnimate[`${el.id}`] = false
el.addEventListener("animationend", () => {
el.classList.remove("animate__zoomIn")
}, { once: true })
el.classList.add("animate__zoomIn");
couldAdIntroElAnimate[`${el.id}`] = false;
el.addEventListener(
"animationend",
() => {
el.classList.remove("animate__zoomIn");
},
{ once: true }
);
}
return
return;
}
}
@ -684,9 +714,11 @@ function isElementPartiallyInViewport(el) {
if (!el) return false;
const rect = el.getBoundingClientRect();
return (
rect.top < (window.innerHeight || document.documentElement.clientHeight) &&
rect.top <
(window.innerHeight || document.documentElement.clientHeight) &&
rect.bottom > 0 &&
rect.left < (window.innerWidth || document.documentElement.clientWidth) &&
rect.left <
(window.innerWidth || document.documentElement.clientWidth) &&
rect.right > 0
);
}
@ -696,8 +728,80 @@ function isElementOutOfViewport(el) {
const rect = el.getBoundingClientRect();
return (
rect.bottom < 0 ||
rect.top > (window.innerHeight || document.documentElement.clientHeight) ||
rect.top >
(window.innerHeight || document.documentElement.clientHeight) ||
rect.right < 0 ||
rect.left > (window.innerWidth || document.documentElement.clientWidth)
);
}
function handleDialog() {
const dialogEl = document.querySelector(".ad-dialog");
if (!dialogEl) return;
lockBodyScroll(dialogEl.classList.contains("show"));
overridePlanButton();
const dialogBackdropEl = dialogEl.querySelector(".ad-dialog-backdrop");
if (dialogBackdropEl) {
dialogBackdropEl.addEventListener("click", () => {
dialogEl.classList.remove("show");
lockBodyScroll(false);
handleDialogAnimate(false)
});
}
const dialogFooterBtnEl = dialogEl.querySelector(".ad-dialog-footer-btn");
if (dialogFooterBtnEl) {
dialogFooterBtnEl.addEventListener("click", () => {
dialogEl.classList.remove("show");
lockBodyScroll(false);
handleDialogAnimate(false)
});
}
}
function lockBodyScroll(bool) {
document.body.style.overflowY = bool ? "hidden" : "auto";
}
function overridePlanButton() {
function showDialog(e) {
e.preventDefault();
e.stopPropagation();
const dialogEl = document.querySelector(".ad-dialog");
if (!dialogEl) return;
dialogEl.classList.add("show");
lockBodyScroll(true);
handleDialogAnimate(true)
}
const planButtonEl = document.querySelectorAll(".plan-item-button");
planButtonEl.forEach((el) => {
el.removeEventListener("click", showDialog);
const aEl = el.querySelector("a");
if (!aEl.href || aEl.href.includes("#")) {
aEl.removeAttribute("href");
el.addEventListener("click", showDialog);
}
});
}
function handleDialogAnimate(bool) {
const dialogEl = document.querySelector(".ad-dialog");
if (!dialogEl) return;
const dialogWrapperEl = dialogEl.querySelector(".ad-dialog-wrapper");
if (!dialogWrapperEl) return;
if (bool) {
dialogWrapperEl.classList.add("animate__animated", "animate__bounceIn", "animate__faster");
dialogWrapperEl.addEventListener("animationend", () => {
dialogWrapperEl.classList.remove("animate__animated", "animate__bounceIn", "animate__faster")
})
} else {
dialogWrapperEl.classList.remove("animate__animated", "animate__bounceIn", "animate__faster")
}
}

View File

@ -25,6 +25,22 @@
</head>
<body>
<div class="ad-dialog">
<div class="ad-dialog-backdrop"></div>
<div class="ad-dialog-wrapper">
<div id="ad-dialog-header" class="ad-dialog-header">
<div id="ad-dialog-header-img" class="ad-dialog-header-img"></div>
</div>
<div id="ad-dialog-content" class="ad-dialog-content">
如需购买请扫码添加微信客服专员
</div>
<div class="ad-dialog-footer">
<button id="ad-dialog-footer-btn" class="ad-dialog-footer-btn">确定</button>
</div>
</div>
</div>
<div id="layout" class="ad-wrapper">
<!-- 同意cookie弹框 -->
<div id="cookieConsent">