完成轮播图组件
parent
f94730519a
commit
345b1d1bcc
|
@ -49,6 +49,7 @@
|
||||||
- [x] `wc-code`代码高亮插件
|
- [x] `wc-code`代码高亮插件
|
||||||
- [x] `wc-scroll`滚动组件
|
- [x] `wc-scroll`滚动组件
|
||||||
- [x] `wc-silder`面包屑组件
|
- [x] `wc-silder`面包屑组件
|
||||||
|
- [x] `wc-swipe`轮播图组件
|
||||||
- [x] `wc-breadcrumb`滑块组件
|
- [x] `wc-breadcrumb`滑块组件
|
||||||
- [ ] `wc-progress`进度条组件
|
- [ ] `wc-progress`进度条组件
|
||||||
- [ ] `wc-tree`树形菜单组件
|
- [ ] `wc-tree`树形菜单组件
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
/**
|
/**
|
||||||
* {}
|
* 轮播图组件
|
||||||
* @author chensbox<chensbox@foxmail.com>
|
* @author chensbox<chensbox@foxmail.com>
|
||||||
* @date 2023/03/26 16:14:10
|
* @date 2023/03/26 16:14:10
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { css, html, Component, nextTick } from '@bd/core'
|
import { css, html, Component, nextTick, styleMap } from '@bd/core'
|
||||||
import '../icon/index.js'
|
import '../icon/index.js'
|
||||||
const CARD_SCALE = 0.83
|
const CARD_SCALE = 0.83
|
||||||
function createWatcher(object, key, effect) {
|
function createWatcher(object, key, effect) {
|
||||||
|
@ -19,7 +19,7 @@ function createWatcher(object, key, effect) {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
class Carousel extends Component {
|
class Swipe extends Component {
|
||||||
static props = {
|
static props = {
|
||||||
'initial-index': {
|
'initial-index': {
|
||||||
type: Number,
|
type: Number,
|
||||||
|
@ -34,7 +34,7 @@ class Carousel extends Component {
|
||||||
},
|
},
|
||||||
trigger: {
|
trigger: {
|
||||||
type: String,
|
type: String,
|
||||||
default: 'hover'
|
default: 'hover' // hover or click
|
||||||
},
|
},
|
||||||
autoplay: {
|
autoplay: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
|
@ -47,23 +47,26 @@ class Carousel extends Component {
|
||||||
type: Number,
|
type: Number,
|
||||||
default: 3000
|
default: 3000
|
||||||
},
|
},
|
||||||
'indicator-position': { String, attributes: false },
|
|
||||||
indicator: {
|
indicator: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: true
|
default: true
|
||||||
},
|
},
|
||||||
arrow: {
|
arrow: {
|
||||||
type: String,
|
type: String,
|
||||||
default: 'hover'
|
default: 'hover' // hover or alway
|
||||||
|
},
|
||||||
|
type: {
|
||||||
|
type: String,
|
||||||
|
default: '', // '' or card
|
||||||
|
attributes: false
|
||||||
},
|
},
|
||||||
type: { type: String, default: '', attributes: false },
|
|
||||||
loop: {
|
loop: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: true
|
default: true
|
||||||
},
|
},
|
||||||
direction: {
|
direction: {
|
||||||
type: String,
|
type: String,
|
||||||
default: 'horizontal'
|
default: 'horizontal' // horizontal or vertical
|
||||||
},
|
},
|
||||||
'pause-on-hover': {
|
'pause-on-hover': {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
|
@ -77,7 +80,34 @@ class Carousel extends Component {
|
||||||
display: block;
|
display: block;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
:host([direction='vertical']) {
|
||||||
|
.indicator {
|
||||||
|
flex-direction: column;
|
||||||
|
left: calc(100% - 26px);
|
||||||
|
top: 50%;
|
||||||
|
height: 80%;
|
||||||
|
width: 26px;
|
||||||
|
transform: translatey(-50%);
|
||||||
|
li {
|
||||||
|
width: 26px;
|
||||||
|
height: 24px;
|
||||||
|
margin: 5px 0;
|
||||||
|
&::after {
|
||||||
|
position: absolute;
|
||||||
|
content: '';
|
||||||
|
left: calc(50% - 2px);
|
||||||
|
top: 0;
|
||||||
|
height: 100%;
|
||||||
|
width: 2px;
|
||||||
|
background-color: #fff;
|
||||||
|
opacity: 0.48;
|
||||||
|
}
|
||||||
|
&.active::after {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
.toggle-btn {
|
.toggle-btn {
|
||||||
z-index: 4;
|
z-index: 4;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
|
@ -86,7 +116,7 @@ class Carousel extends Component {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
opacity: 0.8;
|
opacity: 0;
|
||||||
width: 33px;
|
width: 33px;
|
||||||
height: 33px;
|
height: 33px;
|
||||||
font-size: 24px;
|
font-size: 24px;
|
||||||
|
@ -95,6 +125,11 @@ class Carousel extends Component {
|
||||||
border-color: #fff;
|
border-color: #fff;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
--size: 12px;
|
--size: 12px;
|
||||||
|
transition: opacity linear 0.2s;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
opacity: 0.8 !important;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.left,
|
.left,
|
||||||
.right {
|
.right {
|
||||||
|
@ -102,10 +137,43 @@ class Carousel extends Component {
|
||||||
transform: translateY(-50%);
|
transform: translateY(-50%);
|
||||||
}
|
}
|
||||||
.left {
|
.left {
|
||||||
left: 5%;
|
left: 3%;
|
||||||
}
|
}
|
||||||
.right {
|
.right {
|
||||||
right: 5%;
|
right: 3%;
|
||||||
|
}
|
||||||
|
.indicator {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
position: absolute;
|
||||||
|
width: 80%;
|
||||||
|
bottom: 0px;
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
li {
|
||||||
|
position: relative;
|
||||||
|
width: 24px;
|
||||||
|
height: 26px;
|
||||||
|
margin: 0 5px;
|
||||||
|
list-style: none;
|
||||||
|
&::after {
|
||||||
|
position: absolute;
|
||||||
|
content: '';
|
||||||
|
left: 0;
|
||||||
|
top: calc(50% - 2px);
|
||||||
|
width: 100%;
|
||||||
|
height: 2px;
|
||||||
|
background-color: #fff;
|
||||||
|
opacity: 0.48;
|
||||||
|
}
|
||||||
|
&:hover {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
&.active::after {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
items = []
|
items = []
|
||||||
|
@ -114,7 +182,7 @@ class Carousel extends Component {
|
||||||
|
|
||||||
updateItems() {
|
updateItems() {
|
||||||
this.items = Array.from(this.children).filter(
|
this.items = Array.from(this.children).filter(
|
||||||
item => item.tagName === 'WC-CAROUSEL-ITEM'
|
item => item.tagName === 'WC-SWIPE-ITEM'
|
||||||
)
|
)
|
||||||
nextTick(() => this.$requestUpdate())
|
nextTick(() => this.$requestUpdate())
|
||||||
}
|
}
|
||||||
|
@ -147,6 +215,7 @@ class Carousel extends Component {
|
||||||
this.items.forEach((item, index) => {
|
this.items.forEach((item, index) => {
|
||||||
item.translateItem(index, this.activeIndex, oldIndex)
|
item.translateItem(index, this.activeIndex, oldIndex)
|
||||||
})
|
})
|
||||||
|
nextTick(() => this.$requestUpdate())
|
||||||
}
|
}
|
||||||
setActiveItem(index) {
|
setActiveItem(index) {
|
||||||
const now = Date.now()
|
const now = Date.now()
|
||||||
|
@ -176,12 +245,18 @@ class Carousel extends Component {
|
||||||
if (oldIndex !== this.activeIndex) {
|
if (oldIndex !== this.activeIndex) {
|
||||||
this.resetItemPosition(oldIndex)
|
this.resetItemPosition(oldIndex)
|
||||||
}
|
}
|
||||||
// this.resetItemPosition(oldIndex)
|
|
||||||
this.resetTimer()
|
this.resetTimer()
|
||||||
|
nextTick(() => this.$requestUpdate())
|
||||||
}
|
}
|
||||||
handleIndicatorHover(index) {
|
handleIndicatorHover(event) {
|
||||||
|
let index = +event.target.getAttribute('index')
|
||||||
if (this.trigger === 'hover' && index !== this.activeIndex) {
|
if (this.trigger === 'hover' && index !== this.activeIndex) {
|
||||||
// this.activeIndex = index
|
this.setActiveItem(index)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
handleClickIndicator(event) {
|
||||||
|
let index = +event.target.getAttribute('index')
|
||||||
|
if (this.trigger === 'click' && index !== this.activeIndex) {
|
||||||
this.setActiveItem(index)
|
this.setActiveItem(index)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -191,6 +266,18 @@ class Carousel extends Component {
|
||||||
next() {
|
next() {
|
||||||
this.setActiveItem(this.activeIndex + 1)
|
this.setActiveItem(this.activeIndex + 1)
|
||||||
}
|
}
|
||||||
|
showArrow() {
|
||||||
|
this.showArrowBtn = true
|
||||||
|
this.$requestUpdate()
|
||||||
|
}
|
||||||
|
hideArrow() {
|
||||||
|
this.showArrowBtn = false
|
||||||
|
this.$requestUpdate()
|
||||||
|
}
|
||||||
|
handleSlotChange() {
|
||||||
|
this.updateItems()
|
||||||
|
this.resetItemPosition()
|
||||||
|
}
|
||||||
mounted() {
|
mounted() {
|
||||||
this.updateItems()
|
this.updateItems()
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
|
@ -202,6 +289,18 @@ class Carousel extends Component {
|
||||||
this.resizeObserve.observe(this)
|
this.resizeObserve.observe(this)
|
||||||
this.startTimer()
|
this.startTimer()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
if (this['pause-on-hover']) {
|
||||||
|
this.$on('mouseenter', () => this.pauseTimer())
|
||||||
|
this.$on('mouseleave', () => this.startTimer())
|
||||||
|
}
|
||||||
|
if (this.arrow === 'hover') {
|
||||||
|
this.$on('mouseenter', () => this.showArrow())
|
||||||
|
this.$on('mouseleave', () => this.hideArrow())
|
||||||
|
} else if (this.arrow === 'alway') {
|
||||||
|
this.showArrowBtn = true
|
||||||
|
this.$requestUpdate()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
unmounted() {
|
unmounted() {
|
||||||
this.resizeObserve.disconnect()
|
this.resizeObserve.disconnect()
|
||||||
|
@ -209,23 +308,46 @@ class Carousel extends Component {
|
||||||
this.pauseTimer()
|
this.pauseTimer()
|
||||||
}
|
}
|
||||||
render() {
|
render() {
|
||||||
return html`
|
let styles = styleMap({
|
||||||
<div class="container" style=${`height:${this.height}px`}>
|
opacity: this.showArrowBtn ? 0.5 : 0
|
||||||
<slot></slot>
|
})
|
||||||
<div class="left toggle-btn" @click=${this.prev}>
|
let toggleBtns =
|
||||||
|
this.direction === 'horizontal'
|
||||||
|
? html`
|
||||||
|
<div class="left toggle-btn" style=${styles} @click=${this.prev}>
|
||||||
<wc-icon name="left"></wc-icon>
|
<wc-icon name="left"></wc-icon>
|
||||||
</div>
|
</div>
|
||||||
<div class="right toggle-btn" @click=${this.next}>
|
<div class="right toggle-btn" style=${styles} @click=${this.next}>
|
||||||
<wc-icon name="right"></wc-icon>
|
<wc-icon name="right"></wc-icon>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
`
|
||||||
<ul>
|
: ''
|
||||||
${this.items.map(_ => html`<li>3</li>`)}
|
|
||||||
|
let indicator = this.indicator
|
||||||
|
? html`
|
||||||
|
<ul class="indicator" @click=${this.handleClickIndicator}>
|
||||||
|
${this.items.map(
|
||||||
|
(item, index) =>
|
||||||
|
html` <li
|
||||||
|
index=${index}
|
||||||
|
class=${this.activeIndex === index ? 'active' : ''}
|
||||||
|
@mouseenter=${this.handleIndicatorHover}
|
||||||
|
></li>`
|
||||||
|
)}
|
||||||
</ul>
|
</ul>
|
||||||
`
|
`
|
||||||
|
: ''
|
||||||
|
|
||||||
|
return html`
|
||||||
|
<div class="container" style=${`height:${this.height}px`}>
|
||||||
|
<slot @slotchange=${this.handleSlotChange}></slot>
|
||||||
|
${toggleBtns}
|
||||||
|
</div>
|
||||||
|
${indicator}
|
||||||
|
`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
class CarouselItem extends Component {
|
class SwipeItem extends Component {
|
||||||
static props = {
|
static props = {
|
||||||
name: { String, attributes: false }
|
name: { String, attributes: false }
|
||||||
}
|
}
|
||||||
|
@ -248,7 +370,8 @@ class CarouselItem extends Component {
|
||||||
:host([card]) {
|
:host([card]) {
|
||||||
width: 50%;
|
width: 50%;
|
||||||
transition-duration: 400ms;
|
transition-duration: 400ms;
|
||||||
transition-property: transform, opacity;
|
transition-property: transform, opacity, filter;
|
||||||
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
static watch = {
|
static watch = {
|
||||||
|
@ -269,16 +392,22 @@ class CarouselItem extends Component {
|
||||||
if (this.$parent.type !== 'card') {
|
if (this.$parent.type !== 'card') {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
this.style.opacity = 1
|
let style = {
|
||||||
|
opacity: 1,
|
||||||
|
'z-index': 1,
|
||||||
|
filter: 'brightness(0.8)'
|
||||||
|
}
|
||||||
if (this.inStage) {
|
if (this.inStage) {
|
||||||
this.style['z-index'] = 1
|
style['z-index'] = 1
|
||||||
} else {
|
} else {
|
||||||
this.style['z-index'] = -1
|
style['z-index'] = -1
|
||||||
this.style.opacity = 0
|
style.opacity = 0
|
||||||
}
|
}
|
||||||
if (val) {
|
if (val) {
|
||||||
this.style['z-index'] = 2
|
style['z-index'] = 2
|
||||||
|
style.filter = 'brightness(1)'
|
||||||
}
|
}
|
||||||
|
Object.assign(this.style, style)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
processIndex(index, activeIndex, length) {
|
processIndex(index, activeIndex, length) {
|
||||||
|
@ -347,9 +476,11 @@ class CarouselItem extends Component {
|
||||||
this.$parent = this.parentNode
|
this.$parent = this.parentNode
|
||||||
if (this.$parent.type === 'card') {
|
if (this.$parent.type === 'card') {
|
||||||
this.setAttribute('card', '')
|
this.setAttribute('card', '')
|
||||||
|
const index = this.$parent.items.indexOf(this)
|
||||||
|
this.$on('click', () => this.$parent.setActiveItem(index))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Carousel.reg('carousel')
|
Swipe.reg('swipe')
|
||||||
CarouselItem.reg('carousel-item')
|
SwipeItem.reg('swipe-item')
|
Loading…
Reference in New Issue