实现Cookie弹窗点击控制Google Analytics与GTM的启用状态
需求说明
需要实现Cookie同意页脚逻辑:
- 点击「全部接受」:启用Google Analytics(GA)和Google Tag Manager(GTM)
- 点击「仅必要」:仅启用GTM
分步解决方案
1. 完善Cookie状态区分与弹窗控制
修改FooterCookies组件,存储不同类型的同意状态,并在初始加载时检查已存在的Cookie避免重复弹窗:
import { useState, useEffect } from "react"; import Cookies from 'js-cookie' function FooterCookies() { const [show, setShow] = useState(false); // 初始加载检查Cookie,无同意记录则显示弹窗 useEffect(() => { const consent = Cookies.get('cookie_consent'); if (!consent) setShow(true); }, []); const content = { text: '本网站使用Cookie优化体验并分析流量,你可以在我们的', policy: '隐私政策'中了解更多服务细节。' }; // 设置对应类型的同意Cookie,并触发全局更新事件 const setConsent = (type) => { Cookies.set('cookie_consent', type, { expires: 2 }); setShow(false); window.dispatchEvent(new CustomEvent('cookieConsentUpdated', { detail: type })); }; return ( <> {show && ( <div className=" h-auto bg-black/30 fixed bottom-0 text-cus-yellow rounded py-4 px-8 flex justify-evenly items-center z-[100] max75:flex-col max75:px-5 max75:py-3 max30:py-1 max30:px-1.5 max75:items-start"> <div className=" w-85% max70:text-sm flex items-center max75:w-100% max75:items-start max75:mb-3 "> <p className=" text-[13px] pt-1"> {content.text} <span className=" text-[16px] underline cursor-pointer "> {content.policy} </span> </p> </div> <div className=" flex "> <div onClick={() => setConsent('accept_all')} className="border border-cus-yellow text-cus-yellow hover:bg-cus-yellow/60 transition-all hover:text-black w-28 h-80% bg-black/40 cursor-pointer flex flex-col justify-center items-center whitespace-nowrap duration-500 text-lg max75:text-base font-medium mx-2 px-1 py-2 max75:mx-0 max75:py-1 max75:px-0.5 " > 全部接受 </div> <div onClick={() => setConsent('necessary_only')} className="border border-cus-yellow text-cus-yellow hover:bg-cus-yellow/60 transition-all hover:text-black w-36 h-80% bg-black/40 cursor-pointer flex flex-col justify-center items-center whitespace-nowrap duration-500 text-lg max75:text-base font-medium mx-2 px-1 py-[13.76px] max75:mx-0 max75:ml-3 max75:px-0.5 max75:py-[8.75px] " > 仅必要 </div> </div> </div> )} </> ); } export default FooterCookies;
2. 动态加载追踪脚本(修改MyApp.js)
移除固定加载的脚本,改为根据Cookie同意状态动态加载,同时监听同意更新事件:
import '../styles/globals.css'; import 'tailwindcss/tailwind.css'; import { useEffect, useState } from 'react'; import { useRouter } from 'next/router'; import Cookies from 'js-cookie'; import FooterCookies from './path-to-footer-cookies'; // 替换为实际组件路径 import * as gtag from '../lib/gtag'; function MyApp({ Component, pageProps }) { const router = useRouter(); const [consentType, setConsentType] = useState(Cookies.get('cookie_consent')); // 监听同意更新事件,加载对应脚本 useEffect(() => { const handleConsentUpdate = (e) => { setConsentType(e.detail); loadTrackingScripts(e.detail); }; window.addEventListener('cookieConsentUpdated', handleConsentUpdate); // 初始加载时已有同意记录,直接加载脚本 if (consentType) loadTrackingScripts(consentType); return () => window.removeEventListener('cookieConsentUpdated', handleConsentUpdate); }, [consentType]); // 路由变化时仅在全部同意状态下触发GA页面追踪 useEffect(() => { const trackRoute = (url) => { if (consentType === 'accept_all') gtag.pageview(url); }; router.events.on('routeChangeComplete', trackRoute); router.events.on('hashChangeComplete', trackRoute); return () => { router.events.off('routeChangeComplete', trackRoute); router.events.off('hashChangeComplete', trackRoute); }; }, [router.events, consentType]); // 动态加载GTM/GA脚本 const loadTrackingScripts = (type) => { // 加载GTM(必要脚本),避免重复加载 if (!window.gtmLoaded) { const gtmScript = document.createElement('script'); gtmScript.async = true; gtmScript.src = `https://www.googletagmanager.com/gtm.js?id=YOUR-GTM-ID`; // 替换为你的GTM ID document.body.appendChild(gtmScript); window.gtmLoaded = true; window.dataLayer = window.dataLayer || []; window.dataLayer.push({'gtm.start': new Date().getTime(), event:'gtm.js'}); } // 全部同意时加载GA if (type === 'accept_all' && !window.gaLoaded) { const gaScript = document.createElement('script'); gaScript.async = true; gaScript.src = `https://www.googletagmanager.com/gtag/js?id=${gtag.GA_TRACKING_ID}`; document.body.appendChild(gaScript); gaScript.onload = () => { window.dataLayer = window.dataLayer || []; function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', gtag.GA_TRACKING_ID, { page_path: window.location.pathname }); window.gaLoaded = true; }; } }; return ( <> <Component {...pageProps} /> <FooterCookies /> </> ); } export default MyApp;
3. 清理Document.js中的重复脚本
移除Document.js中重复的GTM/GA脚本,仅保留noscript的GTM iframe:
import { Html, Head, Main, NextScript } from 'next/document'; export default function Document() { return ( <Html> <Head> {/* 移除重复的GTM/GA脚本 */} </Head> <body> <noscript dangerouslySetInnerHTML={{ __html: `<iframe src="https://www.googletagmanager.com/ns.html?id=YOUR-GTM-ID" height="0" width="0" style="display:none;visibility:hidden" />`, }} /> <Main /> <NextScript /> </body> </Html> ); }
核心逻辑说明
- 用
cookie_consent字段存储用户同意类型,值为accept_all或necessary_only - GTM作为必要脚本,无论哪种同意都会加载;GA仅在「全部接受」时加载
- 通过自定义事件
cookieConsentUpdated实现组件间状态同步 - 初始加载检查Cookie,避免重复显示同意弹窗
内容的提问来源于stack exchange,提问作者Ermin
相关产品推荐
相关产品推荐

