2016-12-20 5 views
2

У меня есть фиксированная высота div (тело), ​​содержащая два дочерних элемента, заголовок и содержимое. Высота заголовка изменяется одним нажатием кнопки, а высота содержимого должна автоматически настраиваться, чтобы заполнить остальную часть тела. Теперь проблема заключается в том, что высота нового заголовка вычисляется после того, как заголовок заголовка и содержимого были отображены, поэтому высота контента div не будет обновляться при нажатии кнопки. Вот укороченный код:Мифрил: визуализируйте один элемент базы 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. Это особенно сложно объяснить в декларативных виртуальных 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, что заголовок должен расти, чтобы соответствовать его содержанию и никогда не сжимается, и что содержание должно сокращаться, но никогда не растет.

+2

Это супер полезное понимание! Мое интуитивное решение было flexbox, но это было отклонено, поскольку мы хотим быть уверены в поддержке всех браузеров. Я реализовал первый вариант, работает как шарм! Спасибо вам большое @ Барни! –

+0

Очень полезный ответ, спасибо! – evanrmurphy

 Смежные вопросы

  • Нет связанных вопросов^_^