方位
根据当前鼠标所处的位置不同,箭头所指向的方向也不同:
左上方(left-top)(缺省)、左下方(left-bottom)、右上方(right-top)、右下方(right-bottom)、上左方(top-left)、上右方(top-right)、下左方(bottom-left)、下右方(bottom-right)
优先级
以上各种情况优先级依次降低
探测思路
探测基本思路是:
首先,也是前提条件,判断容器的高或宽是否是弹窗对应的高或宽的两倍,之所以是两倍,因为临界点是目标容器的各个边的中点
/*
* 先判断目标容器的高度或者宽度是否是容器对应高度或宽度与箭头尺寸之和的两倍,否则,报错。之所以是2倍,因为临界点是目标容器的各个边的中点。
*/
接下来,可以依据优先级去逐个判断:
/*
* 思路是,先检测左侧,再检测右侧,左右都放不下,则检测顶部,都排除,再考虑底部。检测左右侧时,先考虑顶部能否放下;检测上下时,先考虑据左右侧那边的距离大。
* 1.检测左侧时,判断上下距离能否放下箭头偏移量,有一个不能放下(例如top),则为['top', 'left'],右侧一样
* 2.检测上下时,判断左右距离能否放下箭头偏移量(缺省为上,即top),有一侧不能放下,即为鼠标偏向的一侧(若left * 缺省是左侧,顶部。 具体情况判断: •根据优先级,先判断鼠标右侧能否放下弹窗: ◦能放下,则去判断能否再放进个箭头 ■若能放下 ■则判断顶部是否能放下个箭头,包括箭头的偏移量,若能 ■判断顶部能放下箭头包括偏移量并且不会超过目标容器高度,则为left-top ■否则如果顶部大于弹窗高度,并底部可放下箭头包括其偏移量,则为left-bottom ■否则,判断底部能放下箭头和弹窗,则为top-left ■否则,基于我们的前提条件,是bottom-left ■若不能放下,判断底部能不能放下弹窗和箭头 ■能,则为top-left ■否则,为bottom-left ◦不能放下,则left考虑完,换right,同样的思路 八种情况弹窗的情况和位置 举例top-left 同样以top-left为例 写的代码,在重构了N遍,写完N行注释后,忽然想到,其实不论是写代码,还是生活,我们都是有个既定的或者约定俗成的前提或者说规范的。而一旦这个规范被打破,往往前功尽弃,即使不是,往往也很受伤。实例小至代码、大至社会,无一例外
*/
代码如下:
case 'top-left' :
// top 加上 箭头尺寸
this.conObj.css('top', top + tarTop);
// 判断left距离
if ( left < arrOffset ) {
// 紧贴左边
this.conObj.css('left', tarLeft);
} else if (right < (conWidth - arrOffset)) { // 如果right,撑不下自身在右边的距离(conWidth - arrOffset),则left值减小,箭头跟随鼠标,使自己右边与容器对齐
// 正常显示的left, 减去右侧还需要的宽度((conWidth - arrOffset) - right ), left - arrOffset - ((conWidth - arrOffset) - right ),得出tarWidth - conWidth
// 换种思路,紧贴右边,即左边距离为,目标容器宽度减去自身宽度
this.conObj.css('left', tarWidth - conWidth + tarLeft);
} else { // 正常显示的left
this.conObj.css('left', left - arrOffset + tarLeft);
}
break;
八种情况下箭头的情况和位置
代码如下:
case 'top-left' :
this.arrowObj.prependTo(this.conObj);
// 如果con紧贴右边,此时,箭头随鼠标移动
if (conLeft === 0 && (conWidth > (right + arrOffset))) {
this.arrowObj.css('left', conWidth - right - arrowPos);
} else {
this.arrowObj.css('left', arrowPos);
}
break;
最后说下在写代码时候的些许感悟: