Guide till implementering av samtycke till cookies och SPA
Förstå utmaningen
Enkeltsidiga applikationer (SPA) byggda med React, Vue, Angular eller andra ramverk innebär unika utmaningar för TermsFeed Cookie Consent eftersom:
- Ingen siduppdatering. Sidan laddas inte om som klassiska webbsidor.
- Dynamiskt innehåll. Innehållet laddas dynamiskt utan att DOMContentLoaded utlöses igen.
- Ruttändringar. Navigering sker via JavaScript, inte genom traditionella sidladdningar.
- Statushantering. Samtyckesstatusen måste bestå vid ruttändringar.
Lösning: Ladda om vid navigering
Problem
"Jag har en React SPA och cookie-bannern visas bara vid den första sidladdningen. När användare navigerar till andra sidor visas inte bannern igen om de inte har gjort ett val. Dessutom, om de accepterar cookies på en sida, laddas inte skript på efterföljande sidor förrän en fullständig uppdatering har skett."
Lösning
När du implementerar TermsFeed Cookie Consent i en SPA måste du:
- Initialisera samtycket vid första laddningen.
- Upptäcka ruttändringar.
- Ladda om bannern vid behov.
- Kontrollera samtyckesstatusen på nytt.
React-implementering
Steg 1: Skapa en komponent för samtycke till cookies
// 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;
Steg 2: Lägg till i appkomponenten
// 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
Steg 1: Skapa plugin-programmet Cookie Consent
// 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);
});
}
}
};
Steg 2: Använd i huvudappen
// 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');
Steg 3: Skapa appkomponenten
<!-- 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
Steg 1: Skapa tjänsten för samtycke till cookies
// 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();
}
}
}
Steg 2: Initialisera i appkomponenten
// 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);
});
}
}
Vanliga problem med SPA och samtycke till cookies
Problem 1: Bannern visas inte igen vid navigering
Problem
Användaren navigerar utan att göra något val, bannern försvinner.
Lösning
Kontrollera om samtycke gavs vid ruttändring.
// 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: Skript laddas inte efter samtycke på nya rutter
Problem
"Användaren accepterar cookies, navigerar till en annan sida i min React-app, men Google Analytics spårar inte den nya sidvisningen."
Lösning
Använd återanrop för att spåra sidvisningar vid varje ruttä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: Flera bannerinstanser visas
Problem
Bannern visas flera gånger när man navigerar snabbt.
Lösning
Använd en guard för att förhindra flera initialiseringar
// Use a guard to prevent multiple initializations
let isInitialized = false;
const initCookieConsent = () => {
if (isInitialized) return;
isInitialized = true;
cookieconsent.run({ / config / });
};
Öppna inställningscentret programmatiskt
För SPA:er kanske du vill öppna inställningarna utan en statisk knapp:
// 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>