diff --git a/Readme.md b/Readme.md index 778a411..55d817e 100644 --- a/Readme.md +++ b/Readme.md @@ -48,8 +48,9 @@ - [ ] `wc-timepicker`时间选择器 - [x] `wc-code`代码高亮插件 - [x] `wc-scroll`滚动组件 -- [x] `wc-silder`面包屑组件 -- [x] `wc-breadcrumb`滑块组件 +- [x] `wc-silder`滑块组件 +- [x] `wc-swipe`轮播图组件 +- [x] `wc-breadcrumb` 面包屑组件 - [ ] `wc-progress`进度条组件 - [ ] `wc-tree`树形菜单组件 - [ ] `wc-uploader`上传组件 diff --git a/src/carousel/index.js b/src/swipe/index.js similarity index 63% rename from src/carousel/index.js rename to src/swipe/index.js index 389ab75..5edb03c 100644 --- a/src/carousel/index.js +++ b/src/swipe/index.js @@ -1,10 +1,10 @@ /** - * {} + * 轮播图组件 * @author chensbox * @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' const CARD_SCALE = 0.83 function createWatcher(object, key, effect) { @@ -19,7 +19,7 @@ function createWatcher(object, key, effect) { } }) } -class Carousel extends Component { +class Swipe extends Component { static props = { 'initial-index': { type: Number, @@ -34,7 +34,7 @@ class Carousel extends Component { }, trigger: { type: String, - default: 'hover' + default: 'hover' // hover or click }, autoplay: { type: Boolean, @@ -47,23 +47,26 @@ class Carousel extends Component { type: Number, default: 3000 }, - 'indicator-position': { String, attributes: false }, indicator: { type: Boolean, default: true }, arrow: { type: String, - default: 'hover' + default: 'hover' // hover or alway + }, + type: { + type: String, + default: '', // '' or card + attributes: false }, - type: { type: String, default: '', attributes: false }, loop: { type: Boolean, default: true }, direction: { type: String, - default: 'horizontal' + default: 'horizontal' // horizontal or vertical }, 'pause-on-hover': { type: Boolean, @@ -77,7 +80,34 @@ class Carousel extends Component { display: block; 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 { z-index: 4; user-select: none; @@ -86,7 +116,7 @@ class Carousel extends Component { display: flex; align-items: center; justify-content: center; - opacity: 0.8; + opacity: 0; width: 33px; height: 33px; font-size: 24px; @@ -95,6 +125,10 @@ class Carousel extends Component { border-color: #fff; border-radius: 50%; --size: 12px; + transition: opacity ease-in-out 0.2s; + &:hover { + opacity: 1 !important; + } } .left, .right { @@ -102,10 +136,43 @@ class Carousel extends Component { transform: translateY(-50%); } .left { - left: 5%; + left: 3%; } .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 = [] @@ -114,7 +181,7 @@ class Carousel extends Component { updateItems() { this.items = Array.from(this.children).filter( - item => item.tagName === 'WC-CAROUSEL-ITEM' + item => item.tagName === 'WC-SWIPE-ITEM' ) nextTick(() => this.$requestUpdate()) } @@ -147,6 +214,7 @@ class Carousel extends Component { this.items.forEach((item, index) => { item.translateItem(index, this.activeIndex, oldIndex) }) + nextTick(() => this.$requestUpdate()) } setActiveItem(index) { const now = Date.now() @@ -176,12 +244,18 @@ class Carousel extends Component { if (oldIndex !== this.activeIndex) { this.resetItemPosition(oldIndex) } - // this.resetItemPosition(oldIndex) this.resetTimer() + nextTick(() => this.$requestUpdate()) } - handleIndicatorHover(index) { + handleIndicatorHover(event) { + let index = +event.target.getAttribute('index') 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) } } @@ -191,6 +265,18 @@ class Carousel extends Component { next() { this.setActiveItem(this.activeIndex + 1) } + showArrow() { + this.showArrowBtn = true + this.$requestUpdate() + } + hideArrow() { + this.showArrowBtn = false + this.$requestUpdate() + } + handleSlotChange() { + this.updateItems() + this.resetItemPosition() + } mounted() { this.updateItems() nextTick(() => { @@ -202,6 +288,17 @@ class Carousel extends Component { this.resizeObserve.observe(this) 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.showArrow() + } } unmounted() { this.resizeObserve.disconnect() @@ -209,23 +306,46 @@ class Carousel extends Component { this.pauseTimer() } render() { + let styles = styleMap({ + opacity: this.showArrowBtn ? 0.6 : 0 + }) + let toggleBtns = + this.direction === 'horizontal' + ? html` +
+ +
+
+ +
+ ` + : '' + + let indicator = this.indicator + ? html` + + ` + : '' + return html`
- -
- -
-
- -
+ + ${toggleBtns}
- + ${indicator} ` } } -class CarouselItem extends Component { +class SwipeItem extends Component { static props = { name: { String, attributes: false } } @@ -248,7 +368,8 @@ class CarouselItem extends Component { :host([card]) { width: 50%; transition-duration: 400ms; - transition-property: transform, opacity; + transition-property: transform, opacity, filter; + cursor: pointer; } ` static watch = { @@ -269,16 +390,22 @@ class CarouselItem extends Component { if (this.$parent.type !== 'card') { return } - this.style.opacity = 1 + let style = { + opacity: 1, + 'z-index': 1, + filter: 'brightness(0.8)' + } if (this.inStage) { - this.style['z-index'] = 1 + style['z-index'] = 1 } else { - this.style['z-index'] = -1 - this.style.opacity = 0 + style['z-index'] = -1 + style.opacity = 0 } if (val) { - this.style['z-index'] = 2 + style['z-index'] = 2 + style.filter = 'brightness(1)' } + Object.assign(this.style, style) } } processIndex(index, activeIndex, length) { @@ -347,9 +474,11 @@ class CarouselItem extends Component { this.$parent = this.parentNode if (this.$parent.type === 'card') { this.setAttribute('card', '') + const index = this.$parent.items.indexOf(this) + this.$on('click', () => this.$parent.setActiveItem(index)) } } } -Carousel.reg('carousel') -CarouselItem.reg('carousel-item') +Swipe.reg('swipe') +SwipeItem.reg('swipe-item')