如何为Store模型添加控制器本地属性?
符合Ember Way的解决方案:路由专属选中状态管理
嘿,这个问题我之前也踩过坑!直接给Store里的模型加selected属性真的容易出问题——因为Store管理的模型是全局共享的,你在当前路由加的属性,其他地方用到同一个模型时也会带上,完全不符合你要的“仅作用于特定route/controller”的需求。下面给你两个最地道的Ember解决方案:
方案一:用控制器维护选中状态
控制器是路由专属的,它的状态只会在当前路由生效,切换路由后就会销毁,刚好适合这种场景。我们不需要修改Store里的Group模型,只在控制器里单独维护选中状态:
控制器代码
import Controller from '@ember/controller'; import { tracked } from '@glimmer/tracking'; export default class GroupsController extends Controller { // 用Set来存储选中的group ID,避免重复 @tracked selectedGroupIds = new Set(); // 切换单个group的选中状态 toggleGroupSelection(group) { if (this.selectedGroupIds.has(group.id)) { this.selectedGroupIds.delete(group.id); } else { this.selectedGroupIds.add(group.id); } } // 辅助方法:判断某个group是否被选中(模板里也可以直接写判断逻辑) isGroupSelected(group) { return this.selectedGroupIds.has(group.id); } }
模板代码
在路由对应的模板里,绑定点击事件和选中样式:
{{#each @model as |group|}} <div class="{{if (this.isGroupSelected group) 'bg-blue-100 selected' ''}}" {{on "click" (fn this.toggleGroupSelection group)}} > {{group.name}} </div> {{/each}}
这个方案的核心是把UI状态和模型数据完全分离,模型只负责存储从后端获取的原始数据,选中状态由控制器本地管理,绝对不会污染全局的Store模型。
方案二:组件封装选中状态(更推荐组件化场景)
如果你的分组列表是可复用的,或者逻辑比较复杂,把选中状态封装到组件里会更符合Ember的组件化思想。组件的状态也是完全隔离的,不会影响其他路由或组件:
组件代码(app/components/group-list.js)
import Component from '@glimmer/component'; import { tracked } from '@glimmer/tracking'; export default class GroupListComponent extends Component { @tracked selectedGroupIds = new Set(); toggleSelection(group) { this.selectedGroupIds.has(group.id) ? this.selectedGroupIds.delete(group.id) : this.selectedGroupIds.add(group.id); } isSelected(group) { return this.selectedGroupIds.has(group.id); } }
组件模板(app/components/group-list.hbs)
{{#each @groups as |group|}} <div class="{{if (this.isSelected group) 'selected' ''}}" {{on "click" (fn this.toggleSelection group)}} > {{group.name}} </div> {{/each}}
在路由模板中使用组件
{{!-- 把控制器里的groups模型传给组件 --}} <GroupList @groups={{@model}} />
为什么不直接修改Store模型?
Ember的Store模型是全局单例的,同一个ID的模型在整个应用里只有一个实例。如果你给模型加了selected属性,其他路由或组件用到这个模型时,也会看到这个属性,很容易导致状态混乱——比如你在A路由选中了某个group,切换到B路由后,同一个group居然还是“选中”状态,这显然不是你想要的。
所以,把UI状态(比如选中、展开)和业务数据(比如group的名称、ID)分开管理,才是最符合Ember Way的做法!
内容的提问来源于stack exchange,提问作者rjoxford
相关产品推荐
相关产品推荐

