Реализация эффекта перехода отображения элемента и переключения скрытия

внешний интерфейс программист браузер анимация

Я видел это в последнее время. Ты голоден?Appа также h5На станции, после заказа еды на странице сведений о бизнесе, внизу есть элемент, который может всплывать модальное окно для просмотра деталей заказа после нажатия, среди которых есть слой фоновой маски с постепенным эффектом раскрытия и сокрытия .

С моим небольшим опытом первой мыслью было, что этот слой-маска должен быть использованdisplay:none;контролировать скрытие и отображение, но это свойство уничтожитtransitionАнимация, то есть, если слой маски использует это свойство для управления отображением и скрытием, эффект постепенного отображения и скрытия кажется труднодостижимым, и эффект должен отображаться и скрываться мгновенно.

использовать ChromeЯ смоделировал мобильный терминал и проверил реализацию Ele.me, а потом подумал, что Ele.me его использует.vue, этот анимационный эффект на самом деле используетvueЭто реализовано собственной анимацией перехода и функцией перехвата.


Реализация фреймворка

на основеvueРеализация затухания анимации

Использование фреймворка для достижения этого эффекта действительноso easy, не форсируйте код.

// HTML
<div id="app">
    <button class="btn" @click="show = !show">click</button>
    <transition name='fade'>
      <div class="box1" v-if="show"></div>
    </transition>
 </div>
// CSS
.box1 {
  width: 200px;
  height: 200px;
  background-color: green;
 }
.fade-enter-active, .fade-leave-active {
  transition: opacity .5s
 }
.fade-enter, .fade-leave-to{
  opacity: 0;
 }
скопировать код

Нет картинок, нет правды, посмотрите на эффекты, чтобы добавить веселья:

просто не может быть проще

на основеreactРеализация затухания анимации

reactВ своей отдельной библиотеке нет своей анимации перехода, но есть Animation Add-Ons: react-addons-css-transition-group

import React, {Component} from 'react'
import ReactDOM from 'react-dom'
import ReactCSSTransitionGroup from 'react-addons-css-transition-group'
class TodoList extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      show: true
    }
  }
  render() {
    return (
      <div>
        <button onClick={this.changeShow.bind(this)}>click</button>
        <ReactCSSTransitionGroup
          component="div"
          transitionName="fade"
          transitionEnterTimeout={500}
          transitionLeaveTimeout={300}>
          {
            this.state.show &&
            <div className="box1">
            </div>
          }
        </ReactCSSTransitionGroup>
      </div>
    )
  }
  changeShow() {
    this.setState({
      show: !this.state.show
    })
  }
 }скопировать код

Стиль следующий:

.box1 {
  width: 100px;
  height: 100px;
  background-color: green;
  transition: opacity .5s;
 }
.fade-leave.fade-leave-active, .fade-enter {
  opacity: 0;
 }
.fade-enter.fade-enter-active, .fade-leave {
  opacity: 1;
 }скопировать код

все еще оченьeasy


собственная реализация

Все вышеперечисленное — реализации фреймворка, но если у проекта длинная история, то эти ослепляющие фреймворки вообще не будут использоваться.1.2версияjquery, то ни один из вышеперечисленных способов использовать нельзя, надеюсь найти общий нативный способ без использования какого-либо фреймворка.

visibility заменять display

Один из вариантов показан в заголовке, т.к.visibilityЭтот атрибут также может управлять отображением и скрытием элементов и,visibilityимущество в стоимостиvisible а также hiddenПереключение вперед и назад не разрушит элемент.transitionанимация.

но visibilityа также displayЕсть еще некоторые различия в конечном эффекте отображения и скрытия элементов управления.

уже настроенvisibility:hidden;Элемент визуально невидим, но элемент по-прежнему занимает позицию, которую он должен занимать, и по-прежнему будет существовать в потоке документов, влияя на макет страницы, но элемент с этим атрибутом установлен. ширина и высота и использует позиционирование по умолчанию).

и установитьdisplay:none;, который не виден визуально и не занимает места, т.е. исчез из документооборота.

visibilityПоявление и исчезновение элемента управления также происходит мгновенно, но это мгновенное появление отличается отdisplayВид мгновенного возникновения не тот,displayна настройки вообще плеватьtransitionСвойства перехода, заданные и не заданные, одинаковы.

но visibilityЭто значение можно игнорировать, но только время переходаtransition-durationэто свойство.

Например, изvisibility:hiddenприбыть visibility:visible;При смене, если переходное время установлено на3s, то после того, как событие произошло, элемент не сразу рендерится изhiddenприбыть visibleэффект, но он будет как на картинке ниже, сначала подождите3s, а потом моментально скрыть, время от показа до окончательного исчезновения из поля зрения действительно3s, но не постепенно.

Кажется, есть проблема с изображением выше, оно действительно ждет от дисплея, чтобы скрыться.3s, Но прятка, чтобы отображать или как щель, а не ждать3sАргумент.

Визуально это действительно так, но это только визуальное ощущение.На самом деле время ожидания реальное, но его не видно.Кроме того, здесь等待На самом деле это не делает ничего чистого等待.

ЗачемdisplayуничтожитtransitionАнимация, есть поговорка, потому чтоtransitionУправление состоянием элемента во всем переходном процессе рассчитывается по начальному состоянию до и после перехода элемента, например, изopacity:0 прибыть opacity:1Время смены3s,Так transitionздесь будет засчитано3sЭлементы в каждом кадре изображения должны иметьopacityзначение для завершения эффекта перехода, некоторые другие свойства, такие какwidth,scale,colorмогут быть преобразованы в числа для расчета (см. документацию), ноdisplayнеудобное свойство, отdisplay:noneприбыть display:blockКак рассчитать стоимость?

Я не могу вычислить это, поэтому я могу только破坏了,visibilityТо же самое верно, ноvisibilityСравнивать displayнемного лучше, потому что по крайней мереvisibilityОн не разобьет банку и не разрушит ее.

от visibility:hiddenприбыть visibility:visibleв процессе. Поскольку невозможно вычислить значение отсутствия кадра в фазе перехода, элемент отображается напрямую, но внутренняя операция перехода по-прежнему отображается после отображения элемента.3sв то время как отvisibility:visible прибыть visibility:hidden, элемент визуально выглядит ожидающим3sвнутри, на самом деле уже происходит внутриtransitionОперация перехода как раз потому, что нет возможности вычислить значение, поэтому в последний момент фазы перехода элемент сразу устанавливается в конечное состояние, то есть скрыт.

Чтобы проверить это утверждение, вам нужно сотрудничать с другим атрибутом:opacity, это свойство также совместимо сvisibilityЗавершите свойства словосочетания эффекта перехода.

Код реализации выглядит следующим образом

// HTML
<button class="btn">click</button>
<div class="box1"></div>скопировать код
// CSS
.box1 {
  width: 200px;
  height: 200px;
  background-color: green;
  opacity: 0;
  visibility: hidden;
  transition: all 2s linear;
 }
.show {
  opacity: .6;
  visibility: visible;
 }скопировать код

jsКод для управления видимыми и скрытыми эффектами выглядит следующим образом:

let box1 = document.querySelector('.box1')
let btn = document.querySelector('button')
btn.addEventListener('click', ()=>{
  let boxClassName = box1.className
  boxClassName.includes('show')
    ? box1.className = boxClassName.slice(0, boxClassName.length-5)
    : box1.className += ' show'
 })скопировать код

Эффект по-прежнему хорош:

потому что хотяvisibilityНет возможности рассчитать стоимость, ноopacityДа, эффект перехода на самом делеopacityработает.

фактически opacityОн может сам управлять отображением и скрытием элементов, и поместить весь вышеприведенный кодvisibilityУдалить все, эффект остается без изменений, иvisibilityто же самое, наборopacity:0;Элемент все еще присутствует в потоке документов,but,в сравнении с visibility:hidden,opacity:0элементы не отображаются сквозными.

а также visibility:hiddenЭлемент будет отображаться сквозным, а событие щелчка проникнетvisibility:hiddenЭлемент принимается элементом ниже, и когда элемент скрыт, он не будет мешать событиям кликов других элементов.

Кажется, есть некоторые дебаты в Интернете об этом заявлении, но я использую последнюю версию до сих порChrome Firefox так же как 360浏览器Проведите тест, все вышеуказанные результаты.

Если вы просто хотите, чтобы элемент отображался и скрывался постепенно, независимо от того, будет ли скрытый элемент блокировать любые события щелчка или тому подобное, вам не нужно добавлятьvisibilityАтрибут, его добавление напрашивается на хлопоты, но если вам нужно это учитывать, то лучше его добавить.


setTimeOut

Если не использоватьvisibilityЭто хорошо, но если это свойство используется, приведенное выше решение на самом деле немного ошибочно, потому чтоvisibilityот IE10так же как Android4.4Только начали поддерживать, если вам нужна поддержка этой версии браузера, тоvisibilityЭто не пригодится.

Упс, минимальные требования к сайту компанииIE9, это больше не работает.

Как сделать? назад сноваdisplayна этом свойстве.

Зачем displayЭто свойство повлияетtransitionПричина анимации была примерно объяснена выше, так как проблемаdisplay, то я также могу сослаться на вышеизложенноеvisibilityметод, добавьтеopocityатрибут для оказания помощи, и поскольку, учитываяdisplayв сравнении сvisibilityЭто более разрушительно, так что пустьopocity а также displayНельзя ли это сделать отдельно?

Если вы пишете эту форму:

box1.style.display='block'
box1.style.opacity=1скопировать код

Все равно это бесполезноdisplayУстановка значения выглядит как в кодеopacityспереди, но почти одновременно при выполнении.

Мое понимание должно быть, что браузер оптимизирует код. Браузер видит, что вы разделены на два шага для установки одного и того же элемента.CSSатрибут, это кажется немного расточительным, чтобы выполнить эти два шага быстрее, это поможет вам объединить его и поместить в одинtick(См. http://www.infoq.com/cn/articles/javascript-high-performance-animation-and-page-rendering), и это становится одноэтапным процессом, то есть выполняются два предложения кода. синхронно.

Итак, как явно указать браузерам не сливаться вtickвнутри реализации? setTimeOutпригодился.

setTimeOutВажной функцией является задержка выполнения, покаopacityНастройка свойства откладывается до тех пор, покаdisplayПросто сделай это позже.

// CSS
.box1 {
  width: 200px;
  height: 200px;
  background-color: green;
  display: none;
  opacity: 0;
  transition: all 2s linear;
 }скопировать код

Вот код, управляющий прогрессивным отображением элемента:

// JS
let box1 = document.querySelector('.box1')
let btn = document.querySelector('.btn')
btn.addEventListener('click', ()=>{
  let boxDisplay = box1.style.display
  if(boxDisplay === 'none') {
    box1.style.display='block'
    setTimeout(()=> {
      box1.style.opacity = 0.4
    })
  }
 })скопировать код

Самое главное в приведенном выше кодеsetTimeOutЭто предложение, элемент задержкиopacityнастройки свойств.

setTiomeOutВторое необязательное времяdelayПараметры, я в последней версииChromeа также 360Тестируйте в браузере, этот параметр можно опустить или написать как0или другие значения, но вfirefoxВкл, этот параметр нужно прописать, иначе иногда будет работать прогрессивный эффект, и его нельзя будет0, и оно не может быть слишком маленьким. Наименьшее значение, которое я измерил, равно14, чтобы обеспечить прогрессивный эффект, поэтому из соображений совместимости лучше всего добавлять время равномерно.

Что касается того, почему14, я не знаю, но я помню, что читал статью раньше, в которой говорилосьCPUМинимальное время ответа составляет14ms, я думаю, это может иметь какое-то отношение к этому.

Отображаемый эффект есть, так что мне сделать, чтобы скрыть его? setTimeOutКонечно можно, вJSкодif(boxDisplay==='none')добавить один позжеelse

else {
   box1.style.opacity = 0
   setTimeout(()=>{
     box1.style.display = 'none' 
   }, 2000)
 }скопировать код

Установить первым при скрытииopacity,Ждать opacityПосле завершения перехода настройте его сноваdisplay:none;.

Но тут как-то неразумно, потому что хотяsetTimeOutиз delayпараметр2000msа также transition время 2sтакого же размера, но потому чтоJSявляется однопоточным и следует за опросом по времени, поэтому нет никакой гарантииdisplayПараметр свойства находится вopacityВыполняется одновременно после завершения перехода, может быть немного больше задержки, в зависимости от момента завершения анимации перехода,JSЗанят ли основной поток.

Конечно, даже если это задержка, то обычно она не задерживается надолго. Вряд ли человеческий глаз может это почувствовать. Если вам так все равно, то можно вообще-то не обращать на это внимания. Но если я придирчив и хочу быть более совершенным, что мне делать? ?


transitionend

transitionКогда анимация заканчивается, это соответствует событию:transitionend, MDN [ https://developer.mozilla.org/en-US/docs/Web/Events/transitionend ] подробно описывает это событие следующим образом:

transitionendсобытие будетCSS transitionСрабатывает после окончания.transitionудалить до завершенияtransition, такие как удалениеcssиз transition-propertyсвойство, событие не будет запущено, как вtransitionНастройка перед завершениемdisplay:none, событие также не будет запущено.

если вы можете использоватьtransitionПоэтому в основном вы можете использовать это событие, и это событие просто нужно добавить браузер префикса больше (теперь последняя версия всех основных браузеров, не написала префикс), примерно следующая формулировка:

transitionend
webkitTransitionEnd
mozTransitionEnd
oTransitionEndскопировать код

Используя это свойство, вы можете избежать вышеуказанногоsetTimeOutМожет быть проблема, пример использования следующий:

// ...
else {
  box1.style.opacity = 0
  box1.addEventListener('transitionend', function(e) {
    box1.style.display = 'none'
  });
 }скопировать код

должны знать о том,transitionendОбъектом мониторинга событий является всеCSS中transitionЗначение, указанное атрибутом, например, если вы установите элемент вtransition:all3s;стилей, то элемент может быть либоleft topеще opacityИзменение , приведет к запуску события, что означает, что это событие может запускаться несколько раз, и это не обязательно то, что вы хотите запускать каждый раз.В этом случае лучше всего добавить суждение.

Так как он участвуетJSРеализована анимация, тогда вы действительно можете подумать о том, чтобы поставитьsetTimeoutзаменитьrequestAnimationFrame.

btn.addEventListener('click', ()=>{
  let boxDisplay = box1.style.display
  if(boxDisplay === 'none') {
    box1.style.display='block'
    // setTimeOut 换成 requestAnimationFrame
    requestAnimationFrame(()=> {
      box1.style.opacity = 0.6
    })
  } else {
   box1.style.opacity = 0
   box1.addEventListener('transitionend', function(e) {
     box1.style.display = 'none'
   });
  }
 })скопировать код

В статье сказано в началеvue а также reactМетоды этих двух фреймворков для реализации примеров анимации также используют это преимущество.API,для отслеживания состояния перехода анимации добавлять и удалять серии имен классов перехода для элементов, конечно не все, это событие может отслеживать только момент окончания анимации, и не может отслеживаться в другие моменты времени.

  • Ниже приведеныtransitionEnd существует react-addons-css-transition-groupФорма, которая появляется в исходном коде:

react-addons-css-transition-groupправильно transitionendСовместимо, если браузер поддерживает это свойство, используйте его, если нет, используйте егоsetTimeOutэта форма.

  • Ниже приведеныtransitionEnd существует vueФорма, которая появляется в исходном коде:

Также, кстати, кромеtransitionendсобытие, есть также событие animationend [ https://developer.mozilla.org/en-US/docs/Web/Events/animationend ], которое соответствуетanimationанимация,react-addons-css-transition-group а также vueтакже соответствуютtransitionendКогда фигура этого атрибута появится, она не будет здесь развернута.

——————————————————

Нажмите и удерживайте QR-код, следуйте Dazhuanzhuan FE