Vue.js中如何通过点击事件停止子组件内的滚动ticker动画?
你的需求很明确:点击新闻项后,要停止横向滚动的ticker动画,同时把它改成和普通菜单一样的样式。因为Vue的单向数据流规则,子组件不能直接修改prop,所以咱们得从父组件控制状态这个方向入手——刚好你已经在父组件里用readNewsList跟踪已读状态了,完全可以利用这个来实现需求。
第一步:让父组件动态控制itemType
你现在给所有新闻项都固定传了itemType="news",咱们改成根据已读状态动态传值:如果新闻已经被读过,就传空字符串,否则传"news"。这样子组件会自动切换显示普通文本,动画自然就停了。
修改MainMenu.vue里的组件调用:
<MainMenuItem v-for="news in newsList" :key="news.id" @click="openNews(news)" :title="news.title" :itemType="readNewsList[news.id] ? '' : 'news'" <!-- 改成动态绑定 --> :class="{ readLink: readNewsList[news.id] }" menuIcon="contactless" />
这样一来,用户点击新闻后,readNewsList更新,子组件的itemType自动变成空,原来的ticker容器会被隐藏,换成普通文本容器,动画直接停止,同时readLink类也会生效,字体权重改成500,完美契合你的需求。
第二步:可选的精细动画控制(如果不想切换容器)
要是你不想切换容器,只想暂停动画而保留布局,那可以在子组件里通过动态类来控制动画状态。
先给子组件加个isRead的prop
在父组件里传递已读状态:
<MainMenuItem ... :isRead="readNewsList[news.id]" />
子组件接收这个prop:
props: { // 其他props不变... isRead: { type: Boolean, default: false } }
然后修改子组件的样式和模板
给ticker-item加个暂停动画的类:
._ticker-item display: inline-block padding-left: 100% animation: ticker 8s linear infinite &.ticker-paused animation-play-state: paused
模板里绑定这个类:
<div v-if="itemType === 'news'" class="_ticker"> <div class="ellipsis _ticker-item" :class="{ 'ticker-paused': isRead }">{{ title }}</div> </div>
这样已读之后,动画会暂停,同时readLink类也会修改字体权重,效果也能达到。
为啥不推荐子组件自己存状态?
虽然你可以在子组件里定义data来跟踪是否被点击,但这样状态就分散了——你已经在父组件的readNewsList里管理已读状态了,统一在父组件控制更符合Vue的单向数据流原则,后续维护起来也更方便,不会出现状态不一致的问题。
最后验证效果
点击新闻后,openNews会更新seenNewsPosts,readNewsList跟着变化,然后:
- 子组件的
itemType变成空(或者动画被暂停) readLink类自动加上,字体权重降低- 滚动动画停止,和普通菜单样式一致
内容的提问来源于stack exchange,提问作者LovelyAndy

