2016-12-20 19 views
2

私は2つの子、ヘッダーと内容を含む固定高さdiv(body)を持っています。ヘッダーの高さはボタンをクリックすると変化し、コンテンツの高さはボディの残りの部分を埋めるように自動調整されます。今問題は、ヘッダーとコンテンツdivがレンダリングされた後に新しいヘッダーの高さが計算されるため、コンテンツのdivの高さはボタンのクリック時に更新されません。ミスリル:あるDOM要素を別のDOM要素のベースにします

return m('.body', { 
    style: { 
    height: '312px' 
    } 
}, [ 
    m('.header', /* header contents */), 
    m('.content', { 
    style: { 
     height: (312 - this._viewModel._headerHeight()) + 'px' 
    } 
    }, /* some contents */) 
]) 

headerHeight関数は、ヘッダーの高さを計算し、変更を適用します。しかし、レンダリング後に新しい高さが計算されるため、コンテンツの高さの計算にすぐには適用されません。常に遅れがあります。

これを修正するにはどうすればよいですか?

答えて

2

これは、書き込み可能なDOMプロパティが他の読み込み可能なDOMプロパティから派生した動的なDOMレイアウトを扱う場合、定期的な問題です。これは、Mithrilのような宣言的な仮想DOM慣用句では、すべてのビュー関数がUIステートの自己完結型スナップショットでなければならないという前提に基づいているため、特に難しいです。

3つの選択肢があります.Mithrilのビュー外でDOMを直接操作して仮想DOMイディオムから抜け出すことができます。または、コンポーネントをモデル化して「2回パス」で操作できます。ヘッダー要素への潜在的な変更は、ヘッダーを更新するための1回の描画と、それに応じて内容を更新する2回目の描画とをもたらす。また、純粋なCSSソリューションを手に入れることもできます。

1つのプロパティを更新するだけで済むので、最初のオプションの方がよいでしょう。 config関数を使用すると、描画ごとにビューの後に実行されるカスタム機能を記述できます。

return m('.body', { 
    style: { 
    height: '312px' 
    }, 

    config : function(el){ 
    el.lastChild.style.height = (312 - el.firstChild.offsetHeight) + 'px' 
    } 
}, [ 
    m('.header', /* header contents */), 
    m('.content', /* some contents */) 
]) 

それが直接DOM操作を回避し、ビューによって読み取られ、適用され、モデル内のすべてのステートフルデータを保持しますので、2番目のオプションは、仮想DOMの哲学の観点から、より慣用です。このアプローチは、ビューがレンダリングされるときにビューモデル全体を検査することができるため、多数の動的なDOM関連プロパティがある場合に便利です。特に、シナリオでは、さらに複雑で非効率です。

controller : function(){ 
    this.headerHeight = 0 
}, 
view : function(ctrl){ 
    return m('.body', { 
    style: { 
     height: '312px' 
    } 
    }, [ 
    m('.header', { 
     config : function(el){ 
     if(el.offsetHeight != ctrl.headerHeight){ 
     ctrl.headerHeight = el.offsetHeight 

     window.requestAnimationFrame(m.redraw) 
     } 
    }, /* header contents */), 
    m('.content', { 
     style : { 
     height : (312 - ctrl.headerHeight) + 'px' 
     } 
    }, /* some contents */) 
    ]) 
} 

第3のオプション - depending on which browsers you need to support - は、CSS flexbox moduleを使用することです。

return m('.body', { 
    style: { 
    height: '312px', 
    display: 'flex', 
    flexDirection: 'column' 
    } 
}, [ 
    m('.header', { 
    style : { 
     flexGrow: 1, 
     flexShrink: 0 
    } 
    }, /* header contents */), 
    m('.content', { 
    style : { 
     flexGrow: 0, 
     flexShrink: 1 
    } 
    }, /* some contents */) 
]) 

このように、あなたは、単にコンテナがヘッダはその内容に合わせて、決して縮小に成長する必要があること、及び内容が縮小する必要があることが、成長することはありません、フレキシボックスであることを述べることができます。

+2

これは非常に便利な洞察です!私の直感的な解決策はフレックスボックスでしたが、すべてのブラウザを確実にサポートしたいので、それは拒否されました。私は最初のオプションを実装し、魅力のように動作します!大変ありがとう@バーニー! –

+0

非常に有用な答え、ありがとう! – evanrmurphy