drip-ui
Version:
Lightweight Mobile UI Components built on Vue
291 lines (249 loc) • 9.81 kB
JavaScript
import _extends from "@babel/runtime/helpers/esm/extends";
import create from '../utils/create-basic';
var HtmlFontSize = document.documentElement.style.fontSize || 37.5; // 获取当前HTML的字体大小
var getNumber = parseFloat(HtmlFontSize); // 获取浮点数
var cardinalNumber = 750 / (getNumber * 10); // 算出图纸和真机之间的系数
var defaultCoefficient = +parseFloat(20 / cardinalNumber).toFixed(2); // 左右边距
var dialogMargin = +parseFloat(26 / cardinalNumber).toFixed(2) * 1; // 上下边距
var documentW = document.documentElement.clientWidth; // 获取浏览器的宽
var documentH = document.documentElement.clientHeight; // 获取浏览器的高
export default create({
render: function render() {
var _vm = this;
var _h = _vm.$createElement;
var _c = _vm._self._c || _h;
return _c('div', {
staticClass: "risk-desc"
}, [_c('div', {
staticClass: "risk-desc-wrap"
}, [_c('span', {
ref: "iconMark",
staticClass: "risk-desc-iconSize",
on: {
"click": _vm.tooltipShow
}
}, [_vm._t("icon", [_c('img', {
attrs: {
"src": "//store.sdbao.com/product/detail/riskDescMark.png"
}
})])], 2), _c('div', {
directives: [{
name: "show",
rawName: "v-show",
value: _vm.visible,
expression: "visible"
}],
ref: "icon",
staticClass: "risk-desc-icon",
"class": !_vm.isAuto ? "risk-desc-icon-" + _vm.type : '',
style: _extends({}, _vm.iconStyle, {
borderColor: "transparent transparent " + _vm.backgroundColor
})
}), _c('div', {
directives: [{
name: "show",
rawName: "v-show",
value: _vm.visible,
expression: "visible"
}],
ref: "tooltip",
staticClass: "risk-desc-container",
"class": !_vm.isAuto ? "risk-desc-container-" + _vm.type : '',
style: _extends({}, _vm.dialogDescStyle, {
backgroundColor: _vm.backgroundColor
})
}, [_vm._t("container")], 2)])]);
},
name: 'tooltip',
props: {
visible: {
type: Boolean,
"default": false
},
type: {
type: String,
"default": 'auto'
},
backgroundColor: {
type: String,
"default": '#fff'
}
},
data: function data() {
return {
isdiff: false,
dialogDescStyle: {},
iconStyle: {},
tooltipLocation: {},
// 弹框数据
tooltipIcon: {}
};
},
computed: {
isAuto: function isAuto() {
var type = ['top', 'right', 'bottom', 'left'];
return !type.includes(this.type);
}
},
watch: {
// 当弹框隐藏的时候初始化方便下次计算
visible: function visible(_visible) {
if (!_visible) {
this.initDom();
}
}
},
mounted: function mounted() {
var _this = this;
this.listenerDescMark = this.throttle(function (e) {
// 如果是false 就不计算了
if (!_this.visible) return; // 判断当前点击
var isParentClassName = _this.getParentName(e.target, 'risk-desc');
if (!isParentClassName) {
_this.$emit('update:visible', false);
}
}, 100, {}, this);
this.tooltipShow = this.throttle(this.tooltipShow, 100, {}, this);
document.addEventListener('click', this.listenerDescMark);
},
methods: {
init: function init() {
if (!this.isAuto) return;
var dom = this.$refs.tooltip; // 获取弹框dom
var iconDom = this.$refs.icon; // 获取小三角的dom
this.tooltipLocation = dom.getBoundingClientRect();
this.tooltipIcon = iconDom.getBoundingClientRect(); // 获取小三角距离左上角个个参数
this.iconMarkWidth = this.$refs.iconMark.offsetWidth; // 获取问号的宽
this.iconMarkHeight = this.$refs.iconMark.offsetHeight; // 获取问号的高
this.bottomFlag = documentH - dialogMargin < this.tooltipLocation.top + this.tooltipLocation.height * 2; // 底部判断如果弹框超出当前底部视口
this.riskDescX = -defaultCoefficient; // 弹框初始化 translateX的距离
this.riskDescY = this.tooltipLocation.height + dialogMargin; // 弹框初始化 translateY的距离
this.iconX = this.iconMarkWidth / 2 - this.tooltipIcon.width / 2; // ?icon的宽度一半 减去 方框一半的宽度
this.iconY = dialogMargin; // 方框距离问号的距离
this.rotate = 'rotate(0deg)';
this.auto();
},
autoLeftRight: function autoLeftRight() {
if (this.tooltipLocation.right + defaultCoefficient > documentW) {
// 弹框右边超出
this.riskDescX = documentW - this.tooltipLocation.right - defaultCoefficient; // 浏览器宽度 减去 弹框右边距离浏览器左上角的距离 就是超出的距离 再减去 右边距离 就是弹框偏移量
} else if (this.tooltipLocation.left <= defaultCoefficient) {
this.riskDescX = -this.tooltipLocation.left + defaultCoefficient; // 左边超出的距离 加上左边距 就是弹框偏移量
}
},
auto: function auto() {
this.autoLeftRight();
if (this.bottomFlag) {
// 是否超出当前窗口底部
this.riskDescY = -this.iconMarkHeight - dialogMargin; // 问号高度 减去当前上边距 就是弹框偏移量
this.iconY = -this.iconMarkHeight - dialogMargin + this.tooltipIcon.height;
this.rotate = 'rotate(180deg)';
}
this.setPositon();
},
setPositon: function setPositon() {
this.dialogDescStyle = {
transform: "translate3D(" + this.riskDescX + "px, " + this.riskDescY + "px, 0)"
};
this.iconStyle = {
transform: "translate3D(" + this.iconX + "px, " + this.iconY + "px, 0) " + this.rotate
};
},
/**
* underscore 节流函数,返回函数连续调用时,func 执行频率限定为 次 / wait
*
* @param {function} func 回调函数
* @param {number} wait 表示时间窗口的间隔
* @param {object} options 如果想忽略开始函数的的调用,传入{leading: false}。
* 如果想忽略结尾函数的调用,传入{trailing: false}
* 两者不能共存,否则函数不能执行
* @return {function} 返回客户调用函数
*/
throttle: function throttle(func, wait, options, ctx) {
var context, args, result;
var timeout = null; // 之前的时间戳
var previous = 0; // 如果 options 没传则设为空对象
if (!options) options = {}; // 定时器回调函数
var later = function later() {
// 如果设置了 leading,就将 previous 设为 0
// 用于下面函数的第一个 if 判断
previous = options.leading === false ? 0 : +new Date(); // 置空一是为了防止内存泄漏,二是为了下面的定时器判断
timeout = null;
result = func.apply(context, args);
if (!timeout) context = args = null;
};
return function () {
// 获得当前时间戳
var now = +new Date(); // 首次进入前者肯定为 true
// 如果需要第一次不执行函数
// 就将上次时间戳设为当前的
// 这样在接下来计算 remaining 的值时会大于0
if (!previous && options.leading === false) previous = now; // 计算剩余时间
var remaining = wait - (now - previous);
context = ctx;
args = arguments; // 如果当前调用已经大于上次调用时间 + wait
// 或者用户手动调了时间
// 如果设置了 trailing,只会进入这个条件
// 如果没有设置 leading,那么第一次会进入这个条件
// 还有一点,你可能会觉得开启了定时器那么应该不会进入这个 if 条件了
// 其实还是会进入的,因为定时器的延时
// 并不是准确的时间,很可能你设置了2秒
// 但是他需要2.2秒才触发,这时候就会进入这个条件
if (remaining <= 0 || remaining > wait) {
// 如果存在定时器就清理掉否则会调用二次回调
if (timeout) {
clearTimeout(timeout);
timeout = null;
}
previous = now;
result = func.apply(context, args);
if (!timeout) context = args = null;
} else if (!timeout && options.trailing !== false) {
// 判断是否设置了定时器和 trailing
// 没有的话就开启一个定时器
// 并且不能不能同时设置 leading 和 trailing
timeout = setTimeout(later, remaining);
}
return result;
};
},
initDom: function initDom() {
this.dialogDescStyle = {
transform: ''
};
this.iconStyle = {
transform: ''
};
},
// 弹框显示
tooltipShow: function tooltipShow() {
var _this2 = this;
this.$emit('change');
this.$nextTick(function () {
if (!_this2.visible) return;
_this2.init();
});
},
/**
* 判断当前元素祖父元素是否有某个class
* @param {obj} 子元素
* @param {name} 祖父元素className
*/
getParentName: function getParentName(obj, name) {
var parentNodes = obj;
var flag = false;
while (parentNodes) {
if (parentNodes.className && parentNodes.className.split(' ').includes(name)) {
flag = true;
parentNodes = null;
} else {
parentNodes = parentNodes.parentNode;
}
}
return flag;
}
},
destroyed: function destroyed() {
document.removeEventListener('click', this.listenerDescMark);
}
});