Before, I introduced the basic idea of DevUI component design, and took Carousel component as an example to share with you how to apply the idea of building block theory to component design.
This component is a simplified version of the Carousel component in the Vue DevUI component library. It is very simple, only 300 lines of code, but it is very flexible and can be used to create a variety of components based on this component.
I posted it to the NPM repository, welcome to experience!
www.npmjs.com/package/vue…
Recommended reading:
Building Blocks theory of Front-end development – Do front-end development like building blocks
Design a flexible Carousel lantern assembly with building block theory
Using an accordion folding card example: Why don’t DCarouseIndicator use pageIndex on DCarousel directly?
1 Quick Start
There are two ways to use vue-devui-Carousel components:
- Use directly in HTML pages
- Vite and other scaffolding installation and use
1.1 Use directly in HTML pages
Create an index. HTML:
<! DOCTYPEhtml>
<html>
<head>
<meta charset="UTF-8">
<script src="https://unpkg.com/vue@next"></script>
<script src="https://unpkg.com/vue-devui-carousel"></script>
<link rel="stylesheet" href="https://unpkg.com/vue-devui-carousel/dist/style.css">
<style>
.carousel-item {
text-align: center;
line-height: 200px;
background: #f3f6f8;
}
</style>
<title>Vue DevUI Carousel</title>
</head>
<body>
<div id="app"></div>
<script></script>
</body>
</html>
Copy the code
Then open the browser directly to see the effect!
The basic use of the vue-devui-Carousel component is to add the elements to the DCarousel tag directly:
<DCarousel>
<div class="carousel-item">page 1</div>
<div class="carousel-item">page 2</div>
<div class="carousel-item">page 3</div>
</DCarousel>
Copy the code
You can also add images to create a gold digging campaign page:
<DCarousel style="width: 470px; height: 280px;" > <img height="280" src="https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/0a4dda7abf534e098f04fe0e968b1e0c~tplv-k3u1fbpfcp-zoom-mark-crop-v 2:0:0:940:560.awebp?" /> <img height="280" src="https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/5e5b0b404fcb44ac9fb1359334186b46~tplv-k3u1fbpfcp-zoom-mark-crop-v 2:0:0:940:560.awebp?" /> </DCarousel>Copy the code
1.2 Used in VITE engineering
We usually create a Vite project in which we build building blocks, create pages, and write business logic. Let’s take a look at how vue-Devui-Carousel components are used in a Vite project.
Create a Vite project:
yarn create vite vite-demo --template vue-ts
Copy the code
Then install Carousel:
yarn add vue-devui-carousel
Copy the code
Introduce Carousel in main.ts:
import Carousel from 'vue-devui-carousel'
import 'vue-devui-carousel/dist/style.css'
createApp(App)
.use(Carousel)
.mount('#app')
Copy the code
For use in app.vue:
<DCarousel>
<div class="carousel-item">page 1</div>
<div class="carousel-item">page 2</div>
<div class="carousel-item">page 3</div>
</DCarousel>
Copy the code
The effect is the same as using it directly in HTML
2 Overview of Carousel components
Carousel exposed 4 components 1 Composable:
DCarousel
By the componentDCarouselIndicator
Indicator subcomponentDCarouselPrev
Previous page subcomponentDCarouselNext
Next page subcomponentusePage
Paging Composable
DCarousel is the main carousel component, the other several can be combined with DCarousel, or can be used alone, not coupled with DCarousel.
We used the DCarouselIndicator component alone to create an accordion-like folding card:
Use the DCarouseIndicator component alone to achieve the accordion folding card effect
3 DCarousel: main carousel component
This is the main component that supports a little customization and can be used directly by businesses that don’t need much customization.
3.1 API
The API for this component is very simple, with only three props:
v-model
: binds the current page number bidirectionally,Number
Type, the first page is displayed by defaultautoplay
: Indicates whether to play automatically. The default value istrue
interval
: Interval for automatic playback, in milliseconds. The default value is3000
Supports three types of slots:
default
: Rotation contentindicator
: User-defined indicatorspagination
: Custom pager
3.2 play
3.2.1 Gameplay 1: Usev-model
Implement custom initial page numbers
By default (with no properties set), the initial page number is the first page, which can be changed using the V-Model.
const pageIndex = ref(2)
<DCarousel v-model="pageIndex">
<div class="carousel-item">page 1</div>
<div class="carousel-item">page 2</div>
<div class="carousel-item">page 3</div>
</DCarousel>
Copy the code
3.2.2 Gameplay 2: Usev-model
Implement jump to any page number
By default, the DCarousel component has previous and next buttons and an indicator at the bottom that can be used to toggle the wheel map.
If we don’t want to click on these elements inside the component, is there a way to toggle the wheel view?
The answer is to use v-Model, for example, we want to switch to the previous wheel image, directly set v-Model binding pageIndex can be:
<button @click="pageIndex = pageIndex - 1"> </button>Copy the code
The next slide, the first slide, etc., can be done in the same way:
<button @click="pageIndex = pageIndex + "> </button> <button @click="pageIndex = pageIndex + 1"> </button> <button @click="pageIndex = 1" class="carousel-item">page 1</div> <div class="carousel-item">page 2</div> <div class="carousel-item">page 3</div> </DCarousel>Copy the code
3.2.3 Gameplay 3: Useautoplay
Cancel automatic rotation
By default, the DCarousel component automatically switches to the next chapter of the wheel chart every three seconds, which is a basic feature of the wheel chart.
However, some users do not want autoplay, which can be disabled by setting autoplay to false.
<DCarousel :autoplay="false">
<div class="carousel-item">page 1</div>
<div class="carousel-item">page 2</div>
<div class="carousel-item">page 3</div>
</DCarousel>
Copy the code
3.2.4 Gameplay 4: Useinterval
Set the interval for automatic rotation
In addition to canceling automatic rotation, interval can also set the automatic rotation interval (in ms), the default is 3000ms, we think it is too slow, we want to rotate faster, such as 1s automatic rotation.
<DCarousel :interval="1000">
<div class="carousel-item">page 1</div>
<div class="carousel-item">page 2</div>
<div class="carousel-item">page 3</div>
</DCarousel>
Copy the code
3.2.5 Gameplay 5: Use the default slotdefault
QQ music official website home page round seeding effect
DCarousel components have a total of 3 slots:
default
: Default slotindicator
: Indicator slotpagination
: Pager slot
The default slot is used to set the content that needs to be rotated. Any content can be rotated, such as putting song covers and information is the effect of QQ music.
<script setup lang="ts">
import { DCarousel } from 'vue-devui-carousel'
</script>
<template>
<div>
<DCarousel>
<!-- 以下 html 片段拷贝自QQ音乐官网 -->
<div class="mod_playlist">
<div class="playlist__item">
<div class="playlist__item_box"><div class="playlist__cover mod_cover"><a href="/n/ryqq/playlist/7759293603"><img class="playlist__pic" loading="lazy" src="//qpic.y.qq.com/music_cover/ibO7y1R5gAqKsKKDaUxchyzkEBvN9tMHxMGhxaDsveRImUCyTiboVWrQ/300?n=1" alt="旋律说唱:一起感受粉色恋爱泡泡" data-qar-def="//y.qq.com/mediastyle/global/img/playlist_300.png?max_age=2592000"><i class="mod_cover__mask"></i><i class="mod_cover__icon_play"></i></a></div><h4 class="playlist__title"><span class="playlist__title_txt"><a href="/n/ryqq/playlist/7759293603">旋律说唱:一起感受粉色恋爱泡泡</a></span></h4><div class="playlist__other">播放量:297.2万</div></div>
</div>
<div class="playlist__item">
<div class="playlist__item_box"><div class="playlist__cover mod_cover"><a href="/n/ryqq/playlist/7871303692"><img class="playlist__pic" loading="lazy" src="//qpic.y.qq.com/music_cover/bp55dcibXqUjaQjwt6gP1iaibEdjVJvp7vNbVQMjepC2ZTDNx1M3MkLnw/300?n=1" alt="鬼畜打败恐惧|整点阳间的东西" data-qar-def="//y.qq.com/mediastyle/global/img/playlist_300.png?max_age=2592000"><i class="mod_cover__mask"></i><i class="mod_cover__icon_play"></i></a></div><h4 class="playlist__title"><span class="playlist__title_txt"><a href="/n/ryqq/playlist/7871303692">鬼畜打败恐惧|整点阳间的东西</a></span></h4><div class="playlist__other">播放量:140.7万</div></div>
</div>
<div class="playlist__item">
<div class="playlist__item_box"><div class="playlist__cover mod_cover"><a href="/n/ryqq/playlist/8249092627"><img class="playlist__pic" loading="lazy" src="//qpic.y.qq.com/music_cover/BibN36PYLliczibicnsXMuTzLUZaErDuDop6moxSnrfAuWnAKrqDUnibMlQ/300?n=1" alt="上班族必备:枯燥无味听点歌解闷" data-qar-def="//y.qq.com/mediastyle/global/img/playlist_300.png?max_age=2592000"><i class="mod_cover__mask"></i><i class="mod_cover__icon_play"></i></a></div><h4 class="playlist__title"><span class="playlist__title_txt"><a href="/n/ryqq/playlist/8249092627">上班族必备:枯燥无味听点歌解闷</a></span></h4><div class="playlist__other">播放量:685.5万</div></div>
</div>
<div class="playlist__item">
<div class="playlist__item_box"><div class="playlist__cover mod_cover"><a href="/n/ryqq/playlist/8175037786"><img class="playlist__pic" loading="lazy" src="//qpic.y.qq.com/music_cover/W43yJLl09jro4gLJXBxMR1PKp3oH0yfqaWZsCjgJEFCxCAMhx5XdGA/300?n=1" alt="追星名场面 | 一人一首偶像曲" data-qar-def="//y.qq.com/mediastyle/global/img/playlist_300.png?max_age=2592000"><i class="mod_cover__mask"></i><i class="mod_cover__icon_play"></i></a></div><h4 class="playlist__title"><span class="playlist__title_txt"><a href="/n/ryqq/playlist/8175037786">追星名场面 | 一人一首偶像曲</a></span></h4><div class="playlist__other">播放量:35.2万</div></div>
</div>
<div class="playlist__item">
<div class="playlist__item_box"><div class="playlist__cover mod_cover"><a href="/n/ryqq/playlist/7845656497"><img class="playlist__pic" loading="lazy" src="//qpic.y.qq.com/music_cover/tzTIee65HohmgERhaae4MdXH1NnSAicACibx3A81TpOj14Qheibiajcic0O13hk2qnCd3/300?n=1" alt="『甜度100%』我瞒着所有人在想你" data-qar-def="//y.qq.com/mediastyle/global/img/playlist_300.png?max_age=2592000"><i class="mod_cover__mask"></i><i class="mod_cover__icon_play"></i></a></div><h4 class="playlist__title"><span class="playlist__title_txt"><a href="/n/ryqq/playlist/7845656497">『甜度100%』我瞒着所有人在想你</a></span></h4><div class="playlist__other">播放量:136.3万</div></div>
</div>
</div>
<div class="mod_playlist">
<div class="playlist__item">
<div class="playlist__item_box"><div class="playlist__cover mod_cover"><a href="/n/ryqq/playlist/7683199209"><img class="playlist__pic" loading="lazy" src="//qpic.y.qq.com/music_cover/Eoo44uQyI5ubcwbQbs6E0V8261fic2HA7jsGO6p5oAcsUJ5KxOdU84w/300?n=1" alt="伤感片段丨不过是南柯一梦" data-qar-def="//y.qq.com/mediastyle/global/img/playlist_300.png?max_age=2592000"><i class="mod_cover__mask"></i><i class="mod_cover__icon_play"></i></a></div><h4 class="playlist__title"><span class="playlist__title_txt"><a href="/n/ryqq/playlist/7683199209">伤感片段丨不过是南柯一梦</a></span></h4><div class="playlist__other">播放量:4921.6万</div></div>
</div>
<div class="playlist__item">
<div class="playlist__item_box"><div class="playlist__cover mod_cover"><a href="/n/ryqq/playlist/1169459292"><img class="playlist__pic" loading="lazy" src="//qpic.y.qq.com/music_cover/Ej7F4g676QjYgica7iamaB8vD7Dp1Bgiaicia2V0jNunmKNT5uSFLaZ6r2w/300?n=1" alt="「90后」承载着青春回忆的歌谣" data-qar-def="//y.qq.com/mediastyle/global/img/playlist_300.png?max_age=2592000"><i class="mod_cover__mask"></i><i class="mod_cover__icon_play"></i></a></div><h4 class="playlist__title"><span class="playlist__title_txt"><a href="/n/ryqq/playlist/1169459292">「90后」承载着青春回忆的歌谣</a></span></h4><div class="playlist__other">播放量:9941.1万</div></div>
</div>
<div class="playlist__item">
<div class="playlist__item_box"><div class="playlist__cover mod_cover"><a href="/n/ryqq/playlist/7382629476"><img class="playlist__pic" loading="lazy" src="//qpic.y.qq.com/music_cover/Z89aLA93LOSOicz0QOnMboqgLaiaFohjweglHh6JSoL8hrjOfFOC6DXw/300?n=1" alt="精选 | 好听到单曲循环的热歌" data-qar-def="//y.qq.com/mediastyle/global/img/playlist_300.png?max_age=2592000"><i class="mod_cover__mask"></i><i class="mod_cover__icon_play"></i></a></div><h4 class="playlist__title"><span class="playlist__title_txt"><a href="/n/ryqq/playlist/7382629476">精选 | 好听到单曲循环的热歌</a></span></h4><div class="playlist__other">播放量:14.4亿</div></div>
</div>
<div class="playlist__item">
<div class="playlist__item_box"><div class="playlist__cover mod_cover"><a href="/n/ryqq/playlist/4276472710"><img class="playlist__pic" loading="lazy" src="//qpic.y.qq.com/music_cover/ic88Gx52icY2Txiaiao5n2tlPibPEGUKydonCia8mKhpetTbZnjHhBtMBkbA/300?n=1" alt="欧美节奏控 | 触碰你的听觉神经" data-qar-def="//y.qq.com/mediastyle/global/img/playlist_300.png?max_age=2592000"><i class="mod_cover__mask"></i><i class="mod_cover__icon_play"></i></a></div><h4 class="playlist__title"><span class="playlist__title_txt"><a href="/n/ryqq/playlist/4276472710">欧美节奏控 | 触碰你的听觉神经</a></span></h4><div class="playlist__other">播放量:236.9万</div></div>
</div>
<div class="playlist__item">
<div class="playlist__item_box"><div class="playlist__cover mod_cover"><a href="/n/ryqq/playlist/8037914794"><img class="playlist__pic" loading="lazy" src="//qpic.y.qq.com/music_cover/t3ZMFYNfykL5iaia5MjecOXibibjic2UzATaTkHnCvb5zQNQgicf1w4j0yeQ/300?n=1" alt="粉墨登场~坠入人间的星屑少女" data-qar-def="//y.qq.com/mediastyle/global/img/playlist_300.png?max_age=2592000"><i class="mod_cover__mask"></i><i class="mod_cover__icon_play"></i></a></div><h4 class="playlist__title"><span class="playlist__title_txt"><a href="/n/ryqq/playlist/8037914794">粉墨登场~坠入人间的星屑少女</a></span></h4><div class="playlist__other">播放量:762.9万</div></div>
</div>
</div>
</DCarousel>
</div>
</template>
<style>
/* 以下 css 样式片段拷贝自QQ音乐官网 */
.playlist__item {
position: relative;
padding-bottom: 0;
display: inline-block;
width: 224px;
padding-bottom: 44px;
overflow: hidden;
font-size: 14px;
vertical-align: top;
}
a:hover {
color: #31c27c;
}
a, a:hover {
text-decoration: none;
}
a {
color: #000;
cursor: pointer;
}
.playlist__item_box {
position: absolute;
top: 0;
left: 0;
right: 0;
}
.playlist__item_box {
position: relative;
margin-right: 20px;
}
.playlist__item:nth-child(5) .playlist__item_box {
margin-right: 0;
}
.playlist__cover {
position: relative;
display: block;
overflow: hidden;
padding-top: 100%;
margin-bottom: 15px;
}
.playlist__pic {
height: 100%;
-o-object-fit: cover;
object-fit: cover;
}
.playlist__pic {
transform: scale(1) translateZ(0);
transition: transform .75s;
}
.playlist__pic {
position: absolute;
top: 0;
left: 0;
width: 100%;
-webkit-transform: scale(1) translateZ(0);
-webkit-transition: -webkit-transform .75s;
}
.playlist__cover:hover .playlist__pic {
transform: scale(1.07) translateZ(0);
transition: transform .75s cubic-bezier(0,1,.75,1);
}
.playlist__title_txt {
white-space: normal;
}
.playlist__title {
overflow: hidden;
margin: 0;
padding: 0;
}
.playlist__title_txt {
float: left;
max-width: 100%;
font-weight: 400;
overflow: hidden;
text-overflow: ellipsis;
line-height: 22px;
max-height: 44px;
}
.playlist__author, .playlist__author a, .playlist__other {
color: #999;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
height: 22px;
font-size: 14px;
}
</style>
Copy the code
QQ Music official website effect:
If the book information is placed in the default slot, it can be very convenient to achieve the effect of douban book information rotation.
4 DCarouselIndicator: sub-component of the indicator
4.1 API
The DCarouselIndicator API is very simple, with only 2 properties and 1 slot:
v-model
: Binds the current page number bidirectionallycount
: Indicates the number of small dots in the indicatordefault
: Default slot for customizing indicators
4.2 play
4.2.1 Gameplay 1: Default effect of DCarouselIndicator
The DCarouselIndicator component can be used independently of DCarousel. If nothing is configured, the default effect is a highlighted dot.
<DCarouselIndicator></DCarouselIndicator>
Copy the code
It doesn’t seem to help.
4.2.2 Gameplay 2: Usecount
Property renders a specified number of indicator dots
Multiple points can be rendered using the count attribute.
<DCarouselIndicator :count="3"></DCarouselIndicator>
Copy the code
Doesn’t look like it’s working.
4.2.3 Gameplay 3: Usev-model
Specifies the initial highlighted dot and dynamically changes the highlighted dot
Similar to the DCarousel component, the DCarouselIndicator also has a V-Model property, which can set initial values and dynamically change the high points.
<script setup lang="ts"> import { ref } from 'vue' import { DCarouselIndicator } from 'vue-devui-carousel' const PageIndex = ref(2) </script> <template> <div> < button@click ="pageIndex = pageIndex - 1" @click="pageIndex = pageIndex + 1"> </button> <button @click="pageIndex = 1" :count="3" v-model="pageIndex"></DCarouselIndicator> </div> </template>Copy the code
Using the DCarouselIndicator component alone doesn’t seem to work, but it isn’t. Just using the DCarouselIndicator alone can sometimes achieve very cool and useful results, such as an accordion-style folding card.
4.2.4 Gameplay 4: Usedefault
The default slot implements the accordion folding card effect
I saw this effect in an article written by my battleKing classmates last August.
Accordion folding cards to show the effect
At first glance this effect doesn’t seem to have anything to do with the DCarouselIndicator, but if you think about it:
This is essentially a glorified version of the DCarouselIndicator component.
And DCarouselIndicator implementation does not require any JS code:
<script setup lang="ts"> import { DCarouselIndicator } from 'vue-devui-carousel' </script> <template> <div> <DCarouselIndicator> <template #default="pageInfo"> <! The following HTML snippet was copied from battleKing's gold digging article: https://juejin.cn/post/6991752974896726052 --> <div class="box"> <div :class="['panel', pageInfo.pageIndex === 1 ? 'active' : '']" @click="pageInfo.setPageIndex(1)"> <h3>Explore The World</h3> </div> <div :class="['panel', pageInfo.pageIndex === 2 ? 'active' : '']" @click="pageInfo.setPageIndex(2)"> <h3>Wild Forest</h3> </div> <div :class="['panel', pageInfo.pageIndex === 3 ? 'active' : '']" @click="pageInfo.setPageIndex(3)"> <h3>Sunny Beach</h3> </div> <div :class="['panel', pageInfo.pageIndex === 4 ? 'active' : '']" @click="pageInfo.setPageIndex(4)"> <h3>City on Winter</h3> </div> <div :class="['panel', pageInfo.pageIndex === 5 ? 'active' : '']" @click="pageInfo.setPageIndex(5)"> <h3>Mountains - Clouds</h3> </div> </div> </template> </DCarouselIndicator> </div> </template> <style> /* The following HTML fragment was copied from battleKing's article: https://juejin.cn/post/6991752974896726052 */ .box { display: flex; width: 90vw; } .panel { background-size: cover; background-position: center; background-repeat: no-repeat; height: 40vh; border-radius: 50px; color: #fff; cursor: pointer; Flex: 0.5; margin: 10px; position: relative; -webkit-transition: all 700ms ease-in; transition: all 700ms ease-in; } .panel:nth-child(1){ background-image: url("https://picsum.photos/1350/900? random=1"); } .panel:nth-child(2){ background-image: url("https://picsum.photos/1350/900? random=2"); } .panel:nth-child(3){ background-image: url("https://picsum.photos/1350/900? random=3"); } .panel:nth-child(4){ background-image: url("https://picsum.photos/1350/900? random=4"); } .panel:nth-child(5){ background-image: url("https://picsum.photos/1350/900? random=5"); } .panel h3 { font-size: 24px; position: absolute; bottom: 20px; left: 20px; margin: 0; opacity: 0; } .panel.active { flex: 5; } .panel.active h3 { opacity: 1; Transition: opacity 0.3s ease-in 0.4s; } </style>Copy the code
The effect is as follows:
Comprehensive case: to achieve the round-seeding effect of the home page of STATION B
In addition to being used alone, DCarouselIndicator can also be used with DCarousel. In fact, DCarousel’s built-in indicator is realized by using DCarouselIndicator.
The default indicator of DCarousel is at the bottom center, if I want to put it on the left, similar to the effect of B station home page rotation map.
<script setup lang="ts">
import { defineComponent, ref } from 'vue'
import { DCarousel, DCarouselIndicator, usePage } from 'vue-devui-carousel'
const { pageIndex, prevPage, nextPage, setPageIndex } = usePage(1)
</script>
<template>
<DCarousel v-model="pageIndex" class="carousel-demo-bilibili">
<div>
<div class="carousel-demo-item-bilibili">
<img src = 'https://s3.bmp.ovh/imgs/2022/01/40f0a4406ac09295.png' />
<div class="carousel-mask" style="background-color: rgb(22, 29, 38);"></div>
<div class="carousel-tool not-gray" data-gray="74" style="color:white;">
<a href="https://www.bilibili.com/blackboard/activity-gamereview2021.html" rel="noopener" target="_blank" data-target-url="https://www.bilibili.com/blackboard/activity-gamereview2021.html"><span>谁是游戏区播放TOP1?</span></a></div>
</div>
</div>
<div>
<div class="carousel-demo-item-bilibili">
<img src = 'https://s3.bmp.ovh/imgs/2022/01/5d3503df424141a1.jpg' />
<div class="carousel-mask" style="background-color: rgb(83, 73, 57);"></div>
<div class="carousel-tool not-gray" data-gray="74" style="color:white;"><a href="https://www.bilibili.com/blackboard/activity-gamereview2021.html" rel="noopener" target="_blank" data-target-url="https://www.bilibili.com/blackboard/activity-gamereview2021.html"><span>谁能拒绝可爱小狗呢?</span></a></div>
</div>
</div>
<div>
<div class="carousel-demo-item-bilibili">
<img src = 'https://s3.bmp.ovh/imgs/2022/01/5ed9080ff718b46b.jpg' />
<div class="carousel-mask" style="background-color: rgb(40, 36, 55);"></div>
<div class="carousel-tool not-gray" data-gray="74" style="color:white;">
<a href="https://www.bilibili.com/blackboard/activity-gamereview2021.html" rel="noopener" target="_blank" data-target-url="https://www.bilibili.com/blackboard/activity-gamereview2021.html"><span>守护解放西3热血归来!正义之魂,燃起来了!</span></a></div>
</div>
</div>
<div>
<div class="carousel-demo-item-bilibili">
<img src = 'https://s3.bmp.ovh/imgs/2022/01/1e952454566546f3.png' />
<div class="carousel-mask" style="background-color: rgb(61, 66, 63);"></div>
<div class="carousel-tool not-gray" data-gray="74" style="color:white;">
<a href="https://www.bilibili.com/blackboard/activity-gamereview2021.html" rel="noopener" target="_blank" data-target-url="https://www.bilibili.com/blackboard/activity-gamereview2021.html"><span>必听!TVB经典26首金曲回忆杀</span></a></div>
</div>
</div>
<div>
<div class="carousel-demo-item-bilibili">
<img src = 'https://s3.bmp.ovh/imgs/2022/01/17420d5be0805551.png' />
<div class="carousel-mask" style="background-color: rgb(77, 79, 74);"></div>
<div class="carousel-tool not-gray" data-gray="77" style="color:white;"><a href="https://www.bilibili.com/blackboard/activity-gamereview2021.html" rel="noopener" target="_blank" data-target-url="https://www.bilibili.com/blackboard/activity-gamereview2021.html"><span>原神2.4:云堇唱给你听</span></a></div>
</div>
</div>
<div>
<div class="carousel-demo-item-bilibili">
<img src = 'https://s3.bmp.ovh/imgs/2022/01/721ba44e91795ffb.png' />
<div class="carousel-mask" style="background-color: rgb(213, 89, 57);"></div>
<div class="carousel-tool not-gray" data-gray="122" style="color:white;"><a href="https://www.bilibili.com/blackboard/activity-gamereview2021.html" rel="noopener" target="_blank" data-target-url="https://www.bilibili.com/blackboard/activity-gamereview2021.html"><span>用视频的方式,记录新年!</span></a></div>
</div>
</div>
<template #indicator>
<div class="carousel-demo-bilibili-indicator-wrapper">
<DCarouselIndicator v-model="pageIndex" style="justify-content: flex-start;">
<div class="carousel-demo-bilibili-indicator-item-wrapper">
<div :class="['carousel-demo-bilibili-indicator-item', pageIndex === 1 && 'active']" @click="setPageIndex(1)"></div>
<div :class="['carousel-demo-bilibili-indicator-item', pageIndex === 2 && 'active']" @click="setPageIndex(2)"></div>
<div :class="['carousel-demo-bilibili-indicator-item', pageIndex === 3 && 'active']" @click="setPageIndex(3)"></div>
<div :class="['carousel-demo-bilibili-indicator-item', pageIndex === 4 && 'active']" @click="setPageIndex(4)"></div>
<div :class="['carousel-demo-bilibili-indicator-item', pageIndex === 5 && 'active']" @click="setPageIndex(5)"></div>
<div :class="['carousel-demo-bilibili-indicator-item', pageIndex === 6 && 'active']" @click="setPageIndex(6)"></div>
</div>
</DCarouselIndicator>
</div>
</template>
<template #pagination>
<div class="carousel-demo-bilibili-pagination-wrapper">
<div class="btn-page" @click="prevPage">
<svg width="18px" height="18px" viewBox="0 0 16 16" version="1.1"><g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"><polygon fill="#293040" fill-rule="nonzero" points="10.7071068 12.2928932 9.29289322 13.7071068 3.58578644 8 9.29289322 2.29289322 10.7071068 3.70710678 6.41421356 8"></polygon></g></svg>
</div>
<div class="btn-page" @click="nextPage">
<svg width="18px" height="18px" viewBox="0 0 16 16" version="1.1"><g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"><polygon fill="#293040" fill-rule="nonzero" transform="translate(8.146447, 8.000000) scale(-1, 1) translate(-8.146447, -8.000000) " points="11.7071068 12.2928932 10.2928932 13.7071068 4.58578644 8 10.2928932 2.29289322 11.7071068 3.70710678 7.41421356 8"></polygon></g></svg>
</div>
</div>
</template>
</DCarousel>
</template>
<style scoped>
img {
max-width: 100%;
}
.carousel-demo-bilibili {
width: 600px;
}
.carousel-demo-item-bilibili {
position: relative;
}
.carousel-demo-item-bilibili .carousel-mask {
width: 100%;
height: 100%;
position: absolute;
left: 0;
right: 0;
bottom: 0;
z-index: 1;
user-select: none;
pointer-events: none;
-webkit-mask-image: linear-gradient(0,#2f3238 11%,transparent 20%);
}
.carousel-demo-item-bilibili .carousel-tool {
position: absolute;
margin-top: 0;
flex-grow: 1;
z-index: 2;
transition: filter .3s cubic-bezier(.645,.045,.355,1);
bottom: 60px;
left: 15px;
color: #fff;
}
.carousel-demo-item-bilibili .carousel-tool a {
color: inherit;
font-size: 18px;
}
.carousel-demo-item-bilibili .carousel-tool a:hover {
text-decoration: none;
}
.carousel-demo-bilibili-indicator-wrapper {
z-index: 1;
position: absolute;
bottom: 20px;
padding-left: 15px;
width: 100%;
display: flex;
justify-content: flex-start;
}
.carousel-demo-bilibili-indicator-item {
position: relative;
display: inline-block;
width: 8px;
height: 8px;
margin: 4px;
border-radius: 50%;
background-color: rgba(255,255,255,.4);
overflow: hidden;
cursor: pointer;
}
.carousel-demo-bilibili-indicator-item.active {
width: 14px;
height: 14px;
margin: 1px;
border-radius: 50%;
background-color: #fff;
}
.carousel-demo-bilibili-pagination-wrapper {
position: absolute;
bottom: 50px;
right: 8px;
z-index: 2;
}
.carousel-demo-bilibili-pagination-wrapper .btn-page {
align-items: center;
justify-content: center;
display: inline-flex;
width: 28px;
height: 28px;
margin-right: 12px;
border-radius: 8px;
background-color: rgba(255,255,255,.1);
cursor: pointer;
color: #fff;
}
.carousel-demo-bilibili-pagination-wrapper .btn-page:hover {
background-color: rgba(255,255,255,.2);
}
</style>
Copy the code
The effect is as follows:
Look at the same effect as B station!
This example is slightly more complex, using DCarousel, DCarouselIndicator, usePage components and composables.
Let’s get rid of the extraneous HTML and styles and just focus on the core DCarousel usage.
DCarousel, DCarouselIndicator, and usePage were introduced first, and several key variables and methods were deconstructed from usePage.
<script setup lang="ts"> import {DCarousel, DCarouselIndicator, usePage} from 'vue-devui-carousel' 'usePage' is not required, but is only here to demonstrate how well you can use it together. const { pageIndex, prevPage, nextPage, setPageIndex } = usePage(1) </script>Copy the code
Then customize the HTML of the 3 slots of DCarousel. Use the DCarouselIndicator component in the Indicator slot area. We find that the Indicator slot exports the pageInfo parameter. From now on, the DCarouselIndicator is independent of the external usePage. To make the DCarouselIndicator to the left, add a line of CSS style style=” context-content: flex-start;” It’s very convenient and doesn’t require an indicator-position API.
<DCarousel v-model="pageIndex"> <! <div class="carousel-bilibili"> XXX </div>... <! <template #indicator="pageInfo"> <DCarouselIndicator V-model =" pageinfo.pageIndex" style="justify-content: flex-start;" > <div :class="['carousel-demo-bilibili-indicator-item', pageInfo.pageIndex === 1 && 'active']" @click="pageInfo.setPageIndex(1)"></div> ... </DCarouselIndicator> </template> <! <template #pagination> <div class="btn-page" @click="prevPage"></div> <div class="btn-page" @click="nextPage"></div> </div> </template> </DCarousel>Copy the code
The DCarouselPrev and DCarouselNext components are relatively simple, so you can explore the interesting gameplay on your own.
UsePage abstracts the UI-independent paging logic
Epage is also a Composable that is not really for Carousel but for Pagination paging components, but both components have one common UI-independent logic, paging, and this paging capability is hosted by usePage. In addition to these two, the pagination capability of ImagePreview is also provided by usePage.
We are DevUI open source team, join us and make a high quality component library together!
If you are interested, add DevUI assistant wechat: Devui-Official
Recommended reading:
Building Blocks theory of Front-end development – Do front-end development like building blocks
Design a flexible Carousel lantern assembly with building block theory
Using an accordion folding card example: Why don’t DCarouseIndicator use pageIndex on DCarousel directly?