#javascript #css #vue.js
#javascript #css #vue.js
Вопрос:
Я работаю над компонентом боковой панели VueJS. Это должно позволять родительскому устройству указывать ширину и отображать переключатель, который перемещает боковую панель внутрь и наружу. Что-то вроде этого:
<template>
<div class="sidebarContainer">
<transition
name="slide"
>
<div v-if="isOpen" class="sidebar" :style="{ width }">
<slot/>
</div>
</transition>
<div class="toggle" @click="isOpen = !isOpen">amp;<amp;></div>
</div>
</template>
export default {
props: {
'width': {
default: '20em',
}
},
data() {
return {
isOpen: true,
};
},
};
<style scoped>
.slide-enter-active, .slide-leave-active {
transition: all 0.6s;
}
.slide-enter, .slide-leave-to {
margin-left: -20em;
}
</style>
Работает codepen. Это работает именно так, как я хочу, за исключением того, что ширина перехода (как указано в .slide-enter, .slide-leave-to
style) жестко запрограммирована и не реагирует на width
свойство компонента. Если вы установите width=30em
, то переход будет скачкообразным.
Я подозреваю, что мне, возможно, потребуется использовать перехваты перехода, но, похоже, я не могу заставить это работать. Я пробовал это:
beforeEnter(el) {
el.style = {
transition: 'all 0.6s',
marginLeft: '-20em',
};
},
enter(el, done) {
el.style.marginLeft = '0';
done();
},
beforeLeave(el) {
el.style = {
transition: 'all 0.6s',
marginLeft: '0',
};
},
leave(el, done) {
el.style.marginLeft = '-20em';
done();
},
Смотрите измененный codepen. Вы можете видеть, что боковая панель все еще перемещается, но мгновенно, без анимации. Я подумал, что, возможно, перенос done
обратного вызова в setTimeout
, чтобы завершить переход, помог бы, но это не так.
Я знаю, что мог бы использовать библиотеку, подобную Velocity, или я мог бы вручную закодировать анимацию, но, похоже, должен быть способ просто позволить CSS позаботиться об этом. Чего мне не хватает?
Ответ №1:
Во-первых, ваш способ задать стиль просто не работает
el.style = {
transition: 'all 0.6s',
marginLeft: '-20em',
};
Я просто перехожу transition: 'all 0.6s'
к css и устанавливаю стиль следующим образом
el.style.marginLeft = '-20em';
Во-вторых, enter
событие вызывается очень скоро после beforeEnter
события, поэтому браузер не может обнаружить изменение между двумя состояниями. Итак, я оборачиваю enter
событие в setTimeout
, чтобы сделать трюк для запуска перехода.
В-третьих, done
обратный вызов в этом случае не требуется. Это требуется только в чистом переходе на js. Мы используем смесь CSS и JS
Vue.component('app', {
template: `<div class="app">
<sidebar>sidebar content</sidebar>
<div class="main">Hello, VueJS!</div>
</div>`
});
Vue.component('sidebar', {
template: ` <div class="sidebarContainer">
<transition
name="slide"
@before-enter="beforeEnter"
@enter="enter"
@leave="leave"
>
<div v-if="isOpen" class="sidebar" :style="{ width }">
<slot/>
</div>
</transition>
<div class="toggle" @click="isOpen = !isOpen">amp;<amp;></div>
</div>`,
props: {
'width': {
default: '20em',
}
},
data() {
return {
isOpen: true,
};
},
methods: {
beforeEnter(el) {
el.style.marginLeft = '-20em';
},
enter(el, done) {
// Wait a tick here, so browser can detect style change and tigger transition
setTimeout(() => {
el.style.marginLeft = '0';
}, 0)
},
leave(el, done) {
el.style.marginLeft = '-20em';
},
},
});
new Vue({
el: '#app',
template: '<app/>'
});
html,
body,
.app {
height: 100%;
}
.app {
display: flex;
}
.main {
flex-grow: 1;
background: red;
}
.sidebarContainer {
display: flex;
}
.sidebar {
flex-grow: 1;
padding: 0.5em;
background: blue;
transition: all 0.6s;
}
.toggle {
margin: 0.5em;
}
<div id="app"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.13/vue.min.js"></script>
Комментарии:
1. Я обнаружил, что мне пришлось установить время ожидания равным 1 вместо 0, но тогда это сработало идеально. Спасибо за всю вашу помощь!