Vue转换未在按钮单击时触发
Posted
技术标签:
【中文标题】Vue转换未在按钮单击时触发【英文标题】:Vue Transition not Triggering on button click 【发布时间】:2018-12-03 23:34:00 【问题描述】:我是 Vue JS 的新手,我正在创建一个缩略图查看器,我将在其中获取图像和视频列表作为对象数组。首先,我将只显示 5 个项目,当用户单击顶部/底部按钮时,我想垂直滑动缩略图。
我通过引用 *** 上的一些链接创建了一个codepen。
我正在使用 Vue 过渡,我的数据似乎是反应性的,但是当我单击顶部和底部按钮时,不知何故我看不到平滑过渡(滑动到顶部/底部 100 像素)。
html 代码:
<div id="app" class="container-fluid">
<div class="row row-eq-height">
<div class="thumbnail-container">
<button class="up" @click="moveTop" :disabled="currentTopIndex === 0">Top</button>
<div :class="'slider' + (isSlidingToPrevious ? ' sliding-to-previous' : '')">
<transition-group name='list' tag="ul">
<li v-for="(item,index) in currentCarouselData" v-bind:key="index" class="list-item"><img :src="item.itemImage" : /></li>
</transition-group>
</div>
<button @click="moveBottom" class="down" :disabled="currentBottomIndex === totalCount">Down</button>
</div>
</div>
<pre>
totalCount totalCount
currentTopIndex currentTopIndex
currentBottomIndex currentBottomIndex
itemsToDisplay itemsToDisplay
currentCarouselData currentCarouselData
</pre>
</div>
CSS / LESS 代码:
.row-eq-height
display: flex;
ul
list-style-type: none;
display: flex;
flex-direction: column;
overflow: hidden;
height: auto;
border: 1px solid black;
li
flex: 1;
width: 64px;
height: 64px;
position: relative;
margin: 8px 0;
border: 1px solid red;
img
max-width: 100%;
max-height: 100%;
.list-leave-active,
.list-enter-active
transition: 0.5s;
.list-enter
transform: translate(0, 100px);
.list-leave-to
transform: translate(0, -100px);
.sliding-to-previous
.list-enter
transform: translate(0, -100px);
.list-leave-to
transform: translate(0, 100px);
javascript/VUE 代码:
new Vue(
el: "#app",
data()
return
totalCarouselData: [
itemImage: "https://www.publicdomainpictures.net/pictures/150000/velka/banner-header-tapete-145002399028x.jpg",
itemImageAlt: "Test1"
,
itemImage: "https://www.publicdomainpictures.net/pictures/150000/velka/banner-header-tapete-145002399028x.jpg",
itemImageAlt: "Test2"
,
itemImage: "https://www.publicdomainpictures.net/pictures/150000/velka/banner-header-tapete-145002399028x.jpg",
itemImageAlt: "Test3"
,
itemImage: "https://www.publicdomainpictures.net/pictures/150000/velka/banner-header-tapete-145002399028x.jpg",
itemImageAlt: "Test4"
,
itemImage: "https://www.publicdomainpictures.net/pictures/150000/velka/banner-header-tapete-145002399028x.jpg",
itemImageAlt: "Test5"
,
itemImage: "https://www.publicdomainpictures.net/pictures/150000/velka/banner-header-tapete-145002399028x.jpg",
itemImageAlt: "Test6"
,
itemImage: "https://www.publicdomainpictures.net/pictures/150000/velka/banner-header-tapete-145002399028x.jpg",
itemImageAlt: "Test7"
],
currentCarouselData: [],
isSlidingToPrevious: false,
totalCount: 0,
currentTopIndex: 0,
currentBottomIndex: 0,
itemsToDisplay: 5
;
,
computed: ,
mounted()
//At first show only 5 items
this.currentCarouselData = this.totalCarouselData.slice(
this.currentTopIndex,
this.itemsToDisplay
);
//Get Total Count
this.totalCount = this.totalCarouselData.length;
//Update current bottom index
this.currentBottomIndex = this.itemsToDisplay;
,
methods:
moveTop()
this.isSlidingToPrevious = true;
this.currentTopIndex += 1;
this.currentBottomIndex -= 1;
this.addToTopComputedArr(this.currentBottomIndex);
,
moveBottom()
this.isSlidingToPrevious = false;
this.currentTopIndex -= 1;
this.currentBottomIndex += 1;
this.addToBottomComputedArr(this.currentBottomIndex);
,
addToBottomComputedArr(index)
//Splice the first item
this.currentCarouselData.splice(0, 1);
//Add the next item to the array
this.currentCarouselData.push(this.totalCarouselData[index - 1]);
,
addToTopComputedArr(index)
//Splice the last item
this.currentCarouselData.splice(index - 1, 1);
//Add item to the beginning of the array
this.currentCarouselData.unshift(
this.totalCarouselData[index - this.itemsToDisplay]
);
);
【问题讨论】:
你能定义平滑过渡吗 当然......基本上它应该只是滑到顶部或底部...... 我会给出如何实现它的想法,在SO上编写代码非常困难 如果您想尝试一下,我已经在我的问题中添加了 Codepen 链接 :) 谢谢! 这个Codepen怎么样? 【参考方案1】:您遇到的没有过渡问题是由:key="index"
引起的。
检查Vue Guide: key of v-for,
当 Vue 更新使用 v-for 渲染的元素列表时,通过 默认它使用“就地补丁”策略。
这种默认模式是高效的,但只适用于你的列表 渲染输出不依赖子组件状态或临时 DOM 状态(例如表单输入值)。
给 Vue 一个提示,以便它可以跟踪每个节点的身份,从而 重用和重新排序现有元素,您需要提供唯一键 每个项目的属性。
在您的代码中,您的五张图片始终具有相同的 key=[1, 2, 3, 4, 5]
,因此 Vue 会就地修补它们,这会导致转换未触发。
所以只需将:key="index"
修改为:key="item.itemImageAlt"
即可。
最后自己调整css,让过渡效果满足你的要求。
下面是一个工作演示:
Vue.config.productionTip = false
new Vue(
el: "#app",
data()
return
totalCarouselData: [
itemImage:
"https://www.publicdomainpictures.net/pictures/150000/velka/banner-header-tapete-145002399028x.jpg",
itemImageAlt: "Test1"
,
itemImage:
"https://www.publicdomainpictures.net/pictures/150000/velka/banner-header-tapete-145002399028x.jpg",
itemImageAlt: "Test2"
,
itemImage:
"https://www.publicdomainpictures.net/pictures/150000/velka/banner-header-tapete-145002399028x.jpg",
itemImageAlt: "Test3"
,
itemImage:
"https://www.publicdomainpictures.net/pictures/150000/velka/banner-header-tapete-145002399028x.jpg",
itemImageAlt: "Test4"
,
itemImage:
"https://www.publicdomainpictures.net/pictures/150000/velka/banner-header-tapete-145002399028x.jpg",
itemImageAlt: "Test5"
,
itemImage:
"https://www.publicdomainpictures.net/pictures/150000/velka/banner-header-tapete-145002399028x.jpg",
itemImageAlt: "Test6"
,
itemImage:
"https://www.publicdomainpictures.net/pictures/150000/velka/banner-header-tapete-145002399028x.jpg",
itemImageAlt: "Test7"
],
currentCarouselData: [],
isSlidingToPrevious: false,
totalCount: 0,
currentTopIndex: 0,
currentBottomIndex: 0,
itemsToDisplay: 5
;
,
computed:
computedCarouseData: function () // added computed property
return this.totalCarouselData.slice(
-this.currentTopIndex,
this.itemsToDisplay-this.currentTopIndex
)
,
mounted()
//At first show only 5 items
this.currentCarouselData = this.totalCarouselData.slice(
this.currentTopIndex,
this.itemsToDisplay
);
//Get Total Count
this.totalCount = this.totalCarouselData.length;
//Update current bottom index
this.currentBottomIndex = this.itemsToDisplay;
,
methods:
moveTop()
this.isSlidingToPrevious = true;
this.currentTopIndex += 1;
this.currentBottomIndex -= 1;
this.addToTopComputedArr(this.currentBottomIndex);
,
moveBottom()
this.isSlidingToPrevious = false;
this.currentTopIndex -= 1;
this.currentBottomIndex += 1;
this.addToBottomComputedArr(this.currentBottomIndex);
,
addToBottomComputedArr(index)
//Splice the first item
this.currentCarouselData.splice(0, 1);
//Add the next item to the array
this.currentCarouselData.push(this.totalCarouselData[index - 1]);
,
addToTopComputedArr(index)
//Splice the last item
this.currentCarouselData.splice(index - 1, 1);
//Add item to the beginning of the array
this.currentCarouselData.unshift(
this.totalCarouselData[index - this.itemsToDisplay]
);
);
.row-eq-height
display: flex;
.row-eq-height ul
list-style-type: none;
display: flex;
flex-direction: column;
overflow: hidden;
height: auto;
border: 1px solid black;
.row-eq-height li
flex: 1;
width: 64px;
height: 64px;
position: relative;
margin: 8px 0;
border: 1px solid red;
.row-eq-height li img
max-width: 100%;
max-height: 100%;
.list-leave-active,
.list-enter-active
transition: all 2s ease;
.list-enter
opacity: 0;
transform: translateX(-300px);
.list-leave-to
opacity: 0;
transform: translateX(-300px);
.sliding-to-previous .list-enter
transform: translateY(-100px);
.sliding-to-previous .list-leave-to
transform: translateY(100px);
.list-move
transition: transform 1s;
<script src="https://unpkg.com/vue@2.5.16/dist/vue.js"></script>
<div id="app" class="container-fluid">
<div class="row row-eq-height">
<div class="thumbnail-container">
<button class="up" @click="moveTop" :disabled="currentTopIndex === 0">Top</button>
<button @click="moveBottom" class="down" :disabled="currentBottomIndex === totalCount">Down</button>
<div :class="'slider' + (isSlidingToPrevious ? ' sliding-to-previous' : '')">
<transition-group name='list' tag="ul">
<li v-for="(item,index) in computedCarouseData" v-bind:key="item.itemImageAlt" class="list-item"><img :src="item.itemImage" : style=""/>item.itemImageAlt</li>
</transition-group>
</div>
</div>
</div>
<pre>
totalCount totalCount
currentTopIndex currentTopIndex
currentBottomIndex currentBottomIndex
itemsToDisplay itemsToDisplay
currentCarouselData computedCarouseData
</pre>
</div>
【讨论】:
【参考方案2】:Vue(所有响应式框架)使用虚拟 DOM,因为您更改了数据元素之一或页面重新呈现的任何视觉内容。
说到你的问题,它不是平滑,因为一旦你的值被改变,它就会重新渲染。
缩略图的绝对/相对位置,一旦您将 currentCarouselData 设置为 100px。使用 setInterval 递减 top 直到你得到 0 这将带来滑动效果
使用转换组编辑转换
new Vue(
el: '#flip-list-demo',
data:
items: [1,2,3,4,5]
,
methods:
shuffle: function ()
var x = this.items.splice(0,1)[0]
console.log(x)
this.items.push(x)
)
.a-move
transition: transform 1s;
.a-enter
transform: translateY(10px) 1s;
.a-leave
transform: translateY(10px) 1s;
opacity : 0
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
<div id="flip-list-demo" class="demo">
<button v-on:click="shuffle">Shuffle</button>
<transition-group name="a" tag="ul">
<li v-for="(item, index) in items" v-bind:key="item" v-show="index<5">
item
</li>
</transition-group>
</div>
【讨论】:
如果您查看 Vue 转换页面,他们也会以类似的方式添加和删除数据vuejs.org/v2/guide/transitions.html SetInterval 将始终将磁贴移动到顶部和底部,我正在尝试类似的使用 translateY.. 的方法与更改 top 属性不同吗? 不,它不会起作用,一旦您更改数据,页面将重新呈现 但在 Vue Transitions 中并非如此。他们正在添加和删除数组中的元素,并且看起来动画效果很好.. 我也用过..以上是关于Vue转换未在按钮单击时触发的主要内容,如果未能解决你的问题,请参考以下文章