如何在Marionette LayoutView中动态修改模板?子类如何覆盖父类模板?
嗨,我来帮你搞定这两个Marionette的常见问题,咱们一步步拆解:
Marionette视图默认会继承父类的template属性,这就是为什么你的子类自动加载了父类模板的原因。解决这个问题超直接:
- 显式在子类中定义
template属性:不管父类用的是模板选择器字符串、模板函数还是HTML字符串,只要在子类里重新设置template为你的自定义模板就行。示例代码:
// 父类 Query Advanced const QueryAdvancedView = Marionette.View.extend({ template: '#query-advanced-template' }); // 你的子类,覆盖模板 const CustomQueryView = QueryAdvancedView.extend({ // 指定你的自定义模板选择器 template: '#custom-query-template' });
如果父类用的是旧版本Marionette的templatePath,子类同样可以覆盖这个属性,或者更推荐直接用template(新版本Marionette更倾向于这种写法)。
要是父类的模板是动态生成的(比如用templateFunction),你也可以在子类里重写这个逻辑,返回自己的模板:
const CustomQueryView = QueryAdvancedView.extend({ template: function() { // 这里返回自定义模板内容,比如从DOM获取或动态拼接 return _.template($('#custom-query-template').html()); } });
这样子类就会完全忽略父类的模板,使用你指定的自定义模板了。
LayoutView本质是View的子类,动态修改模板的思路和普通View类似,但要注意regions的处理。这里有两种常用方法:
方法一:直接修改template属性后重新渲染
当你需要在某个事件触发后切换模板时,可以直接更新视图的template属性,再调用render()重新渲染。示例:
const MyLayout = Marionette.LayoutView.extend({ el: '#app-container', template: '#initial-layout-template', regions: { content: '#content-region' }, events: { 'click .switch-template-btn': 'switchTemplate' }, switchTemplate: function() { // 切换到新模板 this.template = '#new-layout-template'; // 重新渲染视图 this.render(); // 若之前regions里有子视图,重新挂载它们(按需选择) this.showChildView('content', this.currentContentChildView); } });
注意:重新渲染会替换原有DOM结构,所以如果之前有子视图在regions里,需要再次调用showChildView重新挂载,同时要确保新模板里包含对应的region选择器。
方法二:使用templateFunction动态返回模板
如果模板切换依赖于视图内部状态,可以用templateFunction动态返回对应模板,每次渲染都会自动根据状态选模板:
const MyLayout = Marionette.LayoutView.extend({ initialize: function(options) { // 初始化状态,可从options传入或设默认值 this.useAlternativeTemplate = options.useAlternative || false; }, // 用函数动态返回模板 template: function() { const templateId = this.useAlternativeTemplate ? '#alt-layout-template' : '#default-layout-template'; return $(templateId).html(); }, // 切换状态的方法 toggleTemplate: function() { this.useAlternativeTemplate = !this.useAlternativeTemplate; // 重新渲染,自动使用新模板 this.render(); // 重新挂载子视图(按需选择) this.showChildView('content', this.currentContentChildView); } });
这种方法适合模板切换依赖内部状态的场景,不用每次手动改template,更新状态后重新渲染就行。
另外,要是你用的是Marionette v3+版本,LayoutView已经和View合并了,但上面的方法依然适用,核心逻辑没变。
内容的提问来源于stack exchange,提问作者John Lippson

