老实说,我不确定为什么这不起作用。似乎是一个非常标准的操作。它没有安装组件,没有抛出错误,也没有直接运行它。所有人都在cfg.AddToCart.vm.addToCart()
cfg.AddToCart = {
vm: {
init() {
return;
},
addToCart() {
let parent = document.getElementById('atc-error');
let errEl = document.getElementById('atc-error-component');
if(cfg.state.selections.SIZE) {
m.mount(errEl, null);
} else {
let component = new cfg.selectComponent(cfg.Options, cfg.optionsView);
m.mount(errEl, component);
cfg.util.toggleSlide(parent);
}
}
},
controller() {
cfg.AddToCart.vm.init();
}
};
cfg.AddToCart.view = function() {
return <div id="add-to-cart-container">
<div id="atc-error">
<span>Select a size and add to cart again.</span>
<div id="atc-error-component"></div>
</div>
<div class="small-12 columns">
<button class="large button alert"
onclick={() => {
this.vm.addToCart();
}}>
Add To Cart
</button>
</div>
</div>;
};
我们在整个应用程序中多次使用new cfg.selectComponent(cfg.Options, cfg.optionsView)
组件,因此它不是错误。 #atc-error
设置为display:none
,但这似乎也不是问题所在。这不是应用程序中唯一的条件挂载,所以这就是我有点难过的原因。
答案 0 :(得分:3)
通过查看你编写代码的方式,我发现你错过了很多秘银的好处。特别是:
cfg.state
中拥有了这个,所以在这种情况下vm
是多余的。config
方法,可以在每次绘制后公开真实的DOM元素。您不需要存储对视图元素的引用,因为您可以在此处执行此操作。这是使虚拟DOM库如此吸引人的很大一部分:视图很聪明,您可以直接在其中引入特定于视图的逻辑。m.mount
只需要初始化Mithril应用程序并定义“顶级”组件;在Mithril代码中,您可以直接通过m
函数调用嵌套组件。其他一些误解:
init
中的vm
功能没有用处。以下是对代码的重写,将上述内容考虑在内。我使用简单的Mithril而不是MSX来避免编译,但你可以轻松地将其转换回来:
// Determine what your external dependencies are
const { state, selectComponent } = cfg
// Define the component
const AddToCart = {
// No need for a separate VM: it is identical in purpose & function to the controller
controller : function(){
// No need to store element references in the model: those are the view's concern.
// Keep the VM / ctrl size to a minimum by only using it to deal with state
this.addToCart = () => {
if( state.selections.SIZE )
this.showSize = false
else {
this.showSize = true
this.slideToErr = true
}
}
},
view : ctrl =>
m( '#add-to-cart-container',
m( '#atc-error', {
// Config exposes the element and runs after every draw.
config : el => {
// Observe state, and affect the view accordingly:
if( ctrl.slideToErr ){
el.scrollIntoView()
// Reset the state flag
ctrl.slideToErr = false
}
}
},
m( 'span', 'Select a size and add to cart again.' ),
// This is an and condition, ie 'if A, then B
ctrl.showSize
// This is how you invoke a component from within a view
&& m( selectComponent )
),
m( '.small-12 columns',
m( 'button.large button alert', {
onclick : () =>
ctrl.addToCart();
},
'Add To Cart'
)
)
)
}
答案 1 :(得分:0)
通过将其更改为此模式来工作:
cfg.AddToCart = {
vm: {
init() {
this.errorComponent = m.prop();
},
addToCart() {
let parent = document.getElementById('atc-error');
let errEl = document.getElementById('atc-error-component');
if(cfg.state.selections.SIZE) {
cfg.util.toggleSlide(parent);
setTimeout(() => {
this.errorComponent(null);
}, 400);
} else {
let component = new cfg.selectComponent(cfg.Options, cfg.optionsView);
this.errorComponent(component);
setTimeout(() => {
cfg.util.toggleSlide(parent);
}, 100);
}
}
},
controller() {
cfg.AddToCart.vm.init();
}
};
cfg.AddToCart.view = function() {
return <div id="add-to-cart-container">
<div id="atc-error">
<span>Select a size and add to cart again.</span>
<div id="atc-error-component" class="row">
{this.vm.errorComponent() ? m.component(this.vm.errorComponent()) : ''}
</div>
</div>
<div class="small-12 columns">
<button class="large button alert"
onclick={() => {
this.vm.addToCart();
}}>
Add To Cart
</button>
</div>
</div>;
};