fix(carousel): [carousel]modify smb theme (#2125)

This commit is contained in:
James 2024-09-13 18:37:58 -07:00 committed by GitHub
parent 5bce345e3b
commit 9100eb93c7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 258 additions and 35 deletions

View File

@ -111,6 +111,21 @@ export default {
pcDemo: 'close-loop', pcDemo: 'close-loop',
mfDemo: '' mfDemo: ''
}, },
{
name: 'disabled',
type: 'boolean',
defaultValue: 'false',
desc: {
'zh-CN': '控制轮播箭头禁用状态,设置为 true 则禁用',
'en-US': 'Control the disabled state of the carousel arrow, set to true to disable'
},
meta: {
stable: '3.19.0'
},
mode: ['pc'],
pcDemo: 'close-loop',
mfDemo: ''
},
{ {
name: 'show-title', name: 'show-title',
type: 'boolean', type: 'boolean',

View File

@ -1,8 +1,16 @@
<template> <template>
<tiny-carousel height="300px" arrow="always" indicator-position="outside"> <tiny-carousel arrow="never" height="300px" indicator-position="none" ref="carouselRef" :initial-index="index - 1">
<div class="btn-layout">
<div>
<tiny-button type="text" @click="prev" :disabled="disabledLeft" :icon="TinyIconChevronLeft"> </tiny-button>
</div>
<div>
<tiny-button type="text" @click="next" :disabled="disabledRight" :icon="TinyIconChevronRight"></tiny-button>
</div>
</div>
<tiny-carousel-item class="carousel-item-demo" v-for="(item, pos) in state.cardData" :key="item"> <tiny-carousel-item class="carousel-item-demo" v-for="(item, pos) in state.cardData" :key="item">
<template #default> <template #default>
<div v-for="num in state.cardData.length" :key="num"> <div class="card-layout" v-for="num in state.cardData.length" :key="num">
<div v-if="num === pos + 1" :class="['card-dsp']"> <div v-if="num === pos + 1" :class="['card-dsp']">
<tiny-card <tiny-card
v-for="(child, childIndex) in item.children" v-for="(child, childIndex) in item.children"
@ -23,10 +31,23 @@
</template> </template>
<script setup> <script setup>
import { ref, reactive } from 'vue' import { ref, reactive, onMounted } from 'vue'
import { Carousel as TinyCarousel, CarouselItem as TinyCarouselItem, Card as TinyCard } from '@opentiny/vue' import {
Carousel as TinyCarousel,
CarouselItem as TinyCarouselItem,
Card as TinyCard,
Button as TinyButton
} from '@opentiny/vue'
import { IconChevronRight, IconChevronLeft } from '@opentiny/vue-icon'
const TinyIconChevronRight = IconChevronRight()
const TinyIconChevronLeft = IconChevronLeft()
let curIndex = ref(0) let curIndex = ref(0)
const index = ref(1)
let disabledLeft = ref(false)
let disabledRight = ref(false)
const carouselRef = ref()
const dsj = ref(`${import.meta.env.VITE_APP_BUILD_BASE_URL}static/images/dsj.png`) const dsj = ref(`${import.meta.env.VITE_APP_BUILD_BASE_URL}static/images/dsj.png`)
const userHead = ref(`${import.meta.env.VITE_APP_BUILD_BASE_URL}static/images/user-head.png`) const userHead = ref(`${import.meta.env.VITE_APP_BUILD_BASE_URL}static/images/user-head.png`)
const state = reactive({ const state = reactive({
@ -78,25 +99,99 @@ const state = reactive({
cardType: 'logo', cardType: 'logo',
cardSrc: `${userHead.value}`, cardSrc: `${userHead.value}`,
content: '1-3-content' content: '1-3-content'
},
{
cardTitle: '2-4',
cardType: 'logo',
cardSrc: `${userHead.value}`,
content: '2-4-content'
} }
] ]
} }
] ]
}) })
onMounted(() => {
disableStatus()
})
const next = () => {
index.value = Math.min(index.value + 1, 8)
carouselRef.value.next()
disableStatus()
}
const prev = () => {
index.value = Math.max(index.value - 1, 0)
carouselRef.value.prev()
disableStatus()
}
const disableStatus = () => {
disabledRight.value = false
disabledLeft.value = false
if (index.value === 1) {
disabledLeft.value = true
disabledRight.value = false
}
if (index.value === state.cardData.length) {
disabledRight.value = true
disabledLeft.value = false
}
}
</script> </script>
<style scoped> <style lang="less" scoped>
.carousel-item-demo {
display: flex;
justify-content: center;
}
.card-dsp { .card-dsp {
display: flex; display: flex;
justify-content: flex-start; justify-content: flex-start;
padding: 0 4px 0 12px; align-items: center;
height: 100%;
} }
.mb { .mb {
margin-bottom: 20px; margin-bottom: 20px;
} }
.card-demo { .card-demo {
width: 25%; width: 25%;
height: 300px;
margin-right: 8px; margin-right: 8px;
height: 200px;
&:last-child {
margin-right: 0;
}
&:hover {
border-color: #1476ff;
}
}
.btn-layout {
position: relative;
display: flex;
justify-content: space-between;
top: 45%;
z-index: 10;
padding: 0 76px;
}
/deep/ .tiny-button.tiny-button--text.tiny-button.is-only-icon {
font-size: 16px;
border: none;
.tiny-svg {
fill: #808080;
}
&.is-disabled {
.tiny-svg {
fill: #c2c2c2;
}
}
&:hover {
background-color: transparent;
}
&:not(.is-disabled) {
.tiny-svg:hover {
fill: #191919;
}
}
} }
</style> </style>

View File

@ -4,15 +4,11 @@ test('轮播卡片', async ({ page }) => {
page.on('pageerror', (exception) => expect(exception).toBeNull()) page.on('pageerror', (exception) => expect(exception).toBeNull())
await page.goto('carousel#card-show') await page.goto('carousel#card-show')
const preview = page.locator('#card-show') const preview = page.locator('#card-show')
await preview const btnRight = preview.getByRole('button').nth(1)
.locator('div') await btnRight.click()
.filter({ hasText: /^1-11-1-content$/ })
.first()
.click()
await preview.getByRole('button').nth(1).click()
await preview await preview
.locator('div') .locator('div')
.filter({ hasText: /^2-11-1-content$/ }) .filter({ hasText: /^2-11-1-content$/ })
.first() .first()
.click() expect(btnRight).toHaveCSS('fill', 'rgb(194, 194, 194)')
}) })

View File

@ -1,8 +1,16 @@
<template> <template>
<tiny-carousel height="300px" arrow="always" indicator-position="outside"> <tiny-carousel arrow="never" height="300px" indicator-position="none" ref="carouselRef" :initial-index="index - 1">
<div class="btn-layout">
<div>
<tiny-button type="text" @click="prev" :disabled="disabledLeft" :icon="TinyIconChevronLeft"> </tiny-button>
</div>
<div>
<tiny-button type="text" @click="next" :disabled="disabledRight" :icon="TinyIconChevronRight"></tiny-button>
</div>
</div>
<tiny-carousel-item class="carousel-item-demo" v-for="(item, pos) in cardData" :key="item"> <tiny-carousel-item class="carousel-item-demo" v-for="(item, pos) in cardData" :key="item">
<template #default> <template #default>
<div v-for="num in cardData.length" :key="num"> <div class="card-layout" v-for="num in cardData.length" :key="num">
<div v-if="num === pos + 1" :class="['card-dsp']"> <div v-if="num === pos + 1" :class="['card-dsp']">
<tiny-card <tiny-card
v-for="(child, childIndex) in item.children" v-for="(child, childIndex) in item.children"
@ -23,17 +31,24 @@
</template> </template>
<script> <script>
import { Carousel, CarouselItem, Card } from '@opentiny/vue' import { Carousel, CarouselItem, Card, Button } from '@opentiny/vue'
import { IconChevronRight, IconChevronLeft } from '@opentiny/vue-icon'
export default { export default {
components: { components: {
TinyCarousel: Carousel, TinyCarousel: Carousel,
TinyCarouselItem: CarouselItem, TinyCarouselItem: CarouselItem,
TinyCard: Card TinyCard: Card,
TinyButton: Button
}, },
data() { data() {
return { return {
TinyIconChevronRight: IconChevronRight(),
TinyIconChevronLeft: IconChevronLeft(),
curIndex: 0, curIndex: 0,
index: 1,
disabledLeft: false,
disabledRight: false,
cardData: [ cardData: [
{ {
children: [ children: [
@ -82,27 +97,99 @@ export default {
cardType: 'logo', cardType: 'logo',
cardSrc: `/static/images/user-head.png`, cardSrc: `/static/images/user-head.png`,
content: '1-3-content' content: '1-3-content'
},
{
cardTitle: '2-4',
cardType: 'logo',
cardSrc: `/static/images/user-head.png`,
content: '2-4-content'
} }
] ]
} }
] ]
} }
},
mounted() {
this.disableStatus()
},
methods: {
next() {
this.index = Math.min(this.index + 1, 8)
this.$refs.carouselRef.next()
this.disableStatus()
},
prev() {
this.index = Math.max(this.index - 1, 0)
this.$refs.carouselRef.prev()
this.disableStatus()
},
disableStatus() {
this.disabledRight = false
this.disabledLeft = false
if (this.index === 1) {
this.disabledLeft = true
this.disabledRight = false
}
if (this.index === this.cardData.length) {
this.disabledRight = true
this.disabledLeft = false
}
}
} }
} }
</script> </script>
<style scoped> <style lang="less" scoped>
.carousel-item-demo {
display: flex;
justify-content: center;
}
.card-dsp { .card-dsp {
display: flex; display: flex;
justify-content: flex-start; justify-content: flex-start;
padding: 0 4px 0 12px; align-items: center;
height: 100%;
} }
.mb { .mb {
margin-bottom: 20px; margin-bottom: 20px;
} }
.card-demo { .card-demo {
width: 25%; width: 25%;
height: 300px;
margin-right: 8px; margin-right: 8px;
height: 200px;
&:last-child {
margin-right: 0;
}
&:hover {
border-color: #1476ff;
}
}
.btn-layout {
position: relative;
display: flex;
justify-content: space-between;
top: 45%;
z-index: 10;
padding: 0 76px;
}
/deep/ .tiny-button.tiny-button--text.tiny-button.is-only-icon {
font-size: 16px;
border: none;
.tiny-svg {
fill: #808080;
}
&.is-disabled {
.tiny-svg {
fill: #c2c2c2;
}
}
&:hover {
background-color: transparent;
}
&:not(.is-disabled) {
.tiny-svg:hover {
fill: #191919;
}
}
} }
</style> </style>

View File

@ -1,5 +1,5 @@
<template> <template>
<tiny-carousel height="150px" :loop="false" arrow="always"> <tiny-carousel height="150px" loop :disabled="true" arrow="always">
<tiny-carousel-item class="carousel-item-demo" v-for="item in 3" :key="item"> <tiny-carousel-item class="carousel-item-demo" v-for="item in 3" :key="item">
<h3>{{ item }}</h3> <h3>{{ item }}</h3>
</tiny-carousel-item> </tiny-carousel-item>

View File

@ -9,7 +9,7 @@ test('关闭循环轮播', async ({ page }) => {
const arrow = carousel.locator('.tiny-carousel__arrow') const arrow = carousel.locator('.tiny-carousel__arrow')
// 左侧切换按钮应该不可见 // 左侧切换按钮应该不可见
await expect(arrow.first()).not.toBeVisible() await expect(arrow.first()).toBeVisible()
// 点击下一张按钮 // 点击下一张按钮
await arrow.nth(1).click() await arrow.nth(1).click()
// 当前应该显示第二张幻灯片 // 当前应该显示第二张幻灯片
@ -18,7 +18,7 @@ test('关闭循环轮播', async ({ page }) => {
// 当前应该显示第三张幻灯片 // 当前应该显示第三张幻灯片
await expect(carouselItems.nth(2)).toHaveCSS('transform', 'matrix(1, 0, 0, 1, 0, 0)') await expect(carouselItems.nth(2)).toHaveCSS('transform', 'matrix(1, 0, 0, 1, 0, 0)')
// 右侧切换按钮应该不可见 // 右侧切换按钮应该不可见
await expect(arrow.nth(1)).not.toBeVisible() await expect(arrow.nth(1)).toBeVisible()
// 点击上一张按钮 // 点击上一张按钮
await arrow.first().click() await arrow.first().click()
// 当前应该显示第一张幻灯片 // 当前应该显示第一张幻灯片

View File

@ -1,5 +1,5 @@
<template> <template>
<tiny-carousel height="150px" :loop="false" arrow="always"> <tiny-carousel height="150px" loop :disabled="true" arrow="always">
<tiny-carousel-item class="carousel-item-demo" v-for="item in 3" :key="item"> <tiny-carousel-item class="carousel-item-demo" v-for="item in 3" :key="item">
<h3>{{ item }}</h3> <h3>{{ item }}</h3>
</tiny-carousel-item> </tiny-carousel-item>

View File

@ -52,9 +52,9 @@ export default {
}, },
desc: { desc: {
'zh-CN': 'zh-CN':
'<p>通过配置 <code>loop</code> 属性为<code>false</code>后,若走马灯幻灯片已切换到最后一项,则将不能再从第一项开始循环切换。即切换到最后一项时,右侧切换箭头不再显示,切换到第一项时,左侧切换箭头不再显示。</p>\n', '<p>通过配置 <code>loop</code> 属性为<code>true</code><code>disabled</code> 属性为<code>true</code>后,若走马灯幻灯片已切换到最后一项,则将不能再从第一项开始循环切换。即切换到最后一项时,右侧切换箭头不再显示,切换到第一项时,左侧切换箭头不再显示。</p>\n',
'en-US': 'en-US':
'<p>After the <code>loop</code> attribute is set to <code>false</code>, if the slide is switched to the last item, the slide cannot be switched cyclically from the first item. That is, when switching to the last item, the right toggle arrow is no longer displayed, and when switching to the first item, the left toggle arrow is no longer displayed. </p>\n' '<p>After the <code>loop</code> attribute is set to <code>true</code> and the <code>disabled</code> attribute is set to <code>true</code> if the slide is switched to the last item, the slide cannot be switched cyclically from the first item. That is, when switching to the last item, the right toggle arrow is no longer displayed, and when switching to the first item, the left toggle arrow is no longer displayed. </p>\n'
}, },
codeFiles: ['close-loop.vue'] codeFiles: ['close-loop.vue']
}, },

View File

@ -59,6 +59,9 @@
.@{svg-prefix-cls} { .@{svg-prefix-cls} {
fill: var(--ti-carousel-indicator-active-text-color); fill: var(--ti-carousel-indicator-active-text-color);
&:hover {
fill: var(--ti-carousel-indicator-hover-text-color);
}
} }
&.@{carousel-prefix-cls}__arrow-left { &.@{carousel-prefix-cls}__arrow-left {
@ -86,7 +89,15 @@
@apply ~'-translate-x-2/4'; @apply ~'-translate-x-2/4';
} }
&:hover { &.@{carousel-prefix-cls}__arrow-disabled {
background-color: var(--ti-carousel-arrow-disabled-bg-color);
cursor: not-allowed;
.@{svg-prefix-cls} {
fill: var(--ti-carousel-arrow-disabled-color);
}
}
&:not(.@{carousel-prefix-cls}__arrow-disabled):hover {
background-color: var(--ti-carousel-arrow-hover-bg-color); background-color: var(--ti-carousel-arrow-hover-bg-color);
color: var(--ti-carousel-arrow-hover-text-color); color: var(--ti-carousel-arrow-hover-text-color);
} }

View File

@ -36,7 +36,9 @@
// 指示器圆角的背景色(hide) // 指示器圆角的背景色(hide)
--ti-carousel-indicators-radius-bg-color: rgba(0, 0, 0, 0.3); --ti-carousel-indicators-radius-bg-color: rgba(0, 0, 0, 0.3);
// 幻灯片内的当前指示器图标色 // 幻灯片内的当前指示器图标色
--ti-carousel-indicator-active-text-color: var(--ti-common-color-text-primary); --ti-carousel-indicator-active-text-color: var(--ti-common-color-icon-normal);
// 幻灯片内的悬浮指示器图标色
--ti-carousel-indicator-hover-text-color: var(--ti-common-color-primary-normal);
// 指示器按钮宽度 // 指示器按钮宽度
--ti-carousel-indicator-button-width: var(--ti-common-size-2x, 8px); --ti-carousel-indicator-button-width: var(--ti-common-size-2x, 8px);
// 指示器按钮高度 // 指示器按钮高度
@ -74,7 +76,11 @@
// 箭头悬浮文本颜色(hide) // 箭头悬浮文本颜色(hide)
--ti-carousel-arrow-hover-text-color: var(--ti-common-color-text-primary); --ti-carousel-arrow-hover-text-color: var(--ti-common-color-text-primary);
// 左侧箭头背景色 // 左侧箭头背景色
--ti-carousel-arrow-left-bg-color: #f5f5f5; --ti-carousel-arrow-left-bg-color: var(--ti-common-color-bg-normal);
// 右侧箭头背景色 // 右侧箭头背景色
--ti-carousel-arrow-right-bg-color: #f5f5f5; --ti-carousel-arrow-right-bg-color: var(--ti-common-color-bg-normal);
// 按钮禁用色
--ti-carousel-arrow-disabled-bg-color: var(--ti-common-color-bg-disabled);
// 按钮禁用色
--ti-carousel-arrow-disabled-color: var(--ti-common-color-primary-disabled-text);
} }

View File

@ -46,6 +46,10 @@ export default defineComponent({
type: Boolean, type: Boolean,
default: true default: true
}, },
disabled: {
type: Boolean,
default: false
},
indicatorPosition: String, indicatorPosition: String,
arrow: { arrow: {
type: String, type: String,

View File

@ -24,8 +24,12 @@
v-if="state.hasButtons" v-if="state.hasButtons"
v-show="(arrow === 'always' || state.hover) && (loop || state.activeIndex > 0)" v-show="(arrow === 'always' || state.hover) && (loop || state.activeIndex > 0)"
type="button" type="button"
class="tiny-carousel__arrow" :class="[
:class="type === 'vertical' ? 'tiny-carousel__arrow-top' : 'tiny-carousel__arrow-left'" 'tiny-carousel__arrow',
type === 'vertical' ? 'tiny-carousel__arrow-top' : 'tiny-carousel__arrow-left',
disabled && state.activeIndex === 0 ? 'tiny-carousel__arrow-disabled' : ''
]"
:disabled="loop && disabled && state.activeIndex === 0"
@mouseenter="handleButtonEnter('left')" @mouseenter="handleButtonEnter('left')"
@mouseleave="handleButtonLeave" @mouseleave="handleButtonLeave"
@click.stop="throttledArrowClick(state.activeIndex - 1)" @click.stop="throttledArrowClick(state.activeIndex - 1)"
@ -40,8 +44,12 @@
v-if="state.hasButtons" v-if="state.hasButtons"
v-show="(arrow === 'always' || state.hover) && (loop || state.activeIndex < state.items.length - 1)" v-show="(arrow === 'always' || state.hover) && (loop || state.activeIndex < state.items.length - 1)"
type="button" type="button"
class="tiny-carousel__arrow" :class="[
:class="type === 'vertical' ? 'tiny-carousel__arrow-bottom' : 'tiny-carousel__arrow-right'" 'tiny-carousel__arrow',
type === 'vertical' ? 'tiny-carousel__arrow-bottom' : 'tiny-carousel__arrow-right',
disabled && state.activeIndex === state.items.length - 1 ? 'tiny-carousel__arrow-disabled' : ''
]"
:disabled="loop && disabled && state.activeIndex === state.items.length - 1"
@mouseenter="handleButtonEnter('right')" @mouseenter="handleButtonEnter('right')"
@mouseleave="handleButtonLeave" @mouseleave="handleButtonLeave"
@click.stop="throttledArrowClick(state.activeIndex + 1)" @click.stop="throttledArrowClick(state.activeIndex + 1)"
@ -97,6 +105,7 @@ export default defineComponent({
'type', 'type',
'showTitle', 'showTitle',
'loop', 'loop',
'disabled',
'swipeable', 'swipeable',
'lite', 'lite',
'beforeSwipe' 'beforeSwipe'