【问题标题】:Mithril: how to use multiple root elements?秘银:如何使用多个根元素?
【发布时间】:2020-11-14 00:56:38
【问题描述】:

当使用m.route 时,它下面的所有内容是否都必须使用 Hyperscript 渲染(不包括 JSX)?是否可以将纯 HTML 与使用 Hyperscript 呈现的多个单独部分混合?

假设我有这个 HTML 代码:

<div id="root">
    <div class="header">
        <h3 id="header-text">Header Text</h3>
    </div>
    <div class="container">
        <div id="content"></div>
        <div id="sidebar"></div>
    </div>
    <div id="footer"></div>
</div>

是否可以使用 Mithril 来渲染 HTML 部分的多个部分?像这样(伪代码):

var root = document.getElementById('root');

var header = document.getElementById('header');
var content = document.getElementById('content');
var sidebar = document.getElementById('sidebar');
var footer = document.getElementById('footer');

var HeaderComponent = ...; // to render header text
var ContentComponent = ...; // main page content
var SidebarComponent = ...; // show links, bio, etc.
var Footer = ...; // contact info, etc.

var index = {
    view: function(){
        return [
            {el: header, component: HeaderComponent},
            {el: content, component: ContentComponent},
            {el: sidebar, component: SidebarComponent},
            {el: footer, component: FooterComponent}
        ];
    }
};

m.route(root, '/', {
    '/': index
});

以便在 HTML 代码中呈现 多个单独的部分,而不是仅具有单个根元素?我真的不想在 Mithril 中渲染整个 HTML 骨架模板,像这样:

❌不想要:

// I DON'T want this
m('div#root', [
    m('div.header', [
        m('h3#header-text', m(HeaderComponent))
    ]),
    
    m('div.container', [
        m('div#content', m(ContentComponent)),
        m('div#sidebar', m(SidebarComponent))
    ]),
    
    m('div#footer', m(FooterComponent))
]);

我知道它是可管理的,但我真的希望基本骨架模板位于 .HTML 文件中,以便以后可以无缝包装更多 HTML 标签,例如使用 Bootstrap 类(卡片、容器、行、额外需要包装 div 等)。谢谢:)!

【问题讨论】:

    标签: mithril.js


    【解决方案1】:

    没有什么能阻止您多次使用m.mount 函数,并且可以通过这种方式初始化多个挂载点:

    var count = 0 
    
    m.mount(root1, {
      view: () => 
        m('button', {
          onclick: () => count++,
          textContent: 'Increase count',
        }),
    })
    
    m.mount(root2, {
      view: () =>
        m('p', 'Count: ', count)
    })
    <h1>
      Static page with multiple roots
    </h1>
    
    <div id=root1>
    </div>
    
    <p>
      Intermediary static content
    </p>
    
    <div id=root2>
    </div>
    
    <script src="https://unpkg.com/mithril@2.0.4/mithril.min.js"></script>

    【讨论】:

    • 谢谢!我正在研究这个并得出了相同的结论。感谢您抽出宝贵时间写出来:)
    【解决方案2】:

    使用下面@Barney 的答案,我设法将m.route 用于主要内容,将多个m.mount 用于其他组件:

    var header = document.getElementById('header');
    var content = document.getElementById('content');
    var sidebar = document.getElementById('sidebar');
    var footer = document.getElementById('footer');
    
    var HeaderComponent = ...; // to render header text
    var SidebarComponent = ...; // show links, bio, etc.
    var Footer = ...; // contact info, etc.
    
    // this will be shown under content
    var HomePage = {
        view: function(){
            return m('p', [
                'Lorem ipusom dolor amit ',
                m(m.route.Link, {href: '/about'}, 'About')
            ]);
        }
    };
    var AboutPage = {
        view: function(){
            return m('p', 'This is the About page!');
        }
    };
    
    //// MAIN SOLUTION ////
    var Layout = {
        // oninit is only run once
        oninit: function(){
            m.mount(header, HeaderComponent);
            m.mount(sidebar, SidebarComponent);
            m.mount(footer, FooterComponent);
        },
        
        // run on every route change:
        view: function(vnode){
            return m('div', vnode.children);
        }
    };
    
    m.route(content, '/', {
        // using RouteResolver
        '/': {
            render: function(){
                return m(Layout, m(HomePage));
            },
            onmatch: function(){
                // this will be called on route change, so update your mounted components as needed
                HeaderComponent.title = "Home Page";
            }
        },
        '/about': {
            render: function(){
                return m(Layout, m(AboutPage));
            },
            onmatch: function(){
                HeaderComponent.title = "About Page";
            }
        }
    });
    

    m.route 仅用于&lt;div id="content"&gt;,而所有其他单独的组件(页眉、侧边栏、页脚)都使用m.mount 实例化。我已经用一个用于所有路由的 Layout 组件包装了路由器,因为这允许我初始化和安装单独的组件,这些组件将在路由更改时保留并且不受主路由器的影响。必须修改路由器以使用RouteResolver 以实现更多控制和灵活性。

    注意事项:

    • 每个应用程序只允许单个m.route,但允许多个m.mount
    • same 组件分配了多个路由(在本例中为布局)时,子树不会被删除和从头开始重建——它只会被区分和更新 @ 987654323@。这样,我们可以使用 Layout 组件的 oninit 生命周期钩子来挂载我们其他独立的组件,因为 oninit 只会被调用一次。
    • 我们必须为m.route 中的路由使用RouteResolver,这使我们可以更好地控制如何 应该渲染路由,并且我们还可以得到像onmatch 这样的钩子,它会在之前触发路由已初始化——这是根据需要更新已安装组件的理想场所!

    【讨论】:

    • 很高兴我能帮上忙!这种使用m.routem.mount 的模式非常强大。令人鼓舞的是,看到 Mithrils 的灵活性被用于寻找映射到更全面的应用程序模型的优雅解决方案 :)
    猜你喜欢
    • 2019-10-21
    • 1970-01-01
    • 2019-08-06
    • 1970-01-01
    • 2020-11-16
    • 2019-12-23
    • 1970-01-01
    • 2015-12-03
    • 1970-01-01
    相关资源
    最近更新 更多