这个例子会示范以 Compositions API 开发一个简单的图片轮播。先打 API 从远端取得资料,之後把资料渲染到画面,并加入轮播功能,而且轮播功能使用了 Vue 的 transition
来制作。
此例子是参考六角学院的直播里 Kuro 大大提到的常见面试题之一以及他的例子做法,并加入远端抓资料(从 random user 抓取 5 笔 user 资料)的功能和客制样式来改写。
先展示完成效果:
以下会说明步骤,但只会针对重点部分来解说。
首先,先从 random user 取得资料:
import { reactive } from 'vue';
export default {
setup() {
const users = reactive({ results: [] });
(async () => {
try {
const res = await fetch('https://randomuser.me/api/?results=5');
const resJSON = await res.json();
users.results = resJSON.results;
} catch (err) {
console.log(err);
}
})();
return {
users
};
}
};
在 Vue 3,setup
函式的生命周期等於 created
,因此可以直接在 setup
里打 API 取资料。或者使用 onMounted
或 onBeforeMount
也可以。
把资料渲染到网页上,并使用 currentIndex
来指定见前要显示哪笔资料 :
<!-- 需要加上 v-if 判断是否已抓到远端的资料,不然会报错 -->
<div v-if="users.results[currentIndex]" class="card">
<div class="card-img">
<transition :name="imgTransition">
<img
:key="users.results[currentIndex]"
:src="users.results[currentIndex].picture.large"
/>
</transition>
</div>
<ul>
<li>
{{ users.results[currentIndex].name.title }}
{{ users.results[currentIndex].name.last }}
{{ users.results[currentIndex].name.first }}
</li>
<li>{{ users.results[currentIndex].email }}</li>
<li>{{ users.results[currentIndex].phone }}</li>
</ul>
</div>
注意,最外层需要加上 v-if
来判断是否已抓到远端的资料。因为在打 API 取资料是非同步程序。因此,即使我们在 setup 里已执行打 API的程序码,但在接收到资料之前,程序会一直继续执行,包括渲染画面。当画面渲染好但资料还没回来时,就不能在画面渲染资料,不然会出现例如是 Cannot read property 'name' of undefined
这种错误。
transition 的部分会留待最後才解说。
按钮功能包括:
<div class="carousel-btns">
<a @click.prevent="swipeSlide('prev')" href="#"> prev </a>
<div class="carousel-btn-group">
<a
@click.prevent="selectSlide(index)"
href="#"
v-for="(n, index) in users.results.length"
:key="n"
:class="[
{ 'carousel-btn-active': currentIndex === index },
'carousel-btn'
]"
>
</a>
</div>
<a @click.prevent="swipeSlide('next')" href="#"> next </a>
</div>
setup() {
const imgTransition = ref('');
const currentIndex = ref(0);
// ...
// next, prev 切换资料功能
const swipeSlide = direction => {
imgTransition.value = `${direction}-img`;
if (direction === 'next') {
currentIndex.value = (currentIndex.value + 1) % users.results.length;
} else {
currentIndex.value === 0
? (currentIndex.value = users.results.length - 1)
: currentIndex.value--;
}
};
// 指定显示单一资料功能
const selectSlide = index => {
if (currentIndex.value > index) {
imgTransition.value = 'prev-img';
} else {
imgTransition.value = 'next-img';
}
currentIndex.value = index;
};
return {
users,
currentIndex,
swipeSlide,
selectSlide,
imgTransition
};
}
关於 next, prev 切换资料功能,如果 direction 是 next,写法是:
currentIndex.value = (currentIndex.value + 1) % users.results.length;
这写法是为了当 currentIndex
的数值大於 users
阵列长度时,即代表要切回第一笔资料。currentIndex
是由 0 为开始,这时候会显示第一笔资料。目前资料长度是 5,因此,当显示最後一笔资料时, currentIndex
会是 4 。如果再按下 next
, currentIndex
会加一变成 5,而 5 % 5
的余数会是 0,因此回到第一笔资料。其余页码,例如 1, 2。即是 1 % 5
、2 % 5
等,答案会是 1, 2。即是等於该页码的数值。
有两点要处理:
overflow: hidden
overflow: hidden
切换图片时,当前一张图片还没完全滑走,它就会继续占用位置,因此即将要显示的图片就会被推挤到下面,情况如下:
因为此例中的img
是被 transition
包着,transition
在切换图片时,会在旧 img
後再加即将要显示的新 img
:
切换资料时,使用了 transition 来制作切换动画。
<div class="card-img">
<transition :name="imgTransition">
<img
:key="users.results[currentIndex]"
:src="users.results[currentIndex].picture.large"
/>
</transition>
</div>
因此新的 img
会被推挤到下面。解决方法就是在 card-img
设定 overflow: hidden
。
setup() {
const swipeSlide = direction => {
imgTransition.value = `${direction}-img`;
// ...
};
const selectSlide = index => {
if (currentIndex.value > index) {
imgTransition.value = 'prev-img';
} else {
imgTransition.value = 'next-img';
}
currentIndex.value = index;
};
}
SCSS:
.prev-img-enter-active,
.prev-img-leave-active,
.next-img-enter-active,
.next-img-leave-active {
transition: all 0.5s;
}
.next-img-leave-to {
transform: translate(-100%);
}
.prev-img-leave-to {
transform: translate(100%);
}
有几点要注意:
img
,因此要加上 key。<transition name="">
的 name 属性来定义,因此,当 name 的值是 next-img 时,所有 transition 用到的 class 名称就会以 next-img
作为前辍,例如是 next-img-leave-active
、next-img-leave-to
。currentIndex
是前进,动画就会向左滑动。相反的话,就是向右滑动。关於动画 class 名称的作用,看此图就懂了:
截图自官方文件
因此,当图片要消失时,如果要设定它的目的地,对应的 class 就是 xxx-leave-to
。
https://codesandbox.io/s/composition-api-tu-pian-lun-bo-x27ht?file=/src/App.vue
setup
、onMounted
、onBeforeMount
里进行。v-if
避免资料还没抓到的情况。%
的方式来制作循环的页码。transition
切换动画时,会同时存在旧和新的 DOM,也会为它们加上不同的 class。<transition name="">
的 name 属性。如没有指明,预设就会是 v-xxxx
。transition
里切换的元素有同一标签,就需使用 key
属性。呼~ 终於到了最後一天了,感谢团友和读者,技术分享就到此为止了,明天会总结一下这 30 天的铁人赛心得,会以个人感受与心得为主,明天见~
「懒惰是进步的原动力」 科技的进步降低了许多事情的门槛,例如过去要会换牌档才能开车,现在基本上就自排...
一般来说日期、时间几乎都同时出现 既然昨天学了Android的日期交谈视窗 今天就来学时间的交谈视窗...
1.制作UI按纽 (影片Xd03 档案Xd02) https://neumorphism.io/#2...
当object中的function作为callback function传递给setTimeout时...
昨天介绍 Service Workers 後我们知道它是 PWA 的要素之一,且也是让 Web A...