繁体   English   中英

Vue.js 转换从列表中更改选定元素

[英]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%);
  }

更改配置文件时,如何使其正确滑出然后重新滑入?

我认为我的评论不正确。 你可以做到这一点的一种方法是利用:keyv-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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM