Merge branch 'master' of github.com:9th-js/wcui
						commit
						0bb9e7e9d3
					
				|  | @ -23,10 +23,12 @@ | ||||||
| - [ ] `wc-collapse`折叠组件 | - [ ] `wc-collapse`折叠组件 | ||||||
| - [ ] `wc-counter`倒计时组件 | - [ ] `wc-counter`倒计时组件 | ||||||
| - [ ] `wc-drag`拖拽组件 | - [ ] `wc-drag`拖拽组件 | ||||||
|  | - [x] `wc-image`图片组件 | ||||||
|  | - [x] `wc-image-preview`图片预览组件 | ||||||
| - [x] `wc-button`表单组件-按钮 | - [x] `wc-button`表单组件-按钮 | ||||||
| - [x] `wc-link`表单组件-链接按钮 | - [x] `wc-link`表单组件-链接按钮 | ||||||
| - [x] `wc-checkbox`表单组件-复选框 | - [x] `wc-checkbox`表单组件-复选框 | ||||||
| - [ ] `wc-input`表单组件-文本输入框 | - [x] `wc-input`表单组件-文本输入框 | ||||||
| - [x] `wc-passwd`表单组件-文本输入框 | - [x] `wc-passwd`表单组件-文本输入框 | ||||||
| - [x] `wc-textarea`表单组件-多行文本输入框 | - [x] `wc-textarea`表单组件-多行文本输入框 | ||||||
| - [x] `wc-number`表单组件-步进数字输入 | - [x] `wc-number`表单组件-步进数字输入 | ||||||
|  |  | ||||||
|  | @ -0,0 +1,355 @@ | ||||||
|  | /** | ||||||
|  |  * {} | ||||||
|  |  * @author chensbox<chensbox@foxmail.com> | ||||||
|  |  * @date 2023/03/26 16:14:10 | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | import { css, html, Component, nextTick } from '@bd/core' | ||||||
|  | import '../icon/index.js' | ||||||
|  | const CARD_SCALE = 0.83 | ||||||
|  | function createWatcher(object, key, effect) { | ||||||
|  |   let value | ||||||
|  |   Object.defineProperty(object, key, { | ||||||
|  |     get() { | ||||||
|  |       return value | ||||||
|  |     }, | ||||||
|  |     set(val) { | ||||||
|  |       value = val | ||||||
|  |       effect.call(object, val) | ||||||
|  |     } | ||||||
|  |   }) | ||||||
|  | } | ||||||
|  | class Carousel extends Component { | ||||||
|  |   static props = { | ||||||
|  |     'initial-index': { | ||||||
|  |       type: Number, | ||||||
|  |       default: 0 | ||||||
|  |     }, | ||||||
|  |     height: { | ||||||
|  |       type: String, | ||||||
|  |       default: 200, | ||||||
|  |       observer(val) { | ||||||
|  |         this.style.height = `${val}px` | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     trigger: { | ||||||
|  |       type: String, | ||||||
|  |       default: 'hover' | ||||||
|  |     }, | ||||||
|  |     autoplay: { | ||||||
|  |       type: Boolean, | ||||||
|  |       default: true, | ||||||
|  |       observer(val) { | ||||||
|  |         val ? this.startTimer() : this.pauseTimer() | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     interval: { | ||||||
|  |       type: Number, | ||||||
|  |       default: 3000 | ||||||
|  |     }, | ||||||
|  |     'indicator-position': { String, attributes: false }, | ||||||
|  |     indicator: { | ||||||
|  |       type: Boolean, | ||||||
|  |       default: true | ||||||
|  |     }, | ||||||
|  |     arrow: { | ||||||
|  |       type: String, | ||||||
|  |       default: 'hover' | ||||||
|  |     }, | ||||||
|  |     type: { type: String, default: '', attributes: false }, | ||||||
|  |     loop: { | ||||||
|  |       type: Boolean, | ||||||
|  |       default: true | ||||||
|  |     }, | ||||||
|  |     direction: { | ||||||
|  |       type: String, | ||||||
|  |       default: 'horizontal' | ||||||
|  |     }, | ||||||
|  |     'pause-on-hover': { | ||||||
|  |       type: Boolean, | ||||||
|  |       default: true | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   static styles = css` | ||||||
|  |     :host { | ||||||
|  |       overflow: hidden; | ||||||
|  |       position: relative; | ||||||
|  |       display: block; | ||||||
|  |       width: 100%; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     .toggle-btn { | ||||||
|  |       z-index: 4; | ||||||
|  |       user-select: none; | ||||||
|  |       cursor: pointer; | ||||||
|  |       position: absolute; | ||||||
|  |       display: flex; | ||||||
|  |       align-items: center; | ||||||
|  |       justify-content: center; | ||||||
|  |       opacity: 0.8; | ||||||
|  |       width: 33px; | ||||||
|  |       height: 33px; | ||||||
|  |       font-size: 24px; | ||||||
|  |       color: #fff; | ||||||
|  |       background-color: #606266; | ||||||
|  |       border-color: #fff; | ||||||
|  |       border-radius: 50%; | ||||||
|  |       --size: 12px; | ||||||
|  |     } | ||||||
|  |     .left, | ||||||
|  |     .right { | ||||||
|  |       top: 50%; | ||||||
|  |       transform: translateY(-50%); | ||||||
|  |     } | ||||||
|  |     .left { | ||||||
|  |       left: 5%; | ||||||
|  |     } | ||||||
|  |     .right { | ||||||
|  |       right: 5%; | ||||||
|  |     } | ||||||
|  |   ` | ||||||
|  |   items = [] | ||||||
|  |   activeIndex = 0 | ||||||
|  |   stamp = 0 | ||||||
|  | 
 | ||||||
|  |   updateItems() { | ||||||
|  |     this.items = Array.from(this.children).filter( | ||||||
|  |       item => item.tagName === 'WC-CAROUSEL-ITEM' | ||||||
|  |     ) | ||||||
|  |     nextTick(() => this.$requestUpdate()) | ||||||
|  |   } | ||||||
|  |   playSlides() { | ||||||
|  |     let oldIndex = this.activeIndex | ||||||
|  |     if (this.activeIndex < this.items.length - 1) { | ||||||
|  |       this.activeIndex++ | ||||||
|  |     } else if (this.loop) { | ||||||
|  |       this.activeIndex = 0 | ||||||
|  |     } | ||||||
|  |     this.resetItemPosition(oldIndex) | ||||||
|  |   } | ||||||
|  |   startTimer() { | ||||||
|  |     if (!this.interval || this.interval <= 0 || !this.autoplay || this.timer) { | ||||||
|  |       return | ||||||
|  |     } | ||||||
|  |     this.timer = setInterval(this.playSlides.bind(this), this.interval) | ||||||
|  |   } | ||||||
|  |   pauseTimer() { | ||||||
|  |     if (this.timer) { | ||||||
|  |       clearInterval(this.timer) | ||||||
|  |       this.timer = null | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   resetTimer() { | ||||||
|  |     this.pauseTimer() | ||||||
|  |     this.startTimer() | ||||||
|  |   } | ||||||
|  |   resetItemPosition(oldIndex) { | ||||||
|  |     this.items.forEach((item, index) => { | ||||||
|  |       item.translateItem(index, this.activeIndex, oldIndex) | ||||||
|  |     }) | ||||||
|  |   } | ||||||
|  |   setActiveItem(index) { | ||||||
|  |     const now = Date.now() | ||||||
|  |     if (now - this.stamp < 300) { | ||||||
|  |       return | ||||||
|  |     } | ||||||
|  |     this.stamp = now | ||||||
|  |     if (typeof index === 'string') { | ||||||
|  |       const filteredItems = this.items.filter(item => item.name === index) | ||||||
|  |       if (filteredItems.length > 0) { | ||||||
|  |         index = this.items.indexOf(filteredItems[0]) | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |     index = Number(index) | ||||||
|  |     if (isNaN(index) || index !== Math.floor(index)) { | ||||||
|  |       return | ||||||
|  |     } | ||||||
|  |     const length = this.items.length | ||||||
|  |     const oldIndex = this.activeIndex | ||||||
|  |     if (index < 0) { | ||||||
|  |       this.activeIndex = this.loop ? length - 1 : 0 | ||||||
|  |     } else if (index >= length) { | ||||||
|  |       this.activeIndex = this.loop ? 0 : length - 1 | ||||||
|  |     } else { | ||||||
|  |       this.activeIndex = index | ||||||
|  |     } | ||||||
|  |     if (oldIndex !== this.activeIndex) { | ||||||
|  |       this.resetItemPosition(oldIndex) | ||||||
|  |     } | ||||||
|  |     // this.resetItemPosition(oldIndex)
 | ||||||
|  |     this.resetTimer() | ||||||
|  |   } | ||||||
|  |   handleIndicatorHover(index) { | ||||||
|  |     if (this.trigger === 'hover' && index !== this.activeIndex) { | ||||||
|  |       // this.activeIndex = index
 | ||||||
|  |       this.setActiveItem(index) | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   prev() { | ||||||
|  |     this.setActiveItem(this.activeIndex - 1) | ||||||
|  |   } | ||||||
|  |   next() { | ||||||
|  |     this.setActiveItem(this.activeIndex + 1) | ||||||
|  |   } | ||||||
|  |   mounted() { | ||||||
|  |     this.updateItems() | ||||||
|  |     nextTick(() => { | ||||||
|  |       let initialIndex = this['initial-index'] | ||||||
|  |       if (initialIndex >= 0 && initialIndex < this.items.length) { | ||||||
|  |         this.activeIndex = initialIndex | ||||||
|  |       } | ||||||
|  |       this.resizeObserve = new ResizeObserver(this.resetItemPosition.bind(this)) | ||||||
|  |       this.resizeObserve.observe(this) | ||||||
|  |       this.startTimer() | ||||||
|  |     }) | ||||||
|  |   } | ||||||
|  |   unmounted() { | ||||||
|  |     this.resizeObserve.disconnect() | ||||||
|  |     this.resizeObserve = null | ||||||
|  |     this.pauseTimer() | ||||||
|  |   } | ||||||
|  |   render() { | ||||||
|  |     return html` | ||||||
|  |       <div class="container" style=${`height:${this.height}px`}> | ||||||
|  |         <slot></slot> | ||||||
|  |         <div class="left toggle-btn" @click=${this.prev}> | ||||||
|  |           <wc-icon name="left"></wc-icon> | ||||||
|  |         </div> | ||||||
|  |         <div class="right toggle-btn" @click=${this.next}> | ||||||
|  |           <wc-icon name="right"></wc-icon> | ||||||
|  |         </div> | ||||||
|  |       </div> | ||||||
|  |       <ul> | ||||||
|  |         ${this.items.map(_ => html`<li>3</li>`)} | ||||||
|  |       </ul> | ||||||
|  |     ` | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | class CarouselItem extends Component { | ||||||
|  |   static props = { | ||||||
|  |     name: { String, attributes: false } | ||||||
|  |   } | ||||||
|  |   static styles = css` | ||||||
|  |     :host { | ||||||
|  |       position: absolute; | ||||||
|  |       left: 0; | ||||||
|  |       top: 0; | ||||||
|  |       display: none; | ||||||
|  |       width: 100%; | ||||||
|  |       height: 100%; | ||||||
|  |       transition: transform ease-in-out 0s; | ||||||
|  |     } | ||||||
|  |     :host([ready]) { | ||||||
|  |       display: block; | ||||||
|  |     } | ||||||
|  |     :host([animating]) { | ||||||
|  |       transition-duration: 400ms; | ||||||
|  |     } | ||||||
|  |     :host([card]) { | ||||||
|  |       width: 50%; | ||||||
|  |       transition-duration: 400ms; | ||||||
|  |       transition-property: transform, opacity; | ||||||
|  |     } | ||||||
|  |   ` | ||||||
|  |   static watch = { | ||||||
|  |     translate(val) { | ||||||
|  |       const translateType = | ||||||
|  |         this.$parent.direction === 'horizontal' ? 'translateX' : 'translateY' | ||||||
|  |       this.style.transform = `${translateType}(${val}px) scale(${this.scale})` | ||||||
|  |     }, | ||||||
|  |     ready(val) { | ||||||
|  |       val ? this.setAttribute('ready', '') : this.removeAttribute('ready') | ||||||
|  |     }, | ||||||
|  |     animating(val) { | ||||||
|  |       val | ||||||
|  |         ? this.setAttribute('animating', '') | ||||||
|  |         : this.removeAttribute('animating') | ||||||
|  |     }, | ||||||
|  |     active(val) { | ||||||
|  |       if (this.$parent.type !== 'card') { | ||||||
|  |         return | ||||||
|  |       } | ||||||
|  |       this.style.opacity = 1 | ||||||
|  |       if (this.inStage) { | ||||||
|  |         this.style['z-index'] = 1 | ||||||
|  |       } else { | ||||||
|  |         this.style['z-index'] = -1 | ||||||
|  |         this.style.opacity = 0 | ||||||
|  |       } | ||||||
|  |       if (val) { | ||||||
|  |         this.style['z-index'] = 2 | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   processIndex(index, activeIndex, length) { | ||||||
|  |     if (activeIndex === 0 && index === length - 1) { | ||||||
|  |       return -1 | ||||||
|  |     } else if (activeIndex === length - 1 && index === 0) { | ||||||
|  |       return length | ||||||
|  |     } else if (index < activeIndex - 1 && activeIndex - index >= length / 2) { | ||||||
|  |       return length + 1 | ||||||
|  |     } else if (index > activeIndex + 1 && index - activeIndex >= length / 2) { | ||||||
|  |       return -2 | ||||||
|  |     } | ||||||
|  |     return index | ||||||
|  |   } | ||||||
|  |   calcCardTranslate(index, activeIndex) { | ||||||
|  |     const parentWidth = this.$parent.offsetWidth | ||||||
|  |     if (this.inStage) { | ||||||
|  |       return (parentWidth * ((2 - CARD_SCALE) * (index - activeIndex) + 1)) / 4 | ||||||
|  |     } else if (index < activeIndex) { | ||||||
|  |       return (-(1 + CARD_SCALE) * parentWidth) / 4 | ||||||
|  |     } else { | ||||||
|  |       return ((3 + CARD_SCALE) * parentWidth) / 4 | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   calcTranslate(index, activeIndex, isVertical) { | ||||||
|  |     const distance = this.$parent[isVertical ? 'offsetHeight' : 'offsetWidth'] | ||||||
|  |     return distance * (index - activeIndex) | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   translateItem(index, activeIndex, oldIndex) { | ||||||
|  |     const parentType = this.$parent.type | ||||||
|  |     const parentDirection = this.$parent.direction | ||||||
|  |     const length = this.$parent.items.length | ||||||
|  |     if (parentType !== 'card' && oldIndex !== undefined) { | ||||||
|  |       this.animating = index === activeIndex || index === oldIndex | ||||||
|  |     } | ||||||
|  |     if (index !== activeIndex && length > 2 && this.$parent.loop) { | ||||||
|  |       index = this.processIndex(index, activeIndex, length) | ||||||
|  |     } | ||||||
|  |     if (parentType === 'card') { | ||||||
|  |       if (parentDirection === 'vertical') { | ||||||
|  |         console.warn( | ||||||
|  |           '[Warn][Carousel]vertical direction is not supported in card mode' | ||||||
|  |         ) | ||||||
|  |       } | ||||||
|  |       this.inStage = Math.round(Math.abs(index - activeIndex)) <= 1 | ||||||
|  |       this.active = index === activeIndex | ||||||
|  |       this.scale = this.active ? 1 : CARD_SCALE | ||||||
|  |       this.animating = true | ||||||
|  |       this.translate = this.calcCardTranslate(index, activeIndex) | ||||||
|  |     } else { | ||||||
|  |       this.active = index === activeIndex | ||||||
|  |       const isVertical = parentDirection === 'vertical' | ||||||
|  |       this.scale = 1 | ||||||
|  |       this.translate = this.calcTranslate(index, activeIndex, isVertical) | ||||||
|  |     } | ||||||
|  |     !this.ready && (this.ready = true) | ||||||
|  |   } | ||||||
|  |   created() { | ||||||
|  |     const { watch } = this.constructor | ||||||
|  |     for (const key in watch) { | ||||||
|  |       createWatcher(this, key, watch[key]) | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   mounted() { | ||||||
|  |     this.$parent = this.parentNode | ||||||
|  |     if (this.$parent.type === 'card') { | ||||||
|  |       this.setAttribute('card', '') | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | Carousel.reg('carousel') | ||||||
|  | CarouselItem.reg('carousel-item') | ||||||
		Loading…
	
		Reference in New Issue