ten-design-vue
Version:
ten-vue
566 lines (487 loc) • 18.3 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _vue = _interopRequireDefault(require("vue"));
var _debounce = _interopRequireDefault(require("lodash/debounce"));
var _domHelper = _interopRequireDefault(require("../scripts/utils/dom-helper"));
var _getElSlots = _interopRequireDefault(require("../scripts/mixins/get-el-slots"));
var _emitter = _interopRequireDefault(require("../scripts/mixins/emitter"));
var _resizeObserver = require("../scripts/utils/resize-observer");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); }
function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter); }
function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); }
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
var name = 'ten-popup';
function getDirMatch(direction) {
/* eslint-disable */
var dirMatch = direction.match(/((top|bottom|center|left|right)[\s-]*)/gi);
dirMatch = !dirMatch ? ['top', 'center'] : dirMatch.map(function (dir) {
return dir.replace(/[\s-]/g, '');
});
/* eslint-enable */
if (dirMatch.length === 1) {
dirMatch[1] = 'center';
}
if (dirMatch[0] === 'left' && dirMatch[1] === 'right' || dirMatch[0] === 'right' && dirMatch[1] === 'left' || dirMatch[0] === 'top' && dirMatch[1] === 'bottom' || dirMatch[0] === 'bottom' && dirMatch[1] === 'top') {
dirMatch[1] = 'center';
}
if (dirMatch[0] === 'center') {
if (dirMatch[1] === 'center') {
dirMatch = ['top', 'center'];
}
dirMatch.reverse();
} else if (dirMatch[0] === dirMatch[1]) {
dirMatch[1] = 'center';
}
dirMatch[0] = dirMatch[0].trim();
dirMatch[1] = dirMatch[1].trim();
return dirMatch;
}
var _default = {
name: name,
mixins: [_getElSlots.default, _emitter.default],
model: {
prop: 'show',
event: 'change'
},
props: {
/**
* 弹窗方向
*/
direction: {
type: String,
default: 'top center'
},
/**
* 是否显示
*/
show: Boolean,
/**
* 隐藏时是否销毁
*/
destroy: {
type: Boolean,
default: true
},
disabled: Boolean,
/**
* 获取弹窗内容宽度
*/
width: [Number, Function],
/**
* 设置弹窗偏移量,{ x, y }
*/
offset: Object,
/**
* 触发方式
*/
triggerType: {
validator: function validator(val) {
return ['click', 'hover', 'manual'].indexOf(val) > -1;
},
default: 'click'
},
/**
* 弹框 class
*/
popupClass: [String, Object, Array],
/**
* 类型
* @member default | bubble
*/
type: {
type: String,
default: 'default'
}
},
data: function data() {
return {
popupShowed: false
};
},
watch: {
show: {
immediate: true,
handler: function handler(val) {
this.popupShowed = val;
}
},
disabled: function disabled(v) {
if (v && this.popupShowed && this.triggerType !== 'manual') {
this.popupShowed = false;
}
}
},
render: function render(h) {
// eslint-disable-line
var triggerSlots = this.$scopedSlots.trigger ? this.$scopedSlots.trigger() : null;
var defaultSlot = this.$scopedSlots.default ? this.$scopedSlots.default() : null;
var trigger = null;
if (triggerSlots) {
for (var i = 0; i < triggerSlots.length; i++) {
if (triggerSlots[i].tag) {
trigger = triggerSlots[i];
break;
}
}
}
this.popupComponent.content = this.popupShowed || !this.destroy ? defaultSlot : null;
this.popupComponent.destroy = this.destroy;
this.popupComponent.show = this.popupShowed && trigger;
this.popupComponent.popupClass = this.popupClass;
this.popupComponent.type = this.type;
var dirMatch = getDirMatch(this.direction);
this.popupComponent.dir = dirMatch;
return trigger;
},
beforeCreate: function beforeCreate() {
var _this = this;
var h = this.$createElement;
var resize = function resize() {
_this.resize();
};
var visibleT = 0;
this.globalEventBinded = false;
this.popupElemEventBinded = false;
this.popupComponent = new _vue.default({
parent: this,
data: function data() {
return {
type: 'default',
content: null,
dataContent: null,
popupClass: '',
dir: [],
show: false,
destroy: false
};
},
watch: {
content: {
handler: function handler(v) {
var _this2 = this;
clearTimeout(visibleT);
if (v) {
this.dataContent = v;
} else {
visibleT = setTimeout(function () {
_this2.dataContent = null;
}, 300);
}
},
immediate: true
}
},
methods: {
onAfterLeave: function onAfterLeave() {
if (this.destroy) {
try {
document.body.removeChild(this.$el);
} catch (e) {}
}
}
},
updated: function updated() {
if (this.$refs.popup) {
(0, _resizeObserver.removeResizeListener)(this.$refs.popup, resize);
(0, _resizeObserver.addResizeListener)(this.$refs.popup, resize);
this.$refs.popup.tenPopupParentNode = this.$parent.$el;
}
},
beforeDestroy: function beforeDestroy() {
if (this.$refs.popup) {
(0, _resizeObserver.removeResizeListener)(this.$refs.popup, resize);
this.$refs.popup.tenPopupParentNode = null;
}
},
render: function render(h) {
var _this3 = this;
// eslint-disable-line
var popupClass = ['ten-popup', "ten-popup--p-".concat(this.dir[0], "-").concat(this.dir[1]), "ten-popup--type-".concat(this.type), this.popupClass];
return this.dataContent ? // appear确保初次渲染的时候依然有过渡动画
h("transition", {
attrs: {
name: "ten-flow-in__popup",
appear: true
},
on: {
"afterLeave": function afterLeave() {
_this3.onAfterLeave();
}
}
}, [h("div", {
"class": popupClass,
directives: [{
name: "show",
value: this.show && this.content
}],
ref: "popup"
}, [this.dataContent])]) : null;
}
});
this.popupComponent.$mount();
},
mounted: function mounted() {
this.bindTriggerElemEvent();
this.afterRender();
this.setPopupPosition = (0, _debounce.default)(this.setPopupPosition.bind(this), 16);
},
updated: function updated() {
this.bindTriggerElemEvent();
this.afterRender();
},
beforeDestroy: function beforeDestroy() {
this.unbindGlobalEvent();
this.removePopupElem();
this.popupComponent.$destroy();
},
methods: {
afterRender: function afterRender() {
if (this.popupShowed) {
this.appendPopupElem();
this.bindPopupElemEvent();
if (this.triggerType === 'click' || this.triggerType === 'manual') {
this.bindGlobalEvent();
}
this.dirMatch = getDirMatch(this.direction);
this.$nextTick(function () {
this.setPopupPosition();
});
} else {
this.unbindGlobalEvent();
this.unbindPopupElemEvent();
}
},
appendPopupElem: function appendPopupElem() {
try {
if (this.popupComponent.$el.parentNode === document.body) {
return;
}
document.body.appendChild(this.popupComponent.$el);
this.broadcastAll('do-layout');
} catch (e) {}
},
removePopupElem: function removePopupElem() {
try {
document.body.removeChild(this.popupComponent.$el);
} catch (e) {}
},
bindTriggerElemEvent: function bindTriggerElemEvent() {
this.triggerElem = this.$el;
if (this.triggerElem) {
if (this.triggerType === 'click') {
this.triggerElem.addEventListener('click', this.onClick);
}
if (this.triggerType === 'hover') {
this.triggerElem.addEventListener('mouseenter', this.onMouseenter);
this.triggerElem.addEventListener('mouseleave', this.onMouseleave);
}
}
},
bindPopupElemEvent: function bindPopupElemEvent() {
if (this.popupComponent.$el && !this.popupElemEventBinded) {
this.popupElemEventBinded = true;
if (this.triggerType === 'hover') {
this.popupComponent.$el.addEventListener('mouseenter', this.onMouseenter);
this.popupComponent.$el.addEventListener('mouseleave', this.onMouseleave);
}
}
},
unbindPopupElemEvent: function unbindPopupElemEvent() {
if (this.popupComponent.$el) {
this.popupElemEventBinded = false;
if (this.triggerType === 'hover') {
this.popupComponent.$el.removeEventListener('mouseenter', this.onMouseenter);
this.popupComponent.$el.removeEventListener('mouseleave', this.onMouseleave);
}
}
},
bindGlobalEvent: function bindGlobalEvent() {
if (!this.globalEventBinded) {
this.globalEventBinded = true;
window.addEventListener('resize', this.setPopupPosition);
window.addEventListener('scroll', this.setPopupPosition);
document.addEventListener('scroll', this.setPopupPosition, true);
document.addEventListener('click', this.onClickOutside);
document.addEventListener('keydown', this.onKeydown);
}
},
unbindGlobalEvent: function unbindGlobalEvent() {
this.globalEventBinded = false;
window.removeEventListener('resize', this.setPopupPosition);
window.removeEventListener('scroll', this.setPopupPosition);
document.removeEventListener('scroll', this.setPopupPosition, true);
document.removeEventListener('click', this.onClickOutside);
document.removeEventListener('keydown', this.onKeydown);
},
setPopupPosition: function setPopupPosition() {
this.popupElem = this.popupComponent.$el;
var show = this.popupShowed;
var padding = 0;
var dirMatch = _toConsumableArray(this.dirMatch); // const padding = 16;
var triggerElem = this.triggerElem;
var isTriggerFixed = getComputedStyle(triggerElem).position === 'fixed'; // console.log('setPopupPosition', triggerElem, this.popupElem);
if (!show || !triggerElem || !this.popupElem || triggerElem.nodeType !== 1 || this.popupElem.nodeType !== 1) {
return;
}
var winHeight = window.innerHeight;
var winWidth = window.innerWidth;
var triggerElemRect = triggerElem.getBoundingClientRect();
var popupElemRect = this.popupElem.getBoundingClientRect();
var popupStyle = {
position: isTriggerFixed ? 'fixed' : 'absolute'
};
var popupElemRectWidth = popupElemRect.width;
if (typeof this.width !== 'undefined') {
var width = this.width;
var w;
if (typeof width === 'function') {
w = width(triggerElem);
} else {
w = width;
}
popupElemRectWidth = w + padding * 2;
popupStyle.width = w + padding * 2;
} // If there is not enough space in the specified direction, set it to the opposite direction
if (dirMatch[0] === 'top' && popupElemRect.height > triggerElemRect.top && popupElemRect.height < winHeight - triggerElemRect.top - triggerElemRect.height) {
dirMatch[0] = 'bottom';
}
if (dirMatch[0] === 'bottom' && popupElemRect.height > winHeight - triggerElemRect.top - triggerElemRect.height && popupElemRect.height < triggerElemRect.top) {
dirMatch[0] = 'top';
}
if (dirMatch[0] === 'left' && popupElemRectWidth > triggerElemRect.left && popupElemRectWidth < winWidth - triggerElemRect.left - triggerElemRect.width) {
dirMatch[0] = 'right';
}
if (dirMatch[0] === 'right' && popupElemRectWidth > winWidth - triggerElemRect.left - triggerElemRect.width && popupElemRectWidth < triggerElemRect.left) {
dirMatch[0] = 'left';
}
if (dirMatch[1] === 'top' && popupElemRect.height > winHeight - triggerElemRect.top) {
dirMatch[1] = 'bottom';
} else if (dirMatch[1] === 'bottom' && popupElemRect.height > triggerElemRect.top + triggerElemRect.height) {
dirMatch[1] = 'top';
}
if (dirMatch[1] === 'left' && popupElemRectWidth > winWidth - triggerElemRect.left) {
dirMatch[1] = 'right';
} else if (dirMatch[1] === 'right' && popupElemRectWidth > triggerElemRect.left + triggerElemRect.width) {
dirMatch[1] = 'left';
}
if (dirMatch[0] === 'bottom' || dirMatch[0] === 'top') {
if (dirMatch[1] === 'center' && popupElemRectWidth) {
var leftSpaceRemain = triggerElemRect.left + triggerElemRect.width / 2;
var rightSpaceRemain = winWidth - leftSpaceRemain;
if (popupElemRectWidth / 2 > leftSpaceRemain && popupElemRectWidth / 2 < rightSpaceRemain) {
dirMatch[1] = 'left';
} else if (popupElemRectWidth / 2 > rightSpaceRemain && popupElemRectWidth / 2 < leftSpaceRemain) {
dirMatch[1] = 'right';
}
}
} // style
if (dirMatch[0] === 'top') {
popupStyle.top = triggerElemRect.top - popupElemRect.height;
} else if (dirMatch[0] === 'bottom') {
popupStyle.top = triggerElemRect.top + triggerElemRect.height;
} else if (dirMatch[0] === 'left') {
popupStyle.left = triggerElemRect.left - popupElemRectWidth;
} else if (dirMatch[0] === 'right') {
popupStyle.left = triggerElemRect.left + triggerElemRect.width;
}
if (dirMatch[1] === 'top') {
popupStyle.top = triggerElemRect.top - padding;
} else if (dirMatch[1] === 'bottom') {
popupStyle.top = triggerElemRect.top + triggerElemRect.height - popupElemRect.height + padding;
} else if (dirMatch[1] === 'left') {
popupStyle.left = triggerElemRect.left - padding;
} else if (dirMatch[1] === 'right') {
popupStyle.left = triggerElemRect.left + triggerElemRect.width - popupElemRectWidth + padding;
} else {
/* eslint-disable */
// center
if (dirMatch[0] === 'top' || dirMatch[0] === 'bottom') {
popupStyle.left = triggerElemRect.left - (popupElemRectWidth - triggerElemRect.width) / 2;
} else {
popupStyle.top = triggerElemRect.top - (popupElemRect.height - triggerElemRect.height) / 2;
}
/* eslint-enable */
}
if (dirMatch[0] === 'top') {
popupStyle.top = triggerElemRect.top - popupElemRect.height;
} else if (dirMatch[0] === 'bottom') {
popupStyle.top = triggerElemRect.top + triggerElemRect.height;
} else if (dirMatch[0] === 'center') {
popupStyle.top = triggerElemRect.top - (popupElemRect.height - triggerElemRect.height) / 2;
}
if (!isTriggerFixed) {
popupStyle.top += window.scrollY || window.pageYOffset;
popupStyle.left += window.scrollX || window.pageXOffset;
}
if (this.offset) {
popupStyle.top += this.offset.y || 0;
popupStyle.left += this.offset.x || 0;
}
_domHelper.default.css(this.popupElem, popupStyle); // class for style arrow
this.popupElem.className = this.popupElem.className.replace(/ten-popup--p-[\w-]+/g, '').replace(/\s+/g, ' ');
this.popupElem.classList.add("ten-popup--p-".concat(dirMatch[0], "-").concat(dirMatch[1]));
},
resize: function resize() {
this.setPopupPosition();
},
onClick: function onClick() {
this.togglePopup();
},
onMouseenter: function onMouseenter() {
clearTimeout(this.mouseleaveT);
this.showPopup();
},
onMouseleave: function onMouseleave() {
var _this4 = this;
this.mouseleaveT = setTimeout(function () {
_this4.hidePopup();
}, 150);
},
onClickOutside: function onClickOutside(e) {
if (!this.popupShowed || _domHelper.default.contains(this.popupElem, e.target) || _domHelper.default.contains(this.triggerElem, e.target)) {
return;
}
this.hidePopup();
},
onKeydown: function onKeydown(e) {
if (e.keyCode === 27) {
this.hidePopup();
}
},
togglePopup: function togglePopup() {
this.popupShowed ? this.hidePopup() : this.showPopup();
},
showPopup: function showPopup() {
if (this.disabled) {
return;
}
if (this.triggerType !== 'manual') {
this.popupShowed = true;
}
/**
* 弹窗显示变换回调
*/
this.$emit('change', true);
},
hidePopup: function hidePopup() {
if (this.disabled) {
return;
}
if (this.triggerType !== 'manual') {
this.popupShowed = false;
}
/**
* 弹窗显示变换回调
* @param {Boolean} visible
*/
this.$emit('change', false);
}
}
};
exports.default = _default;