vue.js 如何防止标签更改时的过渡?

vm0i2vca  于 2023-11-21  发布在  Vue.js
关注(0)|答案(2)|浏览(152)

我正在努力防止切换标签后触发转换。

示例

const { createApp, reactive, ref } = Vue;
const app = createApp({
  setup() {      
    // switch tabs to see the side effects
    const currentTabIdx = ref(0);

    const listItems = ref([
      [
        { name: 'John', id: 1 },
        { name: 'Joao', id: 2 },
        { name: 'Jean', id: 3 },
        { name: 'Gerard', id: 4 },
      ],
      [
        { name: 'Max', id: 1 },
        { name: 'Moritz', id: 2 },
        { name: 'Foo', id: 3 },
        { name: 'Mo', id: 4 },
      ],
    ])
    
     function shuffleList() {
      listItems.value[currentTabIdx.value] = listItems.value[currentTabIdx.value].sort(() => Math.random() - 0.5);
    }
    
    return {
      currentTabIdx,
      listItems,
      shuffleList
    }
  }
});

app.component('list-component', {
  props: ['items'],

  template: `
    <ol>
      <transition-group>
        <li
          v-for="(effect, index) in items"
          :key="effect"
        >
          <div class="header">
            <h5>{{ effect.name }}</h5>
          </div>
        </li>
      </transition-group>
    </ol>
  `,
});

app.mount("#app");
li {
  transition: 0.5s;
}

.v-enter-active,
.v-leave-active {
  transition: opacity 0.5s;
}

.v-leave-active {
  position: absolute;
}

.v-enter,
.v-leave-to {
  opacity: 0;
}
<script src="https://unpkg.com/vue@next"></script>
<div id="app">

  <button @click="currentTabIdx=0">Tab 1</button> <!-- SWITCH TABS TO SEE SIDE EFFECTS -->
  <button @click="currentTabIdx=1">Tab 2</button> <!-- SWITCH TABS TO SEE SIDE EFFECTS -->
  | <button @click="shuffleList">Shuffle</button>

  <list-component :items="listItems[currentTabIdx]"></list-component>
  
  
</div>

问题

带有列表和transition-group的子组件触发了选项卡导航的副作用。

已尝试

我试着用* { transition: none !important; }禁用身体上的转换,但列表重复了一秒钟。
你有一个想法,如何防止过渡组上标签开关,但启用它的权利之后?

cnwbcb6i

cnwbcb6i1#

如何防止标签更改时的过渡?
也许,有一个比预防更好的方法。
如果你能做到这一点,你需要用keep-alive Package list-component,这样每次标签改变时组件不会被破坏和重新创建。因此,当重新排序列表时,转换效果仍然保持不变。

const { createApp, reactive, ref, nextTick } = Vue;
const app = createApp({
 setup() { 
 const currentTabIdx = ref(0);

 const listItems = ref([
 [
   { name: 'John', id: 1 },
   { name: 'Joao', id: 2 },
   { name: 'Jean', id: 3 },
   { name: 'Gerard', id: 4 },
 ],
 [
   { name: 'Max', id: 1 },
   { name: 'Moritz', id: 2 },
   { name: 'Foo', id: 3 },
   { name: 'Mo', id: 4 },
 ],
 ])

 function shuffleList() {
 listItems.value[currentTabIdx.value] = listItems.value[currentTabIdx.value].sort(() => Math.random() - 0.5);
 }

 nextTick(() => {
 shuffleList();
 });

 return {
 currentTabIdx,
 listItems,
 shuffleList
 }
 }
});

app.component('list-component', {
 props: ['items'],

 template: `
 <ol>
 <transition-group name="list" tag="ol" mode="out-in">
   <li
     v-for="(effect, index) in items"
     :key="effect.id"
   >
     <div class="header">
       <h5>{{ effect.name }}</h5>
     </div>
   </li>
 </transition-group>
 </ol>
 `,
});

app.mount("#app");
li {
 transition: 0.5s;
}

.list-enter-active,
.list-leave-active {
 transition: opacity 0.5s;
}

.list-leave-active {
 position: absolute;
}

.list-enter,
.list-leave-to {
 opacity: 0;
}
<script src="https://unpkg.com/vue@next"></script>

<div id="app">
 <button @click="currentTabIdx=0">Tab 1</button>
 <button @click="currentTabIdx=1">Tab 2</button>
 <button @click="shuffleList">Shuffle</button>

 <keep-alive>
 <component :is="'list-component'" :items="listItems[currentTabIdx]"></component>
 </keep-alive>
</div>

这里我还使用nextTick来延迟对shuffleList的调用,直到下一个DOM更新周期,以便transition-group在呈现列表时应用转换。

编辑

转换应该在选项卡之间停止,但是应该在列表中应用转换。

const { createApp, reactive, ref } = Vue;
const app = createApp({
 setup() {     
   const currentTabIdx = ref(0);
   const listItems = ref([
     [
       { name: 'John', id: 1 },
       { name: 'Joao', id: 2 },
       { name: 'Jean', id: 3 },
       { name: 'Gerard', id: 4 },
     ],
     [
       { name: 'Max', id: 1 },
       { name: 'Moritz', id: 2 },
       { name: 'Foo', id: 3 },
       { name: 'Mo', id: 4 },
     ],
   ])
   
   function shuffleList() {
     listItems.value[currentTabIdx.value] = listItems.value[currentTabIdx.value].sort(() => Math.random() - 0.5);
   }
   
   return {
     currentTabIdx,
     listItems,
     shuffleList
   }
 }
});

app.component('list-component', {
 props: ['items'],
 template: `
   <ol>
     <transition-group>
       <li
         v-for="(effect, index) in items"
         :key="effect"
       >
         <div class="header">
           <h5>{{ effect.name }}</h5>
         </div>
       </li>
     </transition-group>
   </ol>
 `,
});

app.mount("#app");
li {
 transition: 0.5s;
}

.v-enter-active,
.v-leave-active {
 transition: opacity 0.5s;
}

.v-leave-active {
 position: absolute;
}

.v-enter,
.v-leave-to {
 opacity: 0;
}
<script src="https://unpkg.com/vue@next"></script>

<div id="app">
 <button @click="currentTabIdx=0">Tab 1</button> <!-- SWITCH TABS TO SEE SIDE EFFECTS -->
 <button @click="currentTabIdx=1">Tab 2</button> <!-- SWITCH TABS TO SEE SIDE EFFECTS -->
 | <button @click="shuffleList">Shuffle</button>

 <list-component v-show="currentTabIdx === 0" :items="listItems[0]"></list-component>
 <list-component v-show="currentTabIdx === 1" :items="listItems[1]"></list-component>
</div>

这里,v-show用于控制list-component的可见性,当currentTabIdx发生变化时,只切换列表组件的display,不触发任何转换。

s4chpxco

s4chpxco2#

以下是我目前的解决方案,以防止标签更改时的过渡:

const { createApp, reactive, ref, nextTick } = Vue;
const app = createApp({
  setup() {      

    const currentTabIdx = ref(0);
    
    const preventTransition = ref(true);

    const listItems = ref([
      [
        { name: 'John', id: 1 },
        { name: 'Joao', id: 2 },
        { name: 'Jean', id: 3 },
        { name: 'Gerard', id: 4 },
      ],
      [
        { name: 'Max', id: 1 },
        { name: 'Moritz', id: 2 },
        { name: 'Foo', id: 3 },
        { name: 'Mo', id: 4 },
      ],
    ])
    
    function changeTab (index) {
      preventTransition.value = true;
      currentTabIdx.value = index;
      nextTick(() => {
        preventTransition.value = false;
      });
     };
    
     function shuffleList() {
      listItems.value[currentTabIdx.value] = listItems.value[currentTabIdx.value].sort(() => Math.random() - 0.5);
    }
    
    return {
      currentTabIdx,
      preventTransition,
      listItems,
      changeTab,
      shuffleList,
    }
  }
});

app.component('list-component', {
  props: ['items', 'preventTransition'],

  template: `
    <ol>
      <transition-group :name="preventTransition ? 'show' : 'hide'">
        <li
          v-for="(effect, index) in items"
          :key="effect"
          class="move"
        >
          <div class="header">
            <h5>{{ effect.name }}</h5>
          </div>
        </li>
      </transition-group>
    </ol>
  `,
});

app.mount("#app");
li.move {
  transition: 0.5s;
}

.hide-leave-active {
  display: none;
}
<script src="https://unpkg.com/vue@next"></script>
<div id="app">

  <button @click="changeTab(0)">Tab 1</button> <!-- SWITCH TABS TO SEE SIDE EFFECTS -->
  <button @click="changeTab(1)">Tab 2</button> <!-- SWITCH TABS TO SEE SIDE EFFECTS -->
  | <button @click="shuffleList">Shuffle</button>

  <list-component :items="listItems[currentTabIdx]" :preventTransition="preventTransition"></list-component>
  
  
</div>

复制

  1. parent:创建一个布尔值来在命名的转换之间切换
    1.父:在选项卡更改时设置为!boolean
    1.子:使用:name
  2. child:通过display: none隐藏上一个列表
    现在我们可以在子对象中保持过渡,而不会对选项卡更改产生副作用。

相关问题