UNPKG

veui

Version:

Baidu Enterprise UI for Vue.js.

230 lines (196 loc) 6.06 kB
import { find, pick, assign, isEqual } from 'lodash' import BaseHandler from './BaseHandler' import { getNodes } from '../../utils/context' import { appendTemporaryStyle, draggingStyle } from '../../utils/dom' let style = process.env.VUE_ENV === 'server' ? function () {} : document.documentElement.style const TRANSFORM_ACCESSOR = find( ['transform', 'msTransform', 'MozTransform', 'webkitTransform'], (accessor) => accessor in style ) function getComputedTransform (elm) { return getComputedStyle(elm)[TRANSFORM_ACCESSOR] } function combineTransform (oldTransform, [x, y]) { let transforms = [] if (oldTransform && oldTransform !== 'none') { transforms.push(oldTransform) } if (x !== 0 || y !== 0) { transforms.push(`translate(${x}px,${y}px)`) } return transforms.join(' ') } export default class TranslateHandler extends BaseHandler { elms = [] restoreStyles = [] initialTransforms = [] initialPositions = [] totalDistanceX = 0 totalDistanceY = 0 // 是否被拖动过。 // 只有被拖动过,才记录总的拖动距离 isDragged = false setOptions (options) { if (isEqual(this.options, options)) { return } super.setOptions(options) this.options = assign( this.options, pick(options, ['targets', 'containment', 'axis']) ) this.elms = [] } start () { super.start() if (!this.elms || !this.elms.length) { this.elms = this.options.targets.reduce((prev, cur) => { prev.push(...getNodes(cur, this.context)) return prev }, []) } if (!this.originalStyles || !this.originalStyles.length) { this.originalStyles = this.elms.reduce((prev, cur) => { prev.push(cur.getAttribute('style')) return prev }, []) } this.elms.forEach((elm, index) => { let initialTransform = getComputedTransform(elm) this.initialTransforms[index] = initialTransform === 'none' ? '' : initialTransform this.restoreStyles[index] = appendTemporaryStyle(elm, draggingStyle) let rect = elm.getBoundingClientRect() this.initialPositions[index] = rect }) } drag ({ distanceX, distanceY }) { this.move( distanceX, distanceY, (elm, index, realDistanceX, realDistanceY) => { let initialTransform = this.initialTransforms[index] || '' elm.style[TRANSFORM_ACCESSOR] = combineTransform(initialTransform, [ realDistanceX, realDistanceY ]) } ) this.isDragged = true } end ({ distanceX, distanceY }) { super.end() this.move( distanceX, distanceY, (elm, index, realDistanceX, realDistanceY) => { this.restoreStyles[index]() let initialTransform = this.initialTransforms[index] || '' elm.style[TRANSFORM_ACCESSOR] = combineTransform(initialTransform, [ realDistanceX, realDistanceY ]) if (this.isDragged) { this.totalDistanceX += realDistanceX this.totalDistanceY += realDistanceY } } ) this.initialTransforms = [] this.initialStyles = [] this.isDragged = false } move (distanceX, distanceY, render) { // 统一转换成 { left: ..., top: ..., width: ..., height: ... } 形式的 rect let options = this.options let constraint = null if (options.containment && options.containment.nodeType) { constraint = pick(options.containment.getBoundingClientRect(), [ 'top', 'left', 'right', 'bottom' ]) constraint.width = constraint.right - constraint.left constraint.height = constraint.bottom - constraint.top } else if (options.containment === '@window') { constraint = { top: 0, left: 0, width: window.innerWidth, height: window.innerHeight } } else { constraint = options.containment } this.elms.forEach((elm, index) => { let initialPosition = this.initialPositions[index] let realDistanceX = distanceX let realDistanceY = distanceY let offsetWidth = elm.offsetWidth let offsetHeight = elm.offsetHeight if (constraint) { if (!options.axis || options.axis === 'y') { // 从上面超出范围了 if (initialPosition.top + realDistanceY <= constraint.top) { realDistanceY = constraint.top - initialPosition.top } // 从下面超出范围了 if ( initialPosition.top + offsetHeight + realDistanceY > constraint.top + constraint.height ) { realDistanceY = constraint.top + constraint.height - (initialPosition.top + offsetHeight) } } else { realDistanceY = 0 } if (!options.axis || options.axis === 'x') { // 从左边超出范围了 if (initialPosition.left + realDistanceX < constraint.left) { realDistanceX = constraint.left - initialPosition.left } // 从右边超出范围了 if ( initialPosition.left + offsetWidth + realDistanceX > constraint.left + constraint.width ) { realDistanceX = constraint.left + constraint.width - (initialPosition.left + offsetWidth) } } else { realDistanceX = 0 } } else { if (options.axis === 'y') { realDistanceX = 0 } else if (options.axis === 'x') { realDistanceY = 0 } } render(elm, index, realDistanceX, realDistanceY) }) } reset () { // 恢复最初的样式 this.elms.forEach((elm, i) => { let style = this.originalStyles[i] if (style != null) { elm.setAttribute('style', style) } else { elm.removeAttribute('style') } }) this.totalDistanceX = 0 this.totalDistanceY = 0 } destroy () {} }