使用Rails 7 + Stimulus.js实现滚动事件时跨页面报错求助
问题原因与修复方案
问题根源
- 滚动事件监听器绑定在
window上,Turbo Drive页面切换时未移除,导致其他页面滚动时仍会执行回调。 - 非目标页面不存在
target_title和scroll_header元素,回调中直接调用它们的方法会触发Cannot read properties of null错误。
修复方案(推荐使用Stimulus Targets规范)
修改控制器代码,添加事件清理逻辑并检查元素存在性:
import { Controller } from '@hotwired/stimulus' export default class extends Controller { // 定义Stimulus目标,对应HTML中的data-target属性 static targets = ['title', 'scrollHeader'] connect() { // 保存滚动处理函数引用并绑定this,方便后续移除 this.scrollHandler = this.handleScroll.bind(this) window.addEventListener("scroll", this.scrollHandler) } // 页面切换时移除事件监听器,清理资源 disconnect() { window.removeEventListener("scroll", this.scrollHandler) } handleScroll() { // 先检查目标元素是否存在,不存在则直接返回 if (!this.hasTitleTarget || !this.hasScrollHeaderTarget) return const clientHeight = this.titleTarget.getBoundingClientRect().top; if (-100 > clientHeight) { this.scrollHeaderTarget.classList.add('!block') } else { this.scrollHeaderTarget.classList.remove('!block') } } }
对应HTML需要添加data-target属性(替换your-controller-name为你的控制器名称):
<!-- 目标标题元素 --> <h1 id="target_title" data-controller="your-controller-name" data-your-controller-name-title-target>标题内容</h1> <!-- 滚动头部元素 --> <div id="scroll_header" data-your-controller-name-scroll-header-target>滚动头部内容</div>
简易修复版本(不使用Targets)
如果不想改动HTML结构,也可以直接修改控制器:
import { Controller } from '@hotwired/stimulus' export default class extends Controller { connect() { // 定义滚动处理函数并保存引用 this.scrollHandler = () => { const targetTitle = document.getElementById("target_title"); const scrollHeader = document.getElementById('scroll_header'); // 检查元素是否存在,避免报错 if (!targetTitle || !scrollHeader) return; const clientHeight = targetTitle.getBoundingClientRect().top; if (-100 > clientHeight) { scrollHeader.classList.add('!block') } else { scrollHeader.classList.remove('!block') } } window.addEventListener("scroll", this.scrollHandler); } // 清理事件监听器 disconnect() { window.removeEventListener("scroll", this.scrollHandler); } }
内容的提问来源于stack exchange,提问作者y-tom
相关产品推荐
相关产品推荐

