[英]Vue.js transition on changing selected element from a list
我有一个打开“编辑配置文件”屏幕的配置文件列表。 该屏幕从左侧滑入。 当我选择一个配置文件时,如果已经选择了一个屏幕,我希望它先滑出,更改选定的配置文件数据,然后再滑入。
现在发生的情况是:当我第一次选择一个元素时,屏幕会滑入。当我更改所选元素时,屏幕会停留并且不会滑出和滑入。
这是一个 gif,显示它现在的行为:
我的代码是:
Vue方法:
editProfile: function (index){
// this.editingProfile = false;
this.setProfile(index);
this.editingProfile = true;
}
html视图:
<transition name="fade" mode="out-in">
<div v-if="editingProfile" id="edit-profile">
<input placeholder="Profile Name" v-model="synced.profiles[synced.selectedProfile].name">
</div>
</transition>
CSS:
.fade-enter-active, .fade-leave-active {
transition: all .2s;
/* transform:translateX(0); */
}
.fade-enter, .fade-leave-to /* .fade-leave-active below version 2.1.8 */ {
opacity: 0;
transform:translateX(-100%);
}
更改配置文件时,如何使其正确滑出然后重新滑入?
我认为我的评论不正确。 你可以做到这一点的一种方法是利用:key
和v-if
,这样如果你选择了一个面板,你就可以告诉 Vue 渲染一个面板,然后以这种方式在面板之间进行转换。 那时你不需要有一个transition-group
。
问题是:key
告诉 Vue 一切都变了。 如果您不使用它,Vue 会尝试尽可能多地回收。 请参阅文档: 元素之间的转换
在具有相同标签名称的元素之间切换时,您必须通过赋予它们唯一的
key
属性来告诉 Vue 它们是不同的元素。 否则,Vue 的编译器为了效率只会替换元素的内容。 即使在技术上没有必要,在<transition>
组件中始终键入多个项目也被认为是一种好的做法。
考虑下面的最小示例:
const panels = [{ title: "Hello" }, { title: "World" }, { title: "Foo" }, { title: "Bar" } ]; const app = new Vue({ el: "#app", data() { return { panels, activePanel: null }; }, computed: { titles() { return this.panels.map(panel => panel.title); } }, methods: { handleTitleClick(idx) { if (this.activePanel === idx) { this.activePanel = null; return; } this.activePanel = idx; } } });
body { margin: 0; padding: 0; } #app { display: flex; align-items: stretch; height: 100vh; } #panel-set { flex: 1 0 70%; display: flex; } #side-panel { flex: 1 0 30%; } .panel { padding: 1em; flex: 1 0; background-color: rgba(0, 0, 0, 0.2); } .slide-fade-enter-active, .slide-fade-leave-active { transition: transform 500ms ease-in-out; } .slide-fade-enter, .slide-fade-leave-to { transform: translateX(-100%); }
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.min.js"></script> <div id="app"> <div id="panel-set"> <transition name="slide-fade" mode="out-in"> <div class="panel" v-if="activePanel !== null" :key="activePanel"> <h2>{{panels[activePanel].title}}</h2> <p>Lorem ipsum</p> </div> </transition> </div> <div id="side-panel"> <ul> <li v-for="(title, idx) in titles" @click="handleTitleClick(idx)">{{title}}</li> </ul> </div> </div>
根本原因是v-if="editingProfile"
在您的代码中显示一个配置文件后始终为真。
一种解决方案是先将其设置为 false,然后在this.$nextTick
中再次将其设置为 true。 但是您必须将this.editingProfile = true
放在一个setTimeout
和延迟时间 = 转换时间中。 否则, slide out
效果将被覆盖。
就像下面的演示:
new Vue({ el: '#emit-example-simple', data() { return { editingProfile: false, synced : { profiles: [{'name':'A'}, {'name':'B'}, {'name':'C'}], selectedProfile: 0 }, } }, methods: { editProfile: function (index){ this.editingProfile = !this.editingProfile this.$nextTick(() => { setTimeout(()=> { this.synced.selectedProfile = index this.editingProfile = true }, 1200) }) } } })
.fade-enter-active, .fade-leave-active { transition: all 1.2s; /* transform:translateX(0); */ } .fade-enter, .fade-leave-to /* .fade-leave-active below version 2.1.8 */ { opacity: 0; transform:translateX(-100%); border: 1px solid white; }
<script src="https://unpkg.com/vue/dist/vue.js"></script> <div id="emit-example-simple"> <button @click="editProfile(0)">Profile 1</button> <button @click="editProfile(1)">Profile 2</button> <button @click="editProfile(2)">Profile 3</button> <transition name="fade" mode="out-in"> <div v-if="editingProfile" id="edit-profile"> <input style="border: 5px solid red;" placeholder="Profile Name" v-model="synced.profiles[synced.selectedProfile].name"> </div> </transition> </div>
或者您可以考虑使用如下简单演示的Group transition
:
new Vue({ el: '#emit-example-simple', data() { return { editingProfile: false, profileContainers: [true, false], synced : { profiles: [{'name':'A'}, {'name':'B'}, {'name':'C'}], selectedProfile: 0 }, } }, methods: { editProfile: function (index){ this.synced.selectedProfile = index this.profileContainers = this.profileContainers.map((x)=>!x) } } })
.list-items-enter-active { transition: all 1.2s; } .list-items-leave-active { transition: all 1.2s; } .list-items-enter, .list-items-leave-to /* .fade-leave-active below version 2.1.8 */ { opacity: 0; transform:translateX(-100%); border: 1px solid white; } .list-item { display: inline-block; border: 6px solid red; }
<script src="https://unpkg.com/vue/dist/vue.js"></script> <div id="emit-example-simple"> <button @click="editProfile(0)">Profile 1</button> <button @click="editProfile(1)">Profile 2</button> <button @click="editProfile(2)">Profile 3</button> <transition-group name="list-items" tag="p"> <div v-for="(item, index) in profileContainers" :key="index" v-if="item"> <input style="border: 5px solid red;" placeholder="Profile Name" v-model="synced.profiles[synced.selectedProfile].name"> </div> </transition-group> </div>
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.