实现用户同意管理的前端技术实践与避坑指南

一瑞珺 安全 阅读 1,082
赞 22 收藏
二维码
手机扫码查看
反馈

项目背景和用户同意的引入

最近刚结束一个电商类项目,需求里有一条是必须要有“用户同意”的功能模块。一开始我觉得这不就是个弹窗加个勾选框的事吗?后来发现完全不是这么回事,光这个功能就折腾了我好几天。

实现用户同意管理的前端技术实践与避坑指南

事情的起因是欧盟那边的客户要求符合GDPR规范,说白了就是要让用户明确知道自己同意了哪些数据收集行为。原本我们团队打算用现成的第三方库,但试了几款后发现要么太重,要么定制化太差。最后决定自己写一套轻量化的实现方案。

核心代码与基本逻辑

最开始的思路很简单:在页面加载时检查用户的同意状态,如果没同意就弹出提示框,用户选择后保存到本地存储或者服务器。

以下是最初的代码实现:

// 检查用户是否已经同意
function checkConsent() {
    const consent = localStorage.getItem('userConsent');
    if (!consent) {
        showConsentPopup();
    } else {
        console.log('用户已同意:', consent);
    }
}

// 显示同意弹窗
function showConsentPopup() {
    const popup = document.createElement('div');
    popup.innerHTML = 
        <div style="position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); background: white; padding: 20px; border: 1px solid #ccc;">
            <p>我们需要您的同意来使用Cookie和其他技术。</p>
            <button id="acceptBtn">同意</button>
            <button id="declineBtn">拒绝</button>
        </div>
    ;
    document.body.appendChild(popup);

    document.getElementById('acceptBtn').addEventListener('click', () => {
        localStorage.setItem('userConsent', 'accepted');
        popup.remove();
    });

    document.getElementById('declineBtn').addEventListener('click', () => {
        localStorage.setItem('userConsent', 'declined');
        popup.remove();
    });
}

// 页面加载时执行检查
window.addEventListener('load', checkConsent);

这段代码看起来没问题吧?其实问题大了去了。

最大的坑:用户体验与性能问题

第一次上线后,测试反馈了一堆问题。首先是性能问题,这个弹窗会在每次页面加载时都检查一遍,而且因为它是同步执行的,导致页面渲染被阻塞了几百毫秒。虽然几百毫秒听起来不多,但在电商场景下,这种延迟会让用户流失率直线上升。

其次,用户体验也是一团糟。弹窗样式太丑,按钮点击后没有任何过渡效果,用户点了同意后还得手动刷新页面才能看到变化。

后来我调整了方案,把检查逻辑放到一个异步函数里,并且用CSS动画优化了弹窗的效果:

async function checkConsentAsync() {
    const consent = await new Promise(resolve => {
        setTimeout(() => resolve(localStorage.getItem('userConsent')), 0);
    });
    if (!consent) {
        showConsentPopup();
    }
}

function showConsentPopup() {
    const popup = document.createElement('div');
    popup.innerHTML = 
        <div class="consent-popup">
            <p>我们需要您的同意来使用Cookie和其他技术。</p>
            <button id="acceptBtn">同意</button>
            <button id="declineBtn">拒绝</button>
        </div>
    ;
    popup.classList.add('fade-in');
    document.body.appendChild(popup);

    document.getElementById('acceptBtn').addEventListener('click', () => {
        localStorage.setItem('userConsent', 'accepted');
        popup.classList.add('fade-out');
        setTimeout(() => popup.remove(), 300); // 动画结束后移除
    });

    document.getElementById('declineBtn').addEventListener('click', () => {
        localStorage.setItem('userConsent', 'declined');
        popup.classList.add('fade-out');
        setTimeout(() => popup.remove(), 300);
    });
}

window.addEventListener('load', checkConsentAsync);

CSS部分:

.consent-popup {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: white;
padding: 20px;
border: 1px solid #ccc;
opacity: 0;
transition: opacity 0.3s ease-in-out;
}

.fade-in {
opacity: 1;
}

.fade-out {
opacity: 0;
}
`>
<p>这样一来,性能问题解决了,用户体验也提升了不少。但还有个小问题:如果用户清除了浏览器缓存,之前的同意状态就会丢失,弹窗又会重新弹出来。这个问题暂时还没找到完美的解决办法,不过影响不大,先这样放着了。</p>

<h2>另一个挑战:多语言支持</h2>
&lt;p&gt;项目中还有一个小插曲,就是客户要求支持多语言。弹窗里的文字需要根据用户的浏览器语言自动切换。一开始我是用了一个简单的语言映射表:&lt;/p&gt;</code></pre>javascript
const messages = {
en: 'We need your consent to use cookies and other technologies.',
de: 'Wir benötigen Ihre Zustimmung zur Verwendung von Cookies und anderen Technologien.',
fr: 'Nous avons besoin de votre consentement pour utiliser des cookies et d'autres technologies.'
};

const userLang = navigator.language.split('-')[0];
const message = messages[userLang] || messages['en'];

console.log(message);
>
<p>后来发现这样太死板了,尤其是新增语言的时候还得改代码。于是我把文案放到了后端API里,通过接口动态获取:</p>
`javascript
fetch('https://jztheme.com/api/consent-messages')
.then(response => response.json())
.then(data => {
const userLang = navigator.language.split('-')[0];
const message = data[userLang] || data['en'];
console.log(message);
})
.catch(error => console.error('Failed to fetch consent messages:', error));
`>

这个改动让整个流程更灵活了,但也引入了新的问题——网络请求失败怎么办?最后我在本地加了个默认文案兜底。

回顾与反思

总的来说,这个功能比我想象中复杂得多。从最初的一个简单弹窗,到最后涉及性能优化、用户体验改进、多语言支持等多个方面,确实学到了不少东西。

  • 做得好的地方:最终的用户体验还算不错,弹窗不会卡顿,样式也比较友好。
  • 还能优化的地方:用户清除缓存后同意状态丢失的问题还没彻底解决,可能需要用服务器端存储来弥补。

以上是我个人对这个用户同意功能的完整讲解,有更优的实现方式欢迎评论区交流。

本文章不代表JZTHEME立场,仅为作者个人观点 / 研究心得 / 经验分享,旨在交流探讨,供读者参考。
发表评论

暂无评论