Это обычная проблема при работе с динамическими макетами DOM, в которых некоторые записываемые свойства DOM получены из других доступных для чтения свойств DOM. Это особенно сложно объяснить в декларативных виртуальных DOM-идиомах, таких как Mithril, потому что они основаны на предпосылке, что каждая функция просмотра должна быть самозаполненными моментальными снимками состояния пользовательского интерфейса, что в данном случае невозможно.
У вас есть 3 варианта: вы можете либо выйти из виртуальной DOM-идиомы, чтобы достичь этой функциональности, напрямую манипулируя DOM за пределами взгляда Мифрила, либо вы можете смоделировать ваш компонент для работы с «2-го ничьей», каждое потенциальное изменение в элементе заголовка приводит к 1 ничьей, чтобы обновить заголовок и вторую ничью, чтобы соответствующим образом обновить содержимое. Кроме того, вы можете избавиться от чистого CSS-решения.
Поскольку вам нужно только обновить одно свойство, вам почти наверняка будет лучше для первого варианта. Используя функцию 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, так как это позволяет избежать прямого манипулирования 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 */)
])
}
Третий вариант - 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 */)
])
Таким образом, вы можете просто указать, что контейнер является Flexbox, что заголовок должен расти, чтобы соответствовать его содержанию и никогда не сжимается, и что содержание должно сокращаться, но никогда не растет.
Это супер полезное понимание! Мое интуитивное решение было flexbox, но это было отклонено, поскольку мы хотим быть уверены в поддержке всех браузеров. Я реализовал первый вариант, работает как шарм! Спасибо вам большое @ Барни! –
Очень полезный ответ, спасибо! – evanrmurphy