这篇文章主要介绍了Vue实现内部组件轮播切换效果的示例代码,现在分享给大家,也给大家做个参考。

对于那些不需要路由的内部组件,在切换的时候希望增加一个轮播过渡的效果,效果如下:

Vue实现内部组件轮播切换效果的示例代码

我们可以引入一个轮播组件,但是有个问题,通常轮播组件都会把所有的slide都渲染出来再进行切换,这样就导致所有的资源都会触发加载,这可能不是我们所期待的,毕竟如果slide比较多的情况需要一次性加载的图片等资源太多了。所以我们可以手动简单地写一个,满足需求即可。

现在一步步来实现这个功能,先写一个实现基本切换的demo.

1. 实现切换

先用vue-cli搭建一个工程脚手架,使用以下命令:

npm install -g vue-cli vue init webpack slide-demo # 运行后router等都选择no

这样就搭了一个webpack + vue的工程,进入slide-demo目录,查看src/App.vue,这个文件是初始化工具提供的,是整个页面的组件。还有一个src/components目录,这个是放子组件的目录。

在这个目录里面新建3个组件:task-1.vue、task-2.vue、task-3.vue,然后在App.vue里面import进来,如下App.vue所示:

<script> // import HelloWorld from './components/HelloWorld' import Task1 from "./components/task-1"; import Task2 from "./components/task-2"; import Task3 from "./components/task-3"; export default { name: 'App', components: { Task1, Task2, Task3 } } </script>

我们的数据格式questions是这样的:

[{index: 1, type: 1, content: ''}, {index: 2, type: 1, content: ''}, {index: 3, type: 2, content: ''}, {index: 4, type: 3, content: ''}]

它是一个数组,数组里的每个元素代表每道题,每道题都有一个类型,如选择题、填空题、判断题等,分别对应上面的task-1、task-2、task-3,我们用一个currentIndex变量表示当前是在哪道题,初始化为0,如下代码所示(添加到App.里面):

data() { return { currentIndex: 0 }; }, created() { // 请求question数据 this.questions = [ {index: 1, type: 1, question: ''}, /*...*/]; },

通过改变currentIndex的值,从而切到一下题即下一个组件,要怎么实现这个切换的效果呢?

可以使用Vue自定义的一个全局组件component,给合它的is属性,达到动态改变组件的目的,如下代码所示:

<template> <p id="app"> <p class="task-container"> <component :is="'task-' + questions[currentIndex].type" </component> </p> </p> </template>

当currentIndex增加时,就会改变:is里面的值,依次从task-1变到task-2、task-3等,这样component就会换成相应的task组件。

接着,再添加一个切换到下一题的按钮,在这个按钮的响应函数里面改变currentIndex的值。同时把question的数据传给component:

<template> <p id="app"> <p class="task-container"> <component :is="'task-' + questions[currentIndex].type" :question="questions[currentIndex]"></component> <button class="next-question" @click="nextQuestion">下一题</button> </p> </p> </template>

响应函数nextQuestion实现如下:

methods: { nextQuestion() { this.currentIndex = (this.currentIndex + 1) % this.questions.length; } },

具体每个task的实现参考如task-1.vue示例:

<template> <section> <h2>{{question.index}}. 选择题</h2> <p>{{content}}</p> </section> </template> <script> export default { props: ["question"] } </script>

最后的效果如下(加上题目内容):

Vue实现内部组件轮播切换效果的示例代码

2. 添加轮播切换效果

轮播切换通常是把所有的slide都拼起来,拼成一张长长的横图,然后改变这个横图在显示容器里面的位置,如老牌jQuery插件flipsnap.js,它是把所有的slide都float: left,形成一张长图,然后 改变这张长图的translate值 ,达到切换的目的。这个插件的缺点是没有办法从最后一张切回第一张,解决这个问题的方法之一是不断地移动DOM:每次切的时候都把第一张移到最后一张的后面,这样就实现了最后一张点下一张的时候回到第一张的目的,但是这样移来移去地对性能消耗比较大,不是很优雅。另外一个轮播插件jssor slider,它也是把所有的slide都渲染出来,然后每次切换的时候都 动态地计算每张slide的translate的值 ,而不是整体长图的位置,这样就不用移动DOM节点,相对较为优雅。还有很多Vue的轮播插件的实现也是类似上面提到的方式。

不管怎么样,上面的轮播模式都不太适用于我们的场景,其中一个是这种答题的场景不需要切回上一题,每道题做完就不能回去了,更重要的一个是我们 不希望一次性把所有的slide都渲染出来 ,这样会导致每张幻灯片里的资源都触发加载,就比如img标签虽然你把它display: none了,但是只要它的src是一个正常的url,它就会请求加载。 由于slide往往会比较多,就不使用这种轮播插件了。

还可以使用Vue自带的transition,但是transition的问题是,切下一个的时候,上一个不见了,因为被销毁了,只有下一个的动画,并且不能预加载下一个slide的资源。

所以我们手动实现一个。

我的想法是每次都准备两个slide,第1个slide是当前展示用的,第2个slide拼在它的后面,准备切过来,当第2个slide切过来之后,删掉第1个slide,然后在第2个的后面再接第3个slide,不断地重复这个过程。如果我们没有使用Vue,而是自己增删DOM,那么没什么问题,可以很任性地自己发挥。 使用Vue可以怎么优雅地实现这个功能呢