UNPKG

wot-design

Version:

Mobile UI components built on vue.js

187 lines (167 loc) 4.26 kB
import { context } from './context' import { openModal, closeModal } from './modal' import TouchMixin from '../touch' import { getScrollEventTarget } from '../../utils/scroll' import { on, off } from '../../utils/event' export function stopPropagation (event) { event.stopPropagation() } export function preventDefault (event, isStopPropagation) { /* istanbul ignore else */ if (typeof event.cancelable !== 'boolean' || event.cancelable) { event.preventDefault() } if (isStopPropagation) { stopPropagation(event) } } export default { mixins: [TouchMixin], data () { return { inited: this.value } }, props: { value: Boolean, lockScroll: { type: Boolean, default: true }, closeOnClickModal: { type: Boolean, default: true }, closeOnPopstate: { type: Boolean, default: true }, zIndex: Number, duration: { type: Number, default: 300 }, modal: { type: Boolean, default: true }, modalStyle: { type: Object, default () { return {} } }, teleport: { type: [String, Object], default: 'body' } }, watch: { value (val) { const type = val ? 'open' : 'close' this.inited = this.inited || this.value this[type]() this.$emit(type) }, teleport: 'appendTeleport' }, methods: { open () { if (this.$isServer || this.opened) return if (this.zIndex !== undefined) { context.zIndex = this.zIndex } this.opened = true this.modal && this.renderModal() if (this.lockScroll) { on(document, 'touchstart', this.touchStart) on(document, 'touchmove', this.onTouchMove) if (!context.lockCount) { document.body.classList.add('wd-overflow-hidden') } context.lockCount++ } }, close () { if (!this.opened) return if (this.lockScroll) { off(document, 'touchstart', this.touchStart) off(document, 'touchmove', this.onTouchMove) context.lockCount-- if (!context.lockCount) { document.body.classList.remove('wd-overflow-hidden') } } this.opened = false this.modal && closeModal(this) this.$emit('input', false) }, renderModal () { this.$el.style.zIndex = ++context.zIndex + 1 openModal(this, { duration: this.duration, zIndex: context.zIndex++, closeOnClickModal: this.closeOnClickModal, modalStyle: this.modalStyle }) }, onTouchMove (event) { this.touchMove(event) const direction = this.deltaY > 0 ? '10' : '01' const el = getScrollEventTarget(event.target, this.$el) const { scrollHeight, offsetHeight, scrollTop } = el let status = '11' if (scrollTop === 0) { status = offsetHeight >= scrollHeight ? '00' : '01' } else if (scrollTop + offsetHeight >= scrollHeight) { status = '10' } if (status !== '11' && this.direction === 'vertical' && !(parseInt(status, 2) & parseInt(direction, 2))) { preventDefault(event) } }, appendTeleport () { if (this.$isServer) return let to = 'body' let disabled = false const teleportType = typeof this.teleport if (teleportType === 'object') { to = this.teleport.to disabled = this.teleport.disabled } else if (teleportType === 'string') { to = this.teleport } if (!disabled) { const container = document.querySelector(to) container.appendChild(this.$el) } }, handlePopstate () { this.$emit('popstate') this.close() } }, mounted () { if (this.teleport) { this.appendTeleport() } if (this.value) { this.open() } if (this.closeOnPopstate) { window.addEventListener('popstate', this.handlePopstate) } }, beforeDestroy () { if (this.teleport) { const parentNode = this.$el.parentNode parentNode.removeChild(this.$el) } this.close() if (this.closeOnPopstate) { window.removeEventListener('popstate', this.handlePopstate) } } }