我正在尝试在
BootStrap
中实现 Symfony
的颜色切换器。
我使用
BootStrap
添加了 AssetMapper
,一切正常。
然后,我将颜色切换器从
BootStrap
的示例页面复制到 twig
模板中,以及它的 CSS
和 JS
代码(如 assets
)。
我有一个
Controller
路由到 /
,其模板包括颜色切换器模板。
当我在浏览器中打开页面时,一切似乎都正常工作,但是,如果我在该页面中添加链接(指向其自身或其他页面),则无关紧要 - 颜色切换器将无法在新页面中工作,除非我按
F5
或以其他方式重新加载页面。
我发现初始化颜色切换器的
JavaScript
代码在初始页面加载或重新加载时运行,但是当通过单击链接更改页面时,它不会在目标页面上再次执行。
我尝试添加类似的内容:
if (document.readyState !== 'loading') {
console.log('document is already ready, just execute code here');
initThemeSwitcher();
} else {
document.addEventListener('DOMContentLoaded', function () {
console.log('document was not ready, place code here');
initThemeSwitcher();
});
}
再次,控制台只有在初始页面加载或强制重新加载时才会运行此代码。
所以我的问题是:为什么此代码仅在从服务器获取文件时运行,而不是通过单击链接移动到不同页面(或同一页面)时运行?
编辑刚刚注意到
Stimulus Controllers
发生了同样的事情:它们在页面加载时工作,但当我点击链接时,它们停止工作,直到我重新加载页面(例如键盘上的F5
)
我仍然不确定为什么将
EventListener
添加到 DOMContentLoaded
只适用于加载的第一页,但我设法找到了解决方法。
我没有使用
bootstrap
网站上的“原样”代码,而是用它制作了 Stimulus Controller
- 对代码进行了一些更改,这样就不会使用 DOMContentLoaded
。
我最终得到以下
Stimulus Controller
:
import { Controller } from '@hotwired/stimulus';
export default class extends Controller {
'use strict'
connect() {
const getStoredTheme = () => localStorage.getItem('theme')
const setStoredTheme = theme => localStorage.setItem('theme', theme)
const getPreferredTheme = () => {
const storedTheme = getStoredTheme()
if (storedTheme) {
return storedTheme
}
return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'
}
const setTheme = theme => {
if (theme === 'auto') {
document.documentElement.setAttribute('data-bs-theme', (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'))
} else {
document.documentElement.setAttribute('data-bs-theme', theme)
}
}
setTheme(getPreferredTheme())
const showActiveTheme = (theme, focus = false) => {
const themeSwitcher = document.querySelector('#bd-theme')
if (!themeSwitcher) {
return
}
const themeSwitcherText = document.querySelector('#bd-theme-text')
const activeThemeIcon = document.querySelector('.theme-icon-active use')
const btnToActive = document.querySelector(`[data-bs-theme-value="${theme}"]`)
const svgOfActiveBtn = btnToActive.querySelector('svg use').getAttribute('href')
document.querySelectorAll('[data-bs-theme-value]').forEach(element => {
element.classList.remove('active')
element.setAttribute('aria-pressed', 'false')
})
btnToActive.classList.add('active')
btnToActive.setAttribute('aria-pressed', 'true')
activeThemeIcon.setAttribute('href', svgOfActiveBtn)
const themeSwitcherLabel = `${themeSwitcherText.textContent} (${btnToActive.dataset.bsThemeValue})`
themeSwitcher.setAttribute('aria-label', themeSwitcherLabel)
if (focus) {
themeSwitcher.focus()
}
}
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => {
const storedTheme = getStoredTheme()
if (storedTheme !== 'light' && storedTheme !== 'dark') {
setTheme(getPreferredTheme())
}
})
document.querySelectorAll('[data-bs-theme-value]').forEach(toggle => {
toggle.addEventListener('click', () => {
const theme = toggle.getAttribute('data-bs-theme-value')
setStoredTheme(theme)
setTheme(theme)
showActiveTheme(theme, true)
})
})
}
}