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

Posted

技术标签:

【中文标题】Vue.js 转换从列表中更改选定元素【英文标题】:Vue.js transition on changing selected element from a list 【发布时间】:2019-01-20 11:28:39 【问题描述】:

我有一个打开“编辑个人资料”屏幕的个人资料列表。该屏幕从左侧滑入。当我选择一个配置文件时,如果已经选择了一个屏幕,我希望它先滑出,更改选定的配置文件数据,然后再滑入。

现在发生的情况是:当我第一次选择一个元素时,屏幕会滑入。当我更改所选元素时,屏幕会停留并且不会滑出和滑入。

这是一个 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%);
  

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

【问题讨论】:

你是否正确切换this.editingProfile true falsey 如果我将其切换为 false 然后再次为 true,则不会发生任何事情。 我认为您需要一组面板,而不是您调整其内容的单个面板。否则 Vue 将尝试回收该面板并忽略转换。您想要更多带有项目进出动画的列表过渡。 editProfile里面,你可以先设置为false,然后在this.$nextTick里面,在setTimeout(()=&gt;, 200)里面再设置为true,请查看fiddle。正如@zero298 提到的,组转换应该是滑入/滑出的解决方案。 如果真假切换滑入和滑出是否正常工作,您可以尝试使用单个元素,即 profile1。单击垂直列表元素之一时,您还会调用 editProfile 吗 【参考方案1】:

根本原因是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>

【讨论】:

我认为如果没有nextTick 使用:key,您也许可以逃脱。看我的回答。不过答案很好。【参考方案2】:

我认为我的评论不正确。您可以做到这一点的一种方法是利用:keyv-if,这样如果您选择了一个面板,您就可以告诉Vue 渲染一个面板,然后以这种方式在面板之间进行转换。那时你不需要transition-group

:key 告诉 Vue 一切都变了。如果您不使用它,Vue 会尝试尽可能多地回收。查看文档:Transitioning Between Elements

在具有相同标签名称的元素之间切换时,您 必须通过赋予它们独特性来告诉 Vue 它们是不同的元素 key 属性。否则,Vue 的编译器只会替换 元素的内容以提高效率。即使在技术上 虽然没有必要,始终键入键被认为是一种很好的做法 &lt;transition&gt; 组件中的多个项目

考虑下面的最小示例:

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>

【讨论】:

哦,你说得对,这里用:key会更好。 我考虑过改变,但我仍然更喜欢使用 nexttick,我宁愿控制帧而不是让 vue 决定让它变得神奇。此外,nexttick 会产生更少的代码,并且似乎更容易理解正在发生的事情,尽管由于超时而没有那么优雅。也不太热衷于跟踪数据属性的面板。性能似乎差不多。 我一直在寻找这个!非常感谢

以上是关于Vue.js 转换从列表中更改选定元素的主要内容,如果未能解决你的问题,请参考以下文章

Vue.js:如何使转换组只触发一次?

Vue.js css 转换类更改

Xamarin 列表视图选定项目更改图标颜色

如何使用 Vue.js 在选择选项上使用转换

添加用于在选定元素中编辑数组对象键的“输入” - Vue.js

在 vue.js 中获取选定的下拉值