目录
一、效果展示
二、实现代码
1、ListSet对象
if (typeof ListSet != 'undefined') {
delete ListSet;
}
/**
*
* @param eleId
* @param navs [{text: '',url: '',attributes: {}, style:{}, number:'', show: true},{text: '',url: '',attributes: {}, style:{}, number:'', show:true}]
* @returns {ListSet}
* @constructor
*/
var ListSet = function ({
eleId,
navs = [],
navHeight = 80,
navScrollHeight = 0,
iframeHeight = '100vh',
iframeWidth = '100%',
forceIframeHeight = false,
}) {
if (!eleId) {
throw new Error('未设置根节点元素');
}
if (!navs.length) {
throw new Error('未设置nav菜单');
}
this._rootElement = document.getElementById(eleId);
if (!this._rootElement) {
throw new Error('未找到根节点元素');
}
this._iframeH = iframeHeight;
this._iframeW = iframeWidth;
this._forceIframeH = forceIframeHeight;
this._rangeKey = Math.ceil(Math.random() * 10000);
this._scrollBox = document.createElement('div');
this._navElement = document.createElement('ul');
this._iframeElement = document.createElement('div');
this._activeIframe = 0;
this._navs = navs;
this._navItems = [];
this._iframes = [];
this._loading = null;
this._isMove = false;
this._scrollBox.append(this._navElement);
this._rootElement.append(this._scrollBox);
this._rootElement.append(this._iframeElement);
this._iframeElement.style = `position:relative;
border-top: 3px solid rgba(0,0,0,0.3);
overflow: auto;
-webkit-border-radius: 3px 3px 0px 0px;
-moz-border-radius: 3px 3px 0px 0px;
border-radius: 3px 3px 0px 0px;`;
this._navElement.style = ` width: calc(100% + 40px);
height: ${navHeight}px;
overflow: scroll;
padding: 0px 10px;
margin-left: -10px;
display: flex;
flex-wrap: nowrap;`;
let scrollH = this._scrollBox.scrollHeight - this._scrollBox.offsetHeight;
if (navScrollHeight > 2 * scrollH) {
navScrollHeight = 2 * scrollH;
}else if(navScrollHeight < 0){
navScrollHeight = 0;
}
this._scrollBox.style = ` width: 100%;
height: ${navHeight - scrollH * 2 + navScrollHeight}px;
overflow: hidden;
margin-bottom: 5px;`;
scrollH = this._scrollBox.scrollHeight - this._scrollBox.offsetHeight;
this.initNavs();
this.createIframe();
this.eventListener();
return this;
}
2、添加横向滑动事件(滚动)
ListSet.prototype.eventListener = function () {
let isDown = false, downX = 0, startX = this._navElement.scrollLeft;
if (this._navElement.addEventListener) {
this._navElement.addEventListener('mousedown', (e) => {
isDown = true;
downX = e.screenX;
startX = this._navElement.scrollLeft
});
this._navElement.addEventListener('mousemove', (e) => {
if (isDown) {
let distance = e.screenX - downX;
this._navElement.scrollTo(-distance + startX, 0);
if (Math.abs(distance) > 100) {
this._isMove = true;
}
}
});
this._navElement.addEventListener('mouseup', (e) => {
isDown = false;
});
this._navElement.addEventListener('mouseleave', (e) => {
isDown = false;
this._isMove = false;
})
}
}
3、添加加载效果展示
ListSet.prototype.loading = function () {
let n = 0;
if (!this._loading) {
this._loading = document.createElement('div');
this._loading.style = ` display:none;
width: 100%;
position: absolute;
top: 0px;
left: 0px;
z-index: 100;`;
this._iframeElement.insertBefore(this._loading, this._iframes[0]);
let ul = document.createElement('ul'), lis = [];
ul.style = `width: 100%;
height: 200px;
display:flex;
justify-content: center;
align-items: center;
background:white;`;
this._loading.append(ul);
for (var i = 0; i < 3; i++) {
var li = document.createElement('li');
li.style = `width: 15px;
list-style: none;
height: 15px;
-webkit-border-radius: 15px;
-moz-border-radius: 15px;
border-radius: 15px;
border: 1px solid #ccc;
background: #ddd;
margin: 0px 10px;`;
ul.append(li);
lis.push(li);
}
this._loadingLis = lis;
}
this._iframes[this._activeIframe].style.visibility = 'hidden';
try {
this._iframes[this._activeIframe].contentWindow.location.reload(true);
} catch (e) {
this._iframes[this._activeIframe].src = this._navs[this._activeIframe].url;
}
this._loading.style.display = 'block';
if (this._loadingHandle) clearInterval(this._loadingHandle);
this._loadingHandle = setInterval(() => {
this._loadingLis.forEach((li, i) => {
if (i == n) {
li.style.background = 'red';
} else {
li.style.background = '#ddd';
}
})
n++;
if (n >= this._loadingLis.length) {
n = 0;
}
}, 100);
return this;
}
4、关闭加载效果
ListSet.prototype.loaded = function () {
if (this._loading) {
this._loading.style.display = 'none';
clearInterval(this._loadingHandle);
this._loadingHandle = null;
}
}
5、创建tabs导航栏
ListSet.prototype.initNavs = function () {
let w = 0, tw = this._navElement.clientWidth;
this._navElement.classList.value = 'list-nav-box';
this._navs.forEach((item, index) => {
if (!item.text || !item.url) {
throw new Error(item.text ? '未设置请求url' : '未设置nav菜单文本')
}
if (item.show) {
let li = document.createElement('li');
li.style = `list-style: none;
display: flex;
justify-content: center;
align-items: center;
padding: 10px 30px;
background: #b4bbc5;
flex-wrap: nowrap;
margin: 0px 1px;
cursor: pointer;
min-width: 200px;`;
this._navElement.append(li);
li.innerHTML = `<span>${item.text}</span><span">${item.num ? item.num : ''}</span>`;
if (item.attributes) {
for (var attrName in item.attributes) {
li.setAttribute(attrName, item.attributes[attrName]);
}
}
if (item.style) {
for (var name in item.style) {
li.style[name] = item.style[name];
}
}
li.addEventListener('mouseup', (e) => {
if (this._isMove) {
this._isMove = false;
return false;
}
this._activeIframe = index;
this._iframes.forEach((iframe, i) => {
if (i == index) {
iframe.style.display = 'block';
} else {
iframe.style.display = 'none';
}
});
if (!this._iframes[index]) {
this.createIframe();
} else {
if (this._forceIframeH) {
this._iframes[index].style.height = this._iframeH;
} else {
try {
this._iframes[index].style.height = this._iframes[index].contentWindow.document.body.scrollHeight + 'px';
} catch (e) {
this._iframes[index].style.height = this._iframeH;
}
}
}
this._navItems.forEach((liItem, j) => {
if (j == index) {
liItem.style.background = '#f2f2f2';
} else {
liItem.style.background = '#b4bbc5';
}
})
});
li.addEventListener('dblclick', (e) => {
if (this._activeIframe == index) {
this.loading();
}
})
if (!this._navItems.length) {
this._activeIframe = index;
}
this._navItems[index] = li;
}
})
return this;
}
6、创建iframe窗口(高度自适应 内容高度)
ListSet.prototype.createIframe = function () {
let frame = document.createElement('iframe'), item = this._navs[this._activeIframe];
frame.style = `width: ${this._iframeW};
height: ${this._iframeH};
border: 0px;
visibility: visible;`;
frame.src = item.url;
frame.name = 'iframe' + this._activeIframe;
frame.onload = () => {
if (this._forceIframeH) {
frame.style.height = this._iframeH;
} else {
try {
// frame.contentWindow.onbeforeunload = function () {
// // todo:: 加载完成前执行
// frame.style.height = 'auto';
// };
frame.style.height = frame.contentWindow.document.body.scrollHeight + 'px';
} catch (e) {
frame.style.height = this._iframeH;
}
}
frame.style.visibility = 'visible';
this.loaded();
};
this._navItems[this._activeIframe].style.background = '#f2f2f2';
this._iframeElement.append(frame);
this._iframes[this._activeIframe] = frame;
this.loading();
return this;
}
7、完整代码
if (typeof ListSet != 'undefined') {
delete ListSet;
}
/**
*
* @param eleId
* @param navs [{text: '',url: '',attributes: {}, style:{}},{text: '',url: '',attributes: {}, style:{}}]
* @returns {ListSet}
* @constructor
*/
var ListSet = function ({
eleId,
navs = [],
scrollMode = false,
navHeight = 80,
navScrollHeight = 0,
iframeHeight = '100vh',
iframeWidth = '100%',
forceIframeHeight = false,
clickEvent = null,
iframeBeforeOnLoad = null,
iframeAfterOnLoad = null,
}) {
if (!eleId) {
throw new Error('未设置根节点元素');
}
if (!navs.length) {
throw new Error('未设置nav菜单');
}
this._scrollMode = scrollMode;
this._rootElement = document.getElementById(eleId);
if (!this._rootElement) {
throw new Error('未找到根节点元素');
}
this._iframeH = iframeHeight;
this._iframeW = iframeWidth;
this._forceIframeH = forceIframeHeight;
this._rangeKey = Math.ceil(Math.random() * 10000);
this._scrollBox = document.createElement('div');
this._navElement = document.createElement('ul');
this._iframeElement = document.createElement('div');
this._activeIframe = 0;
this._navs = navs;
this._clickEvent = clickEvent;
this._iframeAfterOnLoad = iframeAfterOnLoad;
this._iframeBeforeOnLoad = iframeBeforeOnLoad;
this._navItems = [];
this._iframes = [];
this._loading = null;
this._isMove = false;
this._scrollBox.append(this._navElement);
this._rootElement.append(this._scrollBox);
this._rootElement.append(this._iframeElement);
this._navElement.classList.add('multi-window-nav-box');
this._iframeElement.classList.add('multi-window-iframe-box');
this._scrollBox.classList.add('multi-window-scroll-div');
let scrollH = this._scrollBox.scrollHeight - this._scrollBox.offsetHeight;
if (navScrollHeight > 2 * scrollH) {
navScrollHeight = 2 * scrollH;
} else if (navScrollHeight < 0) {
navScrollHeight = 0;
}
scrollH = this._scrollBox.scrollHeight - this._scrollBox.offsetHeight;
this.initStyle({
navHeight: scrollMode ? (navHeight + "px") : "auto",
navOverflow: scrollMode ? "scroll" : "auto",
navFlexWrap: scrollMode ? "nowrap" : "wrap",
scrollHeight: scrollMode ? (navHeight - scrollH * 2 + navScrollHeight) + "px" : "auto",
})
this.initNavs();
this.createIframe();
this.eventListener();
return this;
}
ListSet.prototype.initStyle = function ({
navHeight = 'auto',
navOverflow = 'auto',
navFlexWrap = 'wrap',
scrollHeight = 'auto',
}) {
let style = document.createElement('style');
style.innerHTML = `
.multi-window-nav-box{
width: calc(100% + 40px);
padding: 0px 10px 0px 0px;
display: flex;
margin: 0px;
height: ${navHeight};
overflow: ${navOverflow};
flex-wrap: ${navFlexWrap};
}
.multi-window-nav-box > .multi-window-nav-item{
list-style: none;
display: flex;
justify-content: center;
align-items: center;
padding: 10px 25px;
width: 14%;
min-width: 160px;
flex-wrap: nowrap;
margin: ${this._scrollMode ? 0 : 1}px 1px;
cursor: pointer;
background: #b4bbc5;
font-size: 14px;
}
.multi-window-nav-active{
background: rgb(242, 242, 242) !important;
color: red !important;
font-weight: bold;
font-size: 16px;
}
.multi-window-iframe-box{
position:relative;
border-top: 3px solid rgba(0, 0, 0, 0.3);
-webkit-border-radius: 3px 3px 0px 0px;
-moz-border-radius: 3px 3px 0px 0px;
border-radius: 3px 3px 0px 0px;
}
.multi-window-iframe-box > iframe{
width: ${this._iframeW};
height: ${this._iframeH};
border: 0px;
visibility: visible;
}
.multi-window-scroll-div{
width: 100%;
overflow: hidden;
margin: 2px 0px;
height: ${scrollHeight};
}
.multi-window-loading{
display:none;
width: 100%;
position: absolute;
top: 0px;
left: 0px;
z-index: 100;
}
.multi-window-loading > ul{
width: 100%;
height: 200px;
display:flex;
justify-content: center;
align-items: center;
background:white;
}
.multi-window-loading > ul > li{
width: 15px;
list-style: none;
height: 15px;
-webkit-border-radius: 15px;
-moz-border-radius: 15px;
border-radius: 15px;
border: 1px solid #ccc;
background: #ddd;
margin: 0px 10px;
}
`;
document.querySelector('head').append(style);
return this;
}
ListSet.prototype.eventListener = function () {
let isDown = false, downX = 0, startX = this._navElement.scrollLeft;
if (this._navElement.addEventListener) {
this._navElement.addEventListener('mousedown', (e) => {
isDown = true;
downX = e.screenX;
startX = this._navElement.scrollLeft
});
this._navElement.addEventListener('mousemove', (e) => {
if (isDown) {
let distance = e.screenX - downX;
this._navElement.scrollTo(-distance + startX, 0);
if (Math.abs(distance) > 100) {
this._isMove = true;
}
}
});
this._navElement.addEventListener('mouseup', (e) => {
isDown = false;
});
this._navElement.addEventListener('mouseleave', (e) => {
isDown = false;
this._isMove = false;
})
}
}
ListSet.prototype.loading = function () {
let n = 0;
if (!this._loading) {
this._loading = document.createElement('div');
this._loading.classList.add('multi-window-loading');
this._iframeElement.insertBefore(this._loading, this._iframes[0]);
let ul = document.createElement('ul'), lis = [];
this._loading.append(ul);
for (var i = 0; i < 3; i++) {
var li = document.createElement('li');
ul.append(li);
lis.push(li);
}
this._loadingLis = lis;
}
this._iframes[this._activeIframe].style.visibility = 'hidden';
try {
this._iframes[this._activeIframe].contentWindow.location.reload(true);
} catch (e) {
this._iframes[this._activeIframe].src = this._navs[this._activeIframe].url;
}
this._loading.style.display = 'block';
if (this._loadingHandle) clearInterval(this._loadingHandle);
this._loadingHandle = setInterval(() => {
this._loadingLis.forEach((li, i) => {
if (i == n) {
li.style.background = 'red';
} else {
li.style.background = '#ddd';
}
})
n++;
if (n >= this._loadingLis.length) {
n = 0;
}
}, 100);
return this;
}
ListSet.prototype.loaded = function () {
if (this._loading) {
this._loading.style.display = 'none';
clearInterval(this._loadingHandle);
this._loadingHandle = null;
}
}
ListSet.prototype.initNavs = function () {
let w = 0, tw = this._navElement.clientWidth;
this._navs.forEach((item, index) => {
if (!item.text || !item.url) {
throw new Error(item.text ? '未设置请求url' : '未设置nav菜单文本')
}
if (typeof item['show'] == 'undefined' || item.show) {
let li = document.createElement('li');
li.classList.add('multi-window-nav-item')
this._navElement.append(li);
li.innerHTML = `<span>${item.text}</span>${item.num ? "<span>" + item.num + "</span>" : ''}`;
if (item.attributes) {
for (var attrName in item.attributes) {
li.setAttribute(attrName, item.attributes[attrName]);
}
}
if (item.style) {
for (var name in item.style) {
li.style[name] = item.style[name];
}
}
li.addEventListener('mouseup', (e) => {
if (this._clickEvent) {
this._clickEvent.call(this, e, item, index)
}
if (this._isMove) {
this._isMove = false;
return false;
}
this._activeIframe = index;
this._iframes.forEach((iframe, i) => {
if (i == index) {
iframe.style.display = 'block';
} else {
iframe.style.display = 'none';
}
});
if (!this._iframes[index]) {
this.createIframe();
} else {
if (this._forceIframeH) {
this._iframes[index].style.height = this._iframeH;
} else {
try {
this._iframes[index].style.height = this._iframes[index].contentWindow.document.body.scrollHeight + 'px';
} catch (e) {
this._iframes[index].style.height = this._iframeH;
}
}
}
this._navItems.forEach((liItem, j) => {
if (j == index) {
liItem.classList.add('multi-window-nav-active');
} else {
liItem.classList.remove('multi-window-nav-active');
}
})
});
li.addEventListener('dblclick', (e) => {
if (this._activeIframe == index) {
this.loading();
}
})
if (!this._navItems.length) {
this._activeIframe = index;
}
this._navItems[index] = li;
}
})
return this;
}
ListSet.prototype.createIframe = function () {
let frame = document.createElement('iframe'), item = this._navs[this._activeIframe];
frame.src = item.url;
frame.name = 'iframe' + this._activeIframe;
frame.onload = (event) => {
// console.log(222, event)
if (this._iframeAfterOnLoad) {
this._iframeAfterOnLoad.call(this, item);
}
if (this._forceIframeH) {
// frame.style.height = this._iframeH;
if (this._iframeBeforeOnLoad) {
this._iframeBeforeOnLoad.call(this, item);
}
} else {
try {
frame.contentWindow.onbeforeunload = (e) => {
// console.log(1111, e)
// todo:: 加载完成前执行
if (this._iframeBeforeOnLoad) {
this._iframeBeforeOnLoad.call(this, item);
}
};
// frame.style.height = (frame.contentWindow.document.body.scrollHeight) + 'px';
} catch (e) {
// frame.style.height = this._iframeH;
if (this._iframeBeforeOnLoad) {
this._iframeBeforeOnLoad.call(this, item);
}
}
}
frame.style.visibility = 'visible';
this.loaded();
};
this._navItems[this._activeIframe].classList.add('multi-window-nav-active');
this._iframeElement.append(frame);
this._iframes[this._activeIframe] = frame;
this.loading();
return this;
}
function iframeCall({
callback = null,
fireOptions = null,
confirmCallback = null,
cancelCallback = null,
errorCallback = null,
callThis = null,
}) {
if (fireOptions) {
swal.fire(fireOptions).then((isConfirm) => {
try {
if (isConfirm.value) {
confirmCallback && confirmCallback.call(callThis ? callThis : this);
} else {
cancelCallback && cancelCallback.call(callThis ? callThis : this);
}
} catch (e) {
errorCallback && errorCallback.call(callThis ? callThis : this, e);
}
})
}
if (callback) {
if (typeof callback == 'string') {
eval('var fn = ' + callback);
fn.call(callThis ? callThis : this);
} else {
callback.call(callThis ? callThis : this);
}
}
}
三、Example
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
#list-set-box {
width: 100%;
overflow: auto;
padding-top: 10px;
}
</style>
</head>
<body>
<section id="list-set-box"></section>
</body>
</html>
let listSet = new ListSet({
eleId: 'list-set-box',
navHeight = 80,
navScrollHeight = 0,
iframeHeight = '100vh',
iframeWidth = '100%',
forceIframeHeight = false,
navs: [
{
text:'百度',
url:'https://www.baidu.com',
show: true,
num:'<span style="color:red;">(10)</span>',
attributes: {},
style:{}
},{
text:'淘宝',
url:'https://www.taobao.com',
show: true,
num:'',
attributes: {},
style:{}
},{
text:'京东',
url:'https://www.jd.com',
show: true,
num:'',
attributes: {},
style:{}
}
],
})
四、总结经验
至此,完美的实现多个页面之间的切换。
(注意:如果iframe的src是跨域路径,无法获取document.body的高度,所以无法实现iframe自适应高度,可以通过设置固定的iframeHeight值,默认为100vh )
以上内容希望能够帮助到有需要的博友们!!!