Как заставить переход работать с видимостью, но не отображать?

Элемент transition vue работает только с display:none, но не visibility:hidden, есть ли способ заставить его работать с visibility? Я хочу получить clientWidth элемента до того, как он появится, с display:none я не могу получить это значение.

Кстати я использую vue3.

Вот демонстрация воспроизведения: https://codesandbox.io/s/competent-hermann-b1s5q < / а>


person yaquawa    schedule 30.10.2020    source источник
comment
не могли бы вы предоставить какой-нибудь код в codeanbox, вы могли бы создать его codeandbox.io/s/late-framework-96c0g?file=/src/App.vue   -  person Boussadjra Brahim    schedule 30.10.2020
comment
может быть, если вы заставите его с помощью css: div{ display:block !important; }?   -  person Miro    schedule 30.10.2020
comment
@Boussadjra Brahim Спасибо, я обновил свой вопрос.   -  person yaquawa    schedule 30.10.2020
comment
Переходы применяются, когда элемент вставляется или удаляется из модели DOM. Для чего вам нужны элементы "clientWidth"?   -  person Daniel_Knights    schedule 31.10.2020
comment
Вероятно, есть обходной путь, при котором вы можете получить ширину при рендеринге, если она вам не нужна при загрузке страницы?   -  person Daniel_Knights    schedule 31.10.2020


Ответы (2)


Я собираюсь предположить, в качестве аргумента, что вам действительно нужно использовать visibility для сокрытия, и что другие потенциальные решения (например, opacity) не будут работать в вашем реальном варианте использования, возможно, потому что они не предотвращают взаимодействие пользователя с элементом.

Однако утверждение в вопросе немного вводит в заблуждение. На самом деле это не разница между display и visibility. Настоящая разница здесь в том, что в случае display используется v-show, который включает специальную обработку переходов.

Текущий исходный код для v-show можно увидеть здесь:

com / vuejs / vue-next / blob / d7beea015bdb208d89a2352a5d43cc1913f87337 / packages / runtime-dom / src / directives / vShow.ts

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

const visible = {
  updated(el, { value, oldValue }, { transition }) {
    if (!value === !oldValue) {
      return
    }

    if (value) {
      transition.beforeEnter(el)
      el.style.visibility = ''
      transition.enter(el)
    } else {
      transition.leave(el, () => {
        el.style.visibility = 'hidden'
      })
    }
  }
}

Vue.createApp({
  data() {
    return {
      show: true
    };
  },
  methods: {
    toggle() {
      this.show = !this.show;
    }
  },
  directives: {
    visible
  }
}).mount('#app')
#app {
  text-align: center;
}

.tooltip-enter-active {
  transition: transform 0.4s ease-out, opacity 0.3s ease-out;
}

.tooltip-leave-active {
  transition: transform 0.35s ease-in, opacity 0.28s ease-out;
}

.tooltip-enter-from {
  transition: none;
}

.tooltip-enter-from,
.tooltip-leave-to {
  transform: translateY(-30px) scale(0.96);
  opacity: 0;
}
<script src="https://unpkg.com/[email protected]/dist/vue.global.prod.js"></script>
<div id="app">
  <transition name="tooltip">
    <div v-visible="show">
      Using visibility
    </div>
  </transition>
  <button @click="toggle">toggle message</button>
</div>

Мне также пришлось внести небольшое изменение в CSS, чтобы ускорить переход при входе:

.tooltip-enter-from {
  transition: none;
}
person skirtle    schedule 31.10.2020
comment
Спасибо!! На самом деле я применил то же самое решение, что и ваше, но анимация была отрывистой, я не могу понять причину, пока не увижу ваш .tooltip-enter-from! Спасибо большое! - person yaquawa; 31.10.2020

В этом случае, наверное, будет лучше без <transition>:

const app = Vue.createApp({
  data() {
    return {
      show: true,
    };
  },
  methods: {
    toggle() {
      const tooltip = this.$refs.tooltip;

      this.show = !this.show;
      tooltip.classList.toggle("tooltip-show");
    },
  },
  mounted() {
    console.log('Tooltip-width: ', this.$refs.tooltip.clientWidth);
  },
});

app.mount('#app')
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}

.tooltip {
  opacity: 0;
  transform: translateY(-30px) scale(0.96);
  transition: transform 0.35s, opacity 0.25s;
}

.tooltip-show {
  opacity: 1;
  transform: translateY(0) scale(1);
}
<script src="https://unpkg.com/[email protected]/dist/vue.global.js"></script>

<div id="app">
  <div class="tooltip" ref="tooltip">This will work!</div>
  <button @click="toggle">toggle tooltip</button>
</div>

person Daniel_Knights    schedule 30.10.2020