Position 浮层定位
简介
特点
该定位插件具备如下特性:
- 功能单一,代码量少。
- 支持已显示的DOM节点定位和不可见DOM节点定位(visibility:hidden)
- 不支持内存中节点和display:none隐藏元素定位
- 支持三种监听方式:scroll(页面滚动)、resize(窗口尺寸变化)和mutation(body节点变化)
- 支持13种位置定位
- 支持自适应边界并自动修改位置
- 支持修改button按钮,即可转移浮层
- 支持手动重置定位
使用方法
完整写法:axPopupPosition(btnDom, boxDom, options),可简写为:axPopupPosition(btnDom, boxDom),参数说明如下:
btnDom
:必填项,定位按钮,可以填"#id"、".className"、"div"等原生选择器以及Dom对象。boxDom
:必填项,定位浮层,可以填"#id"、".className"、"div"等原生选择器以及Dom对象。node
:必填项,父节点名称,比如div,span,a等。options
:选填项,插件参数,详细如下:- placement:位置,字符串格式,默认top,可填:left、left-start、left-end,right、right-start、right-end,top、top-start、top-end,bottom、bottom-start、bottom-end和center,其中center将使用fixed绝对居中定位
- arrowShow:是否显示三角指示箭头,布尔值,默认true显示,可以false不显示。
- arrowOffset:箭头偏移值,字符串格式,默认2.8rem(当*-start或*-end时并且btn尺寸大于box一半,三角指示箭头的边距,单位可以是px或rem,注意1rem=10px)
- gap:浮层与按钮的间距,字符串格式,默认0.8rem(单位可以是px或rem,注意1rem=10px)
- observer:监听观察对象,可以填"#id"、".className"、"div"等原生选择器以及Dom对象,默认是document.body
- onInit:监听函数,监听初始化,支持参数placement
- onUpdated:监听函数,监听更新位置,支持参数placement
需要注意的是,由于定位浮层是使用position:absolute绝对定位,所以不应该将浮层放在某相对定位的容器里,而应该放在body之下。
操作方法
插件实例存在可使用的变量:
this.btnDom
按钮节点,是一个对象this.btnData
按钮的数据,是一个对象,包含按钮的宽、高、边距等this.boxDom
浮层节点,是一个对象this.boxData
浮层的数据,是一个对象,包含浮层的宽、高、边距等this.browserData
浏览器可见窗口的数据,是一个对象,包含浮窗口的宽和高this.placement
当前浮层的位置this.arrow
三角指示箭头节点,是一个对象
插件实例存在可使用的操作方法:
this.update(callback)
更新位置,支持callback回调,回调函数支持placement参数this.change(btn,callback)
更新定位按钮,支持新按钮节点和callback回调:- btn:新按钮节点,可以填"#id"、".className"、"div"等原生选择器以及Dom对象。
- callback:重定位后的回调函数,支持参数placement即当前的浮层位置。
监听事件
本插件功能单一,但是也支持两个监听事件。具体事件说明如下:
onInit
初始化后执行,无参数update/onUpdate
更新位置后执行,支持参数placement
示例:现有浮层定位
如果浮层已经写入了页面,同时不是display:none
的隐藏状态,则可直接定位到按钮上。
为了避免占位或者跳跃,可事先对浮层使用visibility:hidden
属性隐藏,定位完成了才显示出来。
如果浮层是display:none的隐藏状态,则应该先删除display:none再追加visibility:hidden
属性。
关于两种隐藏状态display:none和visibility:hidden的区别请自行查阅资料。
-
<a href="###" class="ax-btn ax-primary" id="btn01">已显示浮层</a> <a href="###" class="ax-btn ax-primary" id="btn02">不可见浮层</a> <a href="###" class="ax-btn ax-primary" id="btn03">display:none浮层</a> <!--box要放在body之下--> <div class="box" id="box01">已存在并显示在页面的浮层</div> <div class="box" id="box02">已存在但不显示在页面的浮层</div> <div class="box" id="box03">已存在但display:none的浮层</div>
-
let btn01 = document.querySelector('#btn01'), btn02 = document.querySelector('#btn02'), btn03 = document.querySelector('#btn03'), box01 = document.querySelector('#box01'), box02 = document.querySelector('#box02'); box03 = document.querySelector('#box03'); new axPopupPosition(btn01, box01); new axPopupPosition(btn02, box02, { placement: 'bottom-end', //初始化后使之可见 onInit: function () { this.boxDom.style.visibility = 'visible'; } }); box03.style.display = 'block'; box03.style.visibility = 'hidden'; new axPopupPosition(btn03, box03, { placement: 'right', //初始化后使之可见 onInit: function () { this.boxDom.style.visibility = 'visible'; } }); btn01.onclick = () => { if (getComputedStyle(box01).visibility === 'visible') { box01.style.visibility = 'hidden'; } else { box01.style.visibility = 'visible'; } } btn02.onclick = () => { if (getComputedStyle(box02).visibility === 'visible') { box02.style.visibility = 'hidden'; } else { box02.style.visibility = 'visible'; } } btn03.onclick = () => { if (getComputedStyle(box03).visibility === 'visible') { box03.style.visibility = 'hidden'; } else { box03.style.visibility = 'visible'; } }
-
.box { width: 30rem; height: 30rem; padding: 1.4rem; box-sizing: border-box; background-color: aliceblue; border: 1px solid #ebebeb; position: absolute; z-index: 9; } .box [arrow] { width: 1.0rem; height: 1.0rem; box-shadow: 1px 1px 0 #ebebeb; background-color: inherit; } .box[placement^='top'] [arrow] { bottom: -0.5rem; transform: rotate(45deg); } .box[placement^='bottom'] [arrow] { top: -0.5rem; transform: rotate(-135deg); } .box[placement^='left'] [arrow] { right: -0.5rem; transform: rotate(-45deg); } .box[placement^='right'] [arrow] { left: -0.5rem; transform: rotate(135deg); } #box02 { visibility: hidden; } #box03 { display: none; }
示例:手动创建浮层定位
如果浮层节点还未创建,可手动创建节点并append到body中;如果浮层存在于内存中,则先append到body中。确保浮层并不是display:none的隐藏状态则可实施定位。
本示例只是展示创建和删除,更多细节未考虑。
-
<a href="###" class="ax-btn ax-primary" id="btn04">创建浮层并定位</a> <a href="###" class="ax-btn" id="btn05">清除浮层</a>
-
let elem = axAddElem('div', { class: 'box' }, '手动创建的浮层'), btn04 = document.querySelector('#btn04'), btn05 = document.querySelector('#btn05'); btn04.onclick = function () { //追加到页面 document.body.appendChild(elem); //定位 new axPopupPosition(this, elem); } btn05.onclick = function () { //删除节点 elem.remove(); }
-
.box { width: 30rem; height: 30rem; padding: 1.4rem; box-sizing: border-box; background-color: aliceblue; border: 1px solid #ebebeb; position: absolute; z-index: 9; } .box [arrow] { width: 1.0rem; height: 1.0rem; box-shadow: 1px 1px 0 #ebebeb; background-color: inherit; } .box[placement^='top'] [arrow] { bottom: -0.5rem; transform: rotate(45deg); } .box[placement^='bottom'] [arrow] { top: -0.5rem; transform: rotate(-135deg); } .box[placement^='left'] [arrow] { right: -0.5rem; transform: rotate(-45deg); } .box[placement^='right'] [arrow] { left: -0.5rem; transform: rotate(135deg); }
示例:重新定位
为了提高页面渲染效率,减少节点创建和删除操作,可对某一个浮层进行重定位,也就是将浮层定位到其他按钮。使用change(btn,callback)
方法实现重定位。
-
<a href="###" class="ax-btn ax-primary" id="btn06">创建浮层并定位</a> <a href="###" class="ax-btn" id="btn07">重定位</a> <a href="###" class="ax-btn" id="btn08">清除浮层</a>
-
let elem02 = axAddElem('div', { class: 'box' }, '将要重定位的浮层'), btn06 = document.querySelector('#btn06'), btn07 = document.querySelector('#btn07'), btn08 = document.querySelector('#btn08'), ins01 = new axPopupPosition(btn06, elem02); btn06.onclick = function () { //浮层不存在于页面 if (!getComputedStyle(elem02).display || getComputedStyle(elem02).display === 'none') { //追加到页面 document.body.appendChild(elem02); //更新位置 ins01.update(); } } btn07.onclick = function () { //浮层不存在于页面 if (!getComputedStyle(elem02).display || getComputedStyle(elem02).display === 'none') { //追加到页面 document.body.appendChild(elem02); } ins01.change(this, (placement) => { console.log('当前位置是:' + placement) }); } btn08.onclick = function () { //删除节点 elem02.remove(); }
-
.box { width: 30rem; height: 30rem; padding: 1.4rem; box-sizing: border-box; background-color: aliceblue; border: 1px solid #ebebeb; position: absolute; z-index: 9; } .box [arrow] { width: 1.0rem; height: 1.0rem; box-shadow: 1px 1px 0 #ebebeb; background-color: inherit; } .box[placement^='top'] [arrow] { bottom: -0.5rem; transform: rotate(45deg); } .box[placement^='bottom'] [arrow] { top: -0.5rem; transform: rotate(-135deg); } .box[placement^='left'] [arrow] { right: -0.5rem; transform: rotate(-45deg); } .box[placement^='right'] [arrow] { left: -0.5rem; transform: rotate(135deg); }