Vejledning til implementering af cookie-samtykke og SPA
Forstå udfordringen
Single Page Applications (SPA'er), der er bygget med React, Vue, Angular eller andre rammer, udgør unikke udfordringer for TermsFeed Cookie Consent, fordi:
- Ingen sideopdatering. Siden genindlæses ikke som klassiske websider.
- Dynamisk indhold. Indholdet indlæses dynamisk uden at udløse DOMContentLoaded igen.
- Ruteændringer. Navigationen sker via JavaScript, ikke via traditionelle sideindlæsninger.
- Statusstyring. Samtykkestatus skal bevares på tværs af ruteændringer.
Løsning: Genindlæs ved navigation
Problem
"Jeg har en React SPA, og cookie-banneret vises kun ved den første sideindlæsning. Når brugerne navigerer til andre sider, vises banneret ikke igen, hvis de ikke har truffet et valg. Desuden indlæses scripts ikke på efterfølgende sider, hvis de accepterer cookies på én side, før der foretages en fuld opdatering."
Løsning
Når du implementerer TermsFeed Cookie Consent i en SPA, skal du:
- Initialisere samtykke ved første indlæsning.
- Registrere ruteændringer.
- Genindlæse banneret, hvis det er nødvendigt.
- Kontrollere samtykkestatus igen.
React-implementering
Trin 1: Opret en Cookie Consent-komponent
// CookieConsent.js
import { useEffect } from 'react';
import { useLocation } from 'react-router-dom';
const CookieConsent = () => {
const location = useLocation();
useEffect(() => {
// Load TermsFeed script if not already loaded
if (!window.cookieconsent) {
const script = document.createElement('script');
script.src = '//www.termsfeed.com/public/cookie-consent/4.2.0/cookie-consent.js';
script.charset = 'UTF-8';
script.onload = () => initializeCookieConsent();
document.head.appendChild(script);
} else {
// Script already loaded, just check if banner needs to be shown
checkBannerState();
}
}, []); // Run once on mount
useEffect(() => {
// Check banner state on route change
if (window.cookieconsent) {
checkBannerState();
}
}, [location]); // Run on every route change
const initializeCookieConsent = () => {
if (window.cookieconsent && typeof window.cookieconsent.run === 'function') {
window.cookieconsent.run({
"notice_banner_type": "headline",
"consent_type": "express",
"palette": "light",
"language": "en",
"website_name": "My SPA",
"website_privacy_policy_url": "https://mysite.com/privacy",
"open_preferences_center_selector": "#changePreferences",
"page_load_consent_levels": ["strictly-necessary"],
"callbacks": {
"scripts_specific_loaded": (level) => {
console.log("Scripts loaded for: " + level);
// Re-initialize any components that need tracking
if (level === 'tracking') {
reinitializeAnalytics();
}
}
}
});
}
};
const checkBannerState = () => {
// Check if user has already made a consent choice
const consentCookie = getCookie('cookie_consent_level');
if (!consentCookie) {
// No consent yet, banner should be visible
// No action needed - banner will show automatically
}
};
const getCookie = (name) => {
const value = ; ${document.cookie};
const parts = value.split(; ${name}=);
if (parts.length === 2) return parts.pop().split(';').shift();
};
const reinitializeAnalytics = () => {
// Re-run any analytics initialization needed
if (window.gtag) {
window.gtag('config', 'G-XXXXXXXXXX', {
'page_path': location.pathname
});
}
};
return null; // This component doesn't render anything
};
export default CookieConsent;
Trin 2: Føj til App-komponenten
// App.js
import React from 'react';
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
import CookieConsent from './components/CookieConsent';
import Home from './pages/Home';
import About from './pages/About';
function App() {
return (
<Router>
<CookieConsent />
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
</Routes>
{/ Preferences button /}
<button id="changePreferences" style={{
position: 'fixed',
bottom: '20px',
right: '20px',
zIndex: 9999
}}>
Cookie Settings
</button>
<noscript>
Free cookie consent management tool by <a href="https://www.termsfeed.com/">TermsFeed</a>
</noscript>
</Router>
);
}
export default App;
Vue.js-implementering
Trin 1: Opret plugin til cookie-samtykke
// plugins/cookieConsent.js
export default {
install(app, options) {
// Load script
const loadCookieConsent = () => {
if (window.cookieconsent) return Promise.resolve();
return new Promise((resolve, reject) => {
const script = document.createElement('script');
script.src = '//www.termsfeed.com/public/cookie-consent/4.2.0/cookie-consent.js';
script.charset = 'UTF-8';
script.onload = () => resolve();
script.onerror = () => reject();
document.head.appendChild(script);
});
};
// Initialize
const initCookieConsent = () => {
if (window.cookieconsent && typeof window.cookieconsent.run === 'function') {
window.cookieconsent.run({
"notice_banner_type": "headline",
"consent_type": "express",
"palette": "light",
"language": "en",
"website_name": options.websiteName || "My Vue SPA",
"website_privacy_policy_url": options.privacyUrl || "#",
"open_preferences_center_selector": "#changePreferences",
"page_load_consent_levels": ["strictly-necessary"]
});
}
};
// Make available globally
app.config.globalProperties.$cookieConsent = {
load: loadCookieConsent,
init: initCookieConsent
};
// Auto-initialize on mount
if (typeof window !== 'undefined') {
loadCookieConsent().then(() => {
document.addEventListener('DOMContentLoaded', initCookieConsent);
});
}
}
};
Trin 2: Brug i hovedappen
// main.js
import { createApp } from 'vue';
import { createRouter, createWebHistory } from 'vue-router';
import App from './App.vue';
import cookieConsentPlugin from './plugins/cookieConsent';
const router = createRouter({
history: createWebHistory(),
routes: [
{ path: '/', component: () => import('./views/Home.vue') },
{ path: '/about', component: () => import('./views/About.vue') }
]
});
const app = createApp(App);
app.use(router);
app.use(cookieConsentPlugin, {
websiteName: 'My Vue App',
privacyUrl: 'https://mysite.com/privacy'
});
app.mount('#app');
Trin 3: Opret app-komponenten
<!-- App.vue -->
<template>
<div id="app">
<router-view />
<button id="changePreferences" class="cookie-settings-btn">
Cookie Settings
</button>
<noscript>
Free cookie consent management tool by
<a href="https://www.termsfeed.com/">TermsFeed</a>
</noscript>
</div>
</template>
<script>
export default {
name: 'App',
mounted() {
// Watch for route changes
this.$router.afterEach((to, from) => {
// Check if consent banner needs to be re-shown
this.checkConsentState();
});
},
methods: {
checkConsentState() {
const consentCookie = document.cookie
.split('; ')
.find(row => row.startsWith('cookie_consent_level='));
if (!consentCookie) {
console.log('No consent given yet');
}
}
}
};
</script>
<style>
.cookie-settings-btn {
position: fixed;
bottom: 20px;
right: 20px;
z-index: 9999;
padding: 10px 20px;
background: #007bff;
color: white;
border: none;
border-radius: 5px;
cursor: pointer;
}
</style>
Angular-implementering
Trin 1: Opret Cookie Consent-tjenesten
// services/cookie-consent.service.ts
import { Injectable } from '@angular/core';
import { Router, NavigationEnd } from '@angular/router';
import { filter } from 'rxjs/operators';
declare global {
interface Window {
cookieconsent: any;
}
}
@Injectable({
providedIn: 'root'
})
export class CookieConsentService {
private scriptLoaded = false;
constructor(private router: Router) {}
initialize(): Promise<void> {
return this.loadScript().then(() => {
this.initializeConsent();
this.watchRouteChanges();
});
}
private loadScript(): Promise<void> {
if (this.scriptLoaded || window.cookieconsent) {
return Promise.resolve();
}
return new Promise((resolve, reject) => {
const script = document.createElement('script');
script.src = '//www.termsfeed.com/public/cookie-consent/4.2.0/cookie-consent.js';
script.charset = 'UTF-8';
script.onload = () => {
this.scriptLoaded = true;
resolve();
};
script.onerror = () => reject();
document.head.appendChild(script);
});
}
private initializeConsent(): void {
if (window.cookieconsent && typeof window.cookieconsent.run === 'function') {
window.cookieconsent.run({
notice_banner_type: 'headline',
consent_type: 'express',
palette: 'light',
language: 'en',
website_name: 'My Angular App',
website_privacy_policy_url: 'https://mysite.com/privacy',
open_preferences_center_selector: '#changePreferences',
page_load_consent_levels: ['strictly-necessary'],
callbacks: {
scripts_specific_loaded: (level: string) => {
console.log('Scripts loaded for:', level);
this.handleConsentUpdate(level);
}
}
});
}
}
private watchRouteChanges(): void {
this.router.events.pipe(
filter(event => event instanceof NavigationEnd)
).subscribe(() => {
// Check consent state on route change
this.checkConsentState();
});
}
private checkConsentState(): void {
const consentCookie = this.getCookie('cookie_consent_level');
if (!consentCookie) {
console.log('No consent given yet');
}
}
private handleConsentUpdate(level: string): void {
// Handle consent updates
if (level === 'tracking') {
this.initializeAnalytics();
}
}
private initializeAnalytics(): void {
// Re-initialize analytics on consent
if ((window as any).gtag) {
(window as any).gtag('config', 'G-XXXXXXXXXX', {
page_path: this.router.url
});
}
}
private getCookie(name: string): string | null {
const value = ; ${document.cookie};
const parts = value.split(; ${name}=);
if (parts.length === 2) {
return parts.pop()?.split(';').shift() || null;
}
return null;
}
openPreferences(): void {
if (window.cookieconsent && typeof window.cookieconsent.openPreferencesCenter === 'function') {
window.cookieconsent.openPreferencesCenter();
}
}
}
Trin 2: Initialiser i app-komponenten
// app.component.ts
import { Component, OnInit } from '@angular/core';
import { CookieConsentService } from './services/cookie-consent.service';
@Component({
selector: 'app-root',
template:
<router-outlet></router-outlet>
<button id="changePreferences" class="cookie-settings-btn">
Cookie Settings
</button>
<noscript>
Free cookie consent management tool by
<a href="https://www.termsfeed.com/">TermsFeed</a>
</noscript>
,
styles: [
.cookie-settings-btn {
position: fixed;
bottom: 20px;
right: 20px;
z-index: 9999;
padding: 10px 20px;
background: #007bff;
color: white;
border: none;
border-radius: 5px;
cursor: pointer;
}
]
})
export class AppComponent implements OnInit {
constructor(private cookieConsentService: CookieConsentService) {}
ngOnInit(): void {
this.cookieConsentService.initialize().catch(error => {
console.error('Failed to initialize cookie consent:', error);
});
}
}
Almindelige problemer med SPA og cookie-samtykke
Problem 1: Banneren vises ikke igen ved navigation
Problem
Brugeren navigerer uden at træffe et valg, og banneret forsvinder.
Løsning
Kontroller, om der blev givet samtykke ved skift af rute.
// Check if consent was given on route change
router.afterEach(() => {
const hasConsent = getCookie('cookie_consent_level');
if (!hasConsent) {
// Banner should be visible - it will show automatically
// No manual action needed if properly configured
}
});
Problem 2: Scripts indlæses ikke efter samtykke på nye ruter
Problem
"Brugeren accepterer cookies, navigerer til en anden side i min React-app, men Google Analytics sporer ikke den nye sidevisning."
Løsning
Brug callbacks til at spore sidevisninger ved hvert ruteændring.
// In your callback
"callbacks": {
"scripts_specific_loaded": (level) => {
if (level === 'tracking' && window.gtag) {
// Track page view on every route change
router.afterEach((to) => {
gtag('config', 'G-XXXXXXXXXX', {
'page_path': to.path
});
});
}
}
}
Problem 3: Der vises flere bannerinstanser
Problem
Banneret vises flere gange, når man navigerer hurtigt.
Løsning
Brug en guard til at forhindre flere initialiseringer
// Use a guard to prevent multiple initializations
let isInitialized = false;
const initCookieConsent = () => {
if (isInitialized) return;
isInitialized = true;
cookieconsent.run({ / config / });
};
Åbn Indstillingscenter programmatisk
For SPA'er kan du åbne indstillinger uden en statisk knap:
// Method 1: Using the openPreferencesCenter() method
const openPreferences = () => {
if (window.cookieconsent && typeof window.cookieconsent.openPreferencesCenter === 'function') {
window.cookieconsent.openPreferencesCenter();
} else {
console.error('Cookie consent not initialized');
}
};
// In React
<button onClick={openPreferences}>Change Cookie Settings</button>
// In Vue
<button @click="openPreferences">Change Cookie Settings</button>
// In Angular
<button (click)="openPreferences()">Change Cookie Settings</button>