直接上代码(function(factory) {
(function() {
return class {
static version = ‘0.0.1’;
constructor(obj) {
this.mode = obj.mode;
this.step = obj.step;
this.el = obj.el;
}
getDomPos(elName) {
const dom = document.querySelectorAll(elName)[0];
dom.style.pointerEvents = 'none';
dom.style.zIndex = 13;
// dom.style.position = 'relative';
dom.style.position = getComputedStyle(dom, null)['position'] === '' || getComputedStyle(dom, null)['position'] === 'static' ? 'relative' : getComputedStyle(dom, null)['position'];
const firstDomPos = dom.getBoundingClientRect();
let left = 0;
let top = 0;
const docWidth = document.body.clientWidth;
const docHeight = document.body.clientHeight;
if (docWidth - firstDomPos.width > 370 && firstDomPos.left > 370) {
left = firstDomPos.left - 370;
} else if (docWidth - firstDomPos.width - firstDomPos.left > 370) {
left = firstDomPos.left + firstDomPos.width + 20;
} else {
left = firstDomPos.width / 2 + firstDomPos.left;
dom.style.zIndex = 13;
}
if (docHeight - firstDomPos.height - firstDomPos.top > 400) {
top = firstDomPos.height + firstDomPos.top + 20;
} else if (firstDomPos.top > 300) {
top = firstDomPos.top - 300;
}
if (docWidth - firstDomPos.width < 380 && docHeight - firstDomPos.height < 280) {
top = firstDomPos.height / 2 + firstDomPos.top;
dom.style.opacity = 0.8;
dom.style.zIndex = 13;
}
return {
x: left,
y: top,
}
}
guideMove(dialog, mask, message, nextBtn, title, id) {
const arr = [];
let num = 0;
this.step = this.step.splice(id - 1, this.step.length);
this.step.forEach(item => {
arr.push(typeof item.el === 'object' ? item.el : document.querySelector(item.el));
})
nextBtn.onclick = (e) => {
if (nextBtn.innerHTML === '完成') {
mask.style.display = 'none';
dialog.style.display = 'none';
return true;
}
num = num + 1;
// 禁用每个引导元素的点击事件和设置层级
arr[num].style.pointerEvents = 'none';
arr[num].style.position = getComputedStyle(arr[num], null)['position'] === '' || getComputedStyle(arr[num], null)['position'] === 'static' ? 'relative' : getComputedStyle(arr[num], null)['position'];
arr[num].style.setProperty('z-index',13,'important');
arr[num-1].style.zIndex = 'auto';
arr[num-1].style.opacity = 1;
message.innerHTML = this.step[num].content;
title.innerHTML = `第${ id - 0 + num - 0 }步`
let left = '';
let top = '';
const elPosition = arr[num].getBoundingClientRect();
const docWidth = document.body.clientWidth;
const docHeight = document.body.clientHeight;
const place = this.position(dialog, arr[num], elPosition, docWidth, docHeight, left, top);
if (num === this.step.length - 1) {
arr[num].style.zIndex = 13;
nextBtn.innerHTML = '完成';
dialog.style.transform = `translate(${ place.left }, ${ place.top })`;
num = 0;
} else {
const posi = this.position(dialog, arr[num], elPosition, docWidth, docHeight, left, top);
dialog.style.transform = `translate(${ posi.left }, ${ posi.top })`;
}
}
}
position(dialog, arr, elPosition, docWidth, docHeight, left, top) {
if (docWidth - elPosition.width > 370 && elPosition.left > 350) {
left = elPosition.left - dialog.getBoundingClientRect().width - 20 + 'px'
} else if (docWidth - elPosition.width - elPosition.left > 370) {
left = elPosition.left + elPosition.width + 20 + 'px';
} else {
left = elPosition.width / 2 + elPosition.left + 'px';
arr.style.opacity = 0.8;
}
if (docHeight - elPosition.height > dialog.getBoundingClientRect().height && elPosition.top > dialog.getBoundingClientRect().height) {
top = elPosition.top - dialog.getBoundingClientRect().height + 'px';
} else if (docHeight - elPosition.height - elPosition.top > dialog.getBoundingClientRect().height) {
top = elPosition.top + elPosition.height + 'px';
} else {
top = elPosition.height / 2 + elPosition.top + 'px';
arr.style.opacity = 0.8;
}
return {
top,
left
}
}
init(id) {
const dom = document.createElement('div');
this.css = this.createCss(id);
const css = this.css;
dom.classList.add('guide');
dom.innerHTML = `
<div class="mask"></div>
<div class="dialog">
<h3 class="title"></h3>
<p class="message"></p>
<div class="control">
<button class="next">下一步</button>
</div>
</div>`;
document.body.appendChild(dom);
const dialog = document.querySelectorAll('.guide .dialog')[0];
const mask = document.querySelectorAll('.guide .mask')[0];
const message = dialog.querySelector('.message');
const nextBtn = dialog.querySelector('.next');
const title = dialog.querySelector('.title');
const control = dialog.querySelector('.control');
message.innerHTML = this.step[id - 1].content;
title.innerHTML = `第${ id }步`;
dialog.style.fontSize = '16px';
// mask 样式
this.setCss(css.container, mask);
// dialog 样式
this.setCss(css.dialog, dialog);
// dialog内容 样式
this.setCss(css.content, message);
// 下一步按钮 样式
this.setCss(css.nextBtn, nextBtn);
this.setCss(css.title, title);
this.setCss(css.control, control);
this.guideMove(dialog, mask, message, nextBtn, title, id);
// 给下一步按钮添加houve和active事件
nextBtn.onmouseover = function () {
this.style.background = '#d9ecff';
};
nextBtn.onmouseout = function () {
this.style.background = '#ecf5ff';
};
nextBtn.onmousedown = function () {
this.style.background = '#c5e2ff';
};
}
setCss(css, el) {
Object.keys(css).forEach((attrName) => el.style[attrName] = css[attrName]);
}
createCss(id) {
const firstPos = this.getDomPos(this.step[id - 1].el);
return {
container: {
position: 'fixed',
top: 0,
left: 0,
width: '100%',
height: '100%',
background: 'rgba(0, 0, 0, .7)',
zIndex: 12,
},
dialog: {
position: 'fixed',
top: 0,
left: 0,
overflowY: 'auto',
minWidth: '300px',
maxWidth: '350px',
minHeight: '120px',
maxHeight: '70%',
background: '#FFFFFF',
transform: `translate( ${ firstPos.x }px, ${ firstPos.y }px )`,
transition: 'all .3s',
zIndex: 13,
},
content: {
padding: '0 20px',
lineHeight: 1.8,
fontSize: '14px',
maxWidth: '360px',
color: '#606266!important',
wordBreak: 'break-all',
},
nextBtn: {
display: 'inline-block',
width: '60px',
height: '35px',
border: 0,
outline: 'none',
color: '#409eff',
background: '#ecf5ff',
font: 'normal 400 14px 黑体',
fontSize: '14px',
},
title: {
position: 'sticky',
top: 0,
padding: '20px 20px 15px 20px',
fontWeight: 600,
fontSize: '16px',
color: '#303133',
background: '#FFFFFF',
margin: 0,
},
control: {
position: 'sticky',
bottom: 0,
padding: '10px',
marginTop: '10px',
textAlign: 'right',
fontSize: 0,
background: '#FFFFFF',
},
}
}
}
}))
function getUrlParams(name) {
var reg = new RegExp(’(^|&)’ + name + ‘=([^&]*)(&|$)’, ‘i’);
var r = location.search.substr(1).match(reg);
return r === null ? ‘’ : unescape(r[2]);
}
调用(html中再写几个div绑定下面的ID,也可以在项目中用)
var book = {
s0001: {
title: ‘如何创建ABC’,
data: {
el: ‘#nav-container’,
mode: ‘dark’,
step: [{
el: ‘#meetinginvitevisitorform-address’,
content: ‘这是第二步’
}, {
el: ‘#meetinginvitevisitorform-create_by’,
content: ‘这是第三步’
}, {
el: ‘#w2’,
content: ‘这是第一步’
}, {
el: ‘#content’,
content: ‘随后一部’
}]
}
}
}
因为是后期调整成了跨页面的,所以地址栏中要加参数v
地址栏中拼接 ?guideId=1&guideStep=1