英文:
Generate content with Ajax - scroll to Id doesn't work
问题
我根据您的要求为您提供翻译的部分:
"我根据通过Ajax获取的数据生成页面内容。我遇到的问题是,当我想要滚动到一个ID时,要么滚动不发生,要么滚动到错误的位置。
我已经在Stack Overflow的问答中寻找了答案,但我没有找到任何很好的解决方案。很多答案都是针对Angular或React的,但对于纯JavaScript没有什么可靠的解决方案。
举个例子,假设用户点击一个链接“关于我们->项目”,其中“关于我们”是页面,而“项目”是页面末尾带有一些内容的ID。
问题发生在我从不同页面点击链接时。
假设我们在主页上,然后点击关于我们页面的项目链接(ID为projects)。这时滚动不起作用,不像预期的那样工作。如果我们在关于我们页面上点击项目链接,这个问题就不会发生。
由于页面数据是用JavaScript渲染的,我不能使用事件监听器DOMContentLoaded或load,因为它们会在内容生成之前触发(我认为)。
以下是我的非工作解决方案。它应该检查ID是否在视口中,如果不在,则应该滚动。
我不想使用setTimeout,因为它可能不会始终起作用(因为网络较慢,内容较多(图像)等原因)。
非常感谢您的帮助。
function generate(data){
// 代码
let idx = 0 // 以防万一,以免出现无限循环
if (window.location.href.indexOf("#") !== -1) {
const id = window.location.href.split("#")[1];
const element = document.getElementById(id);
document.addEventListener('DOMContentLoaded', function () {
console.log("已加载");
if (element) {
while (!isInViewport(id)) {
idx = idx + 1;
console.log(isInViewport(id))
scrollToElement(id);
if (idx === 10000){
break;
}
};
}
});
}
}
generateContent();
function scrollToElement(id) {
const element = document.getElementById(id);
if (element) {
element.scrollIntoView({
behavior: 'smooth'
});
}
}
function isInViewport(id) {
const element = document.getElementById(id);
if (element) {
const rect = element.getBoundingClientRect();
return (
rect.top >= 0 &&
rect.left >= 0 &&
rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
rect.right <= (window.innerWidth || document.documentElement.clientWidth)
);
}
}
如果我可以提供任何其他数据,请告诉我。"
英文:
I am generating the page content depending on the data I get via ajax.
The problem I am having, is that when I would like to scroll to an ID, the scroll either doesn't happen or it scrolls to the wrong position.
I've been looking at SO q&a, but I haven't found any good solutions. A lot of answers are for Angular or React, but nothing really solid for plain js.
As an example, lets say the user clicks a link About us -> Project, where about us is the page and projects is in id at the end of the page with some content.
The problem occurs when I click the link from a different page.
Lets say we are on the home page, an we click a link for the about us page, section projects (id projects). This is when the scroll doesn't work as it is supposed to. If we click on the link project, when we are on the about us page, this problem doesn't happen.
As the page data in being rendered with javascript, I can't use event listeners DOMContentLoaded
or load
, as they trigger before the content is being generated (I think).
Below is my non working solution. It is supposed to check if the id is in viewport, and if not, it should scroll.
I don't want to use setTimeout
as it might not always work (slow internet, more content (images) etc.)
Any help would be much appreciated.
function generate(data){
// code
let idx = 0 //just in case, so we don't have an infinite loop
if (window.location.href.indexOf("#") !== -1) {
const id = window.location.href.split("#")[1];
const element = document.getElementById(id);
document.addEventListener('DOMContentLoaded', function () {
console.log("loaded");
if (element) {
while (!isInViewport(id)) {
idx = idx + 1;
console.log(isInViewport(id))
scrollToElement(id);
if (idx === 10000){
break;
}
};
}
});
}
}
generateContent();
function scrollToElement(id) {
const element = document.getElementById(id);
if (element) {
element.scrollIntoView({
behavior: 'smooth'
});
}
}
function isInViewport(id) {
const element = document.getElementById(id);
if (element) {
const rect = element.getBoundingClientRect();
return (
rect.top >= 0 &&
rect.left >= 0 &&
rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
rect.right <= (window.innerWidth || document.documentElement.clientWidth)
);
}
}
If I can provide any additional data, please let me know.
答案1
得分: 0
虽然这不是最优雅的解决方案,但目前它有效。
如果有人能找出更好的解决方法,请告诉我。
编辑:稍微修改了代码,解决了用户滚动后仍然出现编程滚动问题。
function generateContent(data){
// 代码
if (window.location.href.indexOf("#") !== -1) {
const id = window.location.href.split("#")[1];
const element = document.getElementById(id);
if (element) {
scrollToLoop(id);
}
}
}
generateContent();
let isUserScrolling = false;
window.addEventListener("wheel", function () {
isUserScrolling = true;
});
window.addEventListener("touchmove", function () {
isUserScrolling = true;
});
function scrollToLoop(id, scrl) {
let scroll = scrl;
const element = document.getElementById(id);
if (element) {
if (!isInViewport(id) && scroll && !isUserScrolling) {
scrollToElement(id);
setTimeout(() => {
if (!isInViewport(id)) {
scrollToLoop(id, true);
}
}, 500);
} else {
setTimeout(() => {
if (!isInViewport(id) && scroll && !isUserScrolling) {
scrollToLoop(id, true);
}
}, 500);
}
}
}
英文:
while it is not the most elegant solution it is working so far.
If anyone can figure out something better, please let me know.
Edit: Changed the code a little bit, removing the problem with programmatic scrolling even after user scrolls.
function generateContent(data){
// code
if (window.location.href.indexOf("#") !== -1) {
const id = window.location.href.split("#")[1];
const element = document.getElementById(id);
if (element) {
scrollToLoop(id);
}
}
}
generateContent();
let isUserScrolling = false;
window.addEventListener("wheel", function () {
isUserScrolling = true;
});
window.addEventListener("touchmove", function () {
isUserScrolling = true;
});
function scrollToLoop(id, scrl) {
let scroll = scrl;
const element = document.getElementById(id);
if (element) {
if (!isInViewport(id) && scroll && !isUserScrolling) {
scrollToElement(id);
setTimeout(() => {
if (!isInViewport(id)) {
scrollToLoop(id, true);
}
}, 500);
} else {
setTimeout(() => {
if (!isInViewport(id) && scroll && !isUserScrolling) {
scrollToLoop(id, true);
}
}, 500);
}
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论