Skip to content

Commit

Permalink
基本完成
Browse files Browse the repository at this point in the history
  • Loading branch information
wanglin25 committed Mar 1, 2023
1 parent dd7488a commit 56bfa22
Show file tree
Hide file tree
Showing 17 changed files with 269 additions and 1,742 deletions.
24 changes: 0 additions & 24 deletions .gitignore

This file was deleted.

3 changes: 0 additions & 3 deletions .vscode/extensions.json

This file was deleted.

18 changes: 0 additions & 18 deletions README.md

This file was deleted.

13 changes: 0 additions & 13 deletions index.html

This file was deleted.

269 changes: 269 additions & 0 deletions noviceGuide.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,269 @@
class NoviceGuide {
constructor(options) {
this.options = Object.assign(
{
padding: 10,
margin: 10,
},
options
);
// 步骤数据
this.steps = [];
// 当前所在步骤
this.currentStepIndex = -1;
this.highlightEl = null;
this.infoEl = null;
this.initSteps();
}

initSteps() {
this.options.steps.forEach((step) => {
this.steps.push({
...step,
element:
typeof step.element === "string"
? document.querySelector(step.element)
: step.element,
});
});
}

start() {
this.next();
}

next() {
if (this.currentStepIndex + 1 >= this.steps.length) {
return this.done();
}
this.currentStepIndex++;
this.to();
}

prev() {
if (this.currentStepIndex - 1 < 0) {
return;
}
this.currentStepIndex--;
this.to();
}

to() {
const currentStep = this.steps[this.currentStepIndex];
if (!currentStep.element) {
// 当前步骤没有元素
this.highlightElement();
this.showStepInfo(currentStep);
return;
}
const rect = currentStep.element.getBoundingClientRect();
const windowHeight = window.innerHeight;
if (!this.elementIsInView(currentStep.element)) {
window.scrollBy(0, rect.top - (windowHeight - rect.height) / 2);
}
this.highlightElement(currentStep.element);
this.showStepInfo(currentStep);
}

done() {
document.body.removeChild(this.highlightEl);
document.body.removeChild(this.infoEl);
}

highlightElement(el) {
// box-shadow方式实现
if (!this.highlightEl) {
this.highlightEl = document.createElement("div");
this.highlightEl.style.cssText = `
position: absolute;
box-shadow: 0 0 0 5000px rgba(0, 0, 0, 0.5);
z-index: 99999999;
border-radius: 5px;
transition: all 0.3s ease-out;
`;
document.body.appendChild(this.highlightEl);
}
if (el) {
const rect = el.getBoundingClientRect();
let { padding } = this.options;
this.highlightEl.style.left =
rect.left + window.pageXOffset - padding + "px";
this.highlightEl.style.top =
rect.top + window.pageYOffset - padding + "px";
this.highlightEl.style.width = rect.width + padding * 2 + "px";
this.highlightEl.style.height = rect.height + padding * 2 + "px";
} else {
this.highlightEl.style.left =
window.innerWidth / 2 + window.pageXOffset + "px";
this.highlightEl.style.top =
window.innerHeight / 2 + window.pageYOffset + "px";
this.highlightEl.style.width = 0 + "px";
this.highlightEl.style.height = 0 + "px";
}
}

elementIsInView(el) {
const rect = el.getBoundingClientRect();
return (
rect.top >= 0 &&
rect.left >= 0 &&
rect.bottom <= window.innerHeight &&
rect.right <= window.innerWidth
);
}

showStepInfo(step) {
let { padding } = this.options;
if (!this.infoEl) {
this.infoEl = document.createElement("div");
this.infoEl.style.cssText = `
position: absolute;
z-index: 99999999;
background-color: #fff;
padding: ${padding}px;
border-radius: 5px;
`;
document.body.appendChild(this.infoEl);
this.infoEl.addEventListener("click", (e) => {
let type = e.target.getAttribute("data-type");
if (type) {
if (type === "prev") {
this.prev();
}
if (type === "next") {
this.next();
}
}
});
}
this.infoEl.innerHTML = `
<div style="width: 1200px; height: 500px;">
${
step.img
? `<div>
<img src="${step.img}" style="width: 250px" />
</div>`
: ""
}
<div>${step.text}</div>
</div>
<div>
<button data-type="prev">上一步</button>
<button data-type="next">下一步</button>
</div>
`;
if (step.element) {
this.computeInfoPosition(step);
} else {
const rect = this.infoEl.getBoundingClientRect();
this.infoEl.style.left =
(window.innerWidth - rect.width) / 2 + window.pageXOffset + "px";
this.infoEl.style.top =
(window.innerHeight - rect.height) / 2 + window.pageYOffset + "px";
}
}

computeInfoPosition(step) {
const { padding, margin } = this.options;
const windowWidth = window.innerWidth;
const windowHeight = window.innerHeight;
const windowPageXOffset = window.pageXOffset;
const windowPageYOffset = window.pageYOffset;
const rect = step.element.getBoundingClientRect();
const infoRect = this.infoEl.getBoundingClientRect();
let left = 0;
let top = 0;
const adjustLeft = () => {
// 优先和高亮框左对齐
if (windowWidth - rect.left - padding >= infoRect.width) {
return rect.left - padding + windowPageXOffset;
} else {
// 否则水平居中显示
return (windowWidth - infoRect.width) / 2 + windowPageXOffset;
}
};
const adjustTop = () => {
// 优先和高亮框上对齐
if (windowHeight - rect.top - padding >= infoRect.height) {
return rect.top - padding + windowPageYOffset;
} else {
// 否则水平居中显示
return (windowHeight - infoRect.height) / 2 + windowPageYOffset;
}
};
if (
rect.bottom + padding + margin + infoRect.height <= windowHeight && // 下方宽度可以容纳
infoRect.width <= windowWidth // 信息框宽度比浏览器窗口小
) {
// 可以在下方显示
left = adjustLeft();
top = rect.bottom + padding + margin + windowPageYOffset;
} else if (
rect.top - padding - margin >= infoRect.height &&
infoRect.width <= windowWidth
) {
// 可以在上方显示
left = adjustLeft();
top = rect.top - padding - margin - infoRect.height + windowPageYOffset;
} else if (
rect.left - padding - margin >= infoRect.width &&
infoRect.height <= windowHeight
) {
// 可以在左方显示
left = rect.left - padding - margin - infoRect.width + windowPageXOffset;
top = adjustTop();
} else if (
rect.right + padding + margin + infoRect.width <= windowWidth &&
infoRect.height <= windowHeight
) {
// 可以在右方显示
left = rect.right + padding + margin + windowPageXOffset;
top = adjustTop();
} else {
// 否则检查高亮框高度+信息框高度是否小于窗口高度
let totalHeightLessThenWindow =
rect.height + padding * 2 + margin + infoRect.height <= windowHeight;
if (
totalHeightLessThenWindow &&
Math.max(rect.width + padding * 2, infoRect.width) <= windowWidth
) {
// 上下排列可以放置
// 滚动页面,居中显示两者整体
let newTop =
(windowHeight -
(rect.height + padding * 2 + margin + infoRect.height)) /
2;
window.scrollBy(0, rect.top - newTop);
} else {
// 恕我无能为力
// 回到默认位置
}
left = adjustLeft();
top = rect.bottom + padding + margin + windowPageYOffset;
}
this.infoEl.style.left = left + "px";
this.infoEl.style.top = top + "px";
}
}

new NoviceGuide({
steps: [
{
element: ".js-pinned-items-reorder-form .Box",
text: "第一步",
},
{
element: ".graph-before-activity-overview",
text: "第二步",
img: "https://camo.githubusercontent.com/d00642928c6a6bef84b4f0d226d10ca4a2c5318cb483270b6085149ccfa1be59/687474703a2f2f6173736574732e6c78716e7379732e636f6d2f2545352538442538332545352542412539332545372542442539315f2545372542432539362545372541382538422545372541382538422545352542412538462545352539312539382545352538362539392545342542422541332545372541302538312545342542412542412545372538392541395f25453525383525383325453725423425413025453725424325393625453525384625423731333133343131302e706e67",
},
{
text: "纯文字描述",
img: "https://avatars.githubusercontent.com/u/17272433?v=4",
},
{
element: ".vcard-details",
text: "第三步",
},
],
}).start();
Loading

0 comments on commit 56bfa22

Please sign in to comment.