在控制器vm内安装不工作

时间:2016-07-27 13:48:19

标签: mithril.js

老实说,我不确定为什么这不起作用。似乎是一个非常标准的操作。它没有安装组件,没有抛出错误,也没有直接运行它。所有人都在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,但这似乎也不是问题所在。这不是应用程序中唯一的条件挂载,所以这就是我有点难过的原因。

2 个答案:

答案 0 :(得分:3)

通过查看你编写代码的方式,我发现你错过了很多秘银的好处。特别是:

  1. 如果您的'vm'与控制器无法区分,那么您无需为此创建和管理整个单独的对象。特别是当您使用方法来控制本地组件状态时, 是控制器的工作。控制器将一个对象暴露给视图 - 这应该被视为该范围的'vm'。当状态在组件实例之外是相关的时,拥有一个单独的对象来保存模型状态是有用的:你已经在cfg.state中拥有了这个,所以在这种情况下vm是多余的。
  2. 秘银视图有一个config方法,可以在每次绘制后公开真实的DOM元素。您不需要存储对视图元素的引用,因为您可以在此处执行此操作。这是使虚拟DOM库如此吸引人的很大一部分:视图很聪明,您可以直接在其中引入特定于视图的逻辑。
  3. 可以直接从视图中调用组件,视图可以使用条件逻辑来确定是否调用它们。 m.mount只需要初始化Mithril应用程序并定义“顶级”组件;在Mithril代码中,您可以直接通过m函数调用嵌套组件。
  4. 其他一些误解:

    1. 控制器在呈现视图之前执行(一旦执行它,它初始化的属性将作为第一个参数暴露给您的视图函数),因此您无法访问由控制器初始化时查看。
    2. init中的vm功能没有用处。
    3. 以下是对代码的重写,将上述内容考虑在内。我使用简单的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>;
};