如何创建“活动”项跟随页面内容位置的侧边菜单?

时间:2022-02-09 09:09:58

I'm looking to learn how to do this left menu : http://js.devexpress.com/New/15_2/#HTML_5_JS_Core When you scroll down the page, the "active" menu item change.

我正在学习如何执行此左侧菜单:http://js.devexpress.com/New/15_2/#HTML_5_JS_Core当您向下滚动页面时,“活动”菜单项会发生变化。

p.s. Is there a name for this type of menu?

附:这种菜单有名称吗?

regards, yaniv

2 个解决方案

#1


2  

Scroll Navigation

That is how we call these type of navigation bars. Basically you have to listen to the scroll event and calculate which element is in the viewport at the moment than you add a class to your navigation that marks the current menu element.

这就是我们如何称呼这些类型的导航栏。基本上你必须听滚动事件并计算当前在视口中的哪个元素,而不是在导航中添加一个标记当前菜单元素的类。

There is a nice demo built in jQuery but because jQuery is a thing of the past, I built one in Vanilla JS. See comments for explanations.

有一个很好的演示在jQuery中,但因为jQuery已成为过去,我在Vanilla JS中构建了一个。请参阅注释以获得解释。

There are different ways to define which is the current element. In my Example it is the last one whose top line just passed the top line of the browser.

有不同的方法来定义哪个是当前元素。在我的示例中,它是最后一行,它的顶行刚刚通过了浏览器的顶行。

Working demo

window.onscroll = onScroll;

function onScroll() {
    var removeActiveClass = function (elements) {
        for (var i = 0; i < elements.length; ++i) {
            elements[i].classList.remove('active');
        }
    }
    var anchors = document.querySelectorAll('#menu-center a');
    var previousRefElement = null;
    for (var i = 0; i < anchors.length; ++i) {
        // Get the current element by the id from the anchor's href.
        var currentRefElement = document.getElementById(anchors[i].getAttribute('href').substring(1));
        var currentRefElementTop = currentRefElement.getBoundingClientRect().top;
        // Searching for the element whose top haven't left the top of the browser.
        if (currentRefElementTop <= 0) {
            //The browser's top line haven't reached the current element, so the previous element is the one we currently look at.
            previousRefElement = anchors[i];
            // Edge case for last element.
            if (i == anchors.length - 1) {
                removeActiveClass(anchors);
                anchors[i].classList.add("active");
            }
        } else {
            removeActiveClass(anchors);
            previousRefElement.classList.add("active");
            break;
        }
        
    }
}
body, html {
    margin: 0;
    padding: 0;
    height: 100%;
    width: 100%;
}
.menu {
    width: 100%;
    height: 75px;
    position: fixed;
    background-color:rgba(4, 180, 49, 0.6);
}
#menu-center {
    width: 980px;
    height: 75px;
    margin: 0 auto;
}
#menu-center ul {
    margin: 15px 0 0 0;
}
#menu-center ul li {
    list-style: none;
    margin: 0 30px 0 0;
    display: inline;
}
.active {
    font-size: 14px;
    color: #fff;
    text-decoration: none;
    line-height: 50px;
}
a {
    font-size: 14px;
    color: black;
    text-decoration: none;
    line-height: 50px;
}
.content {
    height: 100%;
    width: 100%;
}
#portfolio {background-color: grey;}
#about {background-color: blue;}
#contact {background-color: red;}
<div class="menu">
    <div id="menu-center">
        <ul>
            <li><a class="active" href="#home">Home</a></li>
            <li><a href="#portfolio">Portfolio</a></li>
            <li><a href="#about">About</a></li>
            <li><a href="#contact">Contact</a></li>
        </ul>
    </div>
</div>
<div id="home" class="content"></div>
<div id="portfolio" class="content"></div>
<div id="about" class="content"></div>
<div id="contact" class="content"></div>

#2


0  

This is not exactly menu type, it is the way how you can position objects by html.

这不是菜单类型,它是如何通过html定位对象的方式。

You can use position:Abosule property to achieve this effect: http://www.w3schools.com/css/tryit.asp?filename=trycss_position_fixed

您可以使用position:Abosule属性来实现此效果:http://www.w3schools.com/css/tryit.asp?filename = trycss_position_fixed

By this given divs are "flying" above the res of the page. In your case it could be a menu.

通过这个给定的div在页面的res之上“飞行”。在你的情况下,它可能是一个菜单。

EDIT:

To sync this you need to detect when given anchor is currently seen. It can be done by jQuery, this is sample draft of code, should explain clue of solution:

要同步这个,您需要检测当前是否看到给定锚点。它可以通过jQuery来完成,这是代码示例草案,应该解释解决方案的线索:

// list of header on page
var positions = [
    $("#anchor1").offset().top,
    $("#anchor2").offset().top,
    $("#anchor3").offset().top,
];
var menu_objects= [
    "#menu1",
    "#menu2",
    "#menu3"
];
var $w = $(window).scroll(function(){

// clear old
for(var v in menu_objects)
    $(v).css({"color","white"});

for(var i=positions.length-1;i>=0;i--)
{
    if(positions[i]>=$w.scrollTop())
    {
        $(menu_objects[i]).css({"color","red"});
        break;
    }
}
});

#1


2  

Scroll Navigation

That is how we call these type of navigation bars. Basically you have to listen to the scroll event and calculate which element is in the viewport at the moment than you add a class to your navigation that marks the current menu element.

这就是我们如何称呼这些类型的导航栏。基本上你必须听滚动事件并计算当前在视口中的哪个元素,而不是在导航中添加一个标记当前菜单元素的类。

There is a nice demo built in jQuery but because jQuery is a thing of the past, I built one in Vanilla JS. See comments for explanations.

有一个很好的演示在jQuery中,但因为jQuery已成为过去,我在Vanilla JS中构建了一个。请参阅注释以获得解释。

There are different ways to define which is the current element. In my Example it is the last one whose top line just passed the top line of the browser.

有不同的方法来定义哪个是当前元素。在我的示例中,它是最后一行,它的顶行刚刚通过了浏览器的顶行。

Working demo

window.onscroll = onScroll;

function onScroll() {
    var removeActiveClass = function (elements) {
        for (var i = 0; i < elements.length; ++i) {
            elements[i].classList.remove('active');
        }
    }
    var anchors = document.querySelectorAll('#menu-center a');
    var previousRefElement = null;
    for (var i = 0; i < anchors.length; ++i) {
        // Get the current element by the id from the anchor's href.
        var currentRefElement = document.getElementById(anchors[i].getAttribute('href').substring(1));
        var currentRefElementTop = currentRefElement.getBoundingClientRect().top;
        // Searching for the element whose top haven't left the top of the browser.
        if (currentRefElementTop <= 0) {
            //The browser's top line haven't reached the current element, so the previous element is the one we currently look at.
            previousRefElement = anchors[i];
            // Edge case for last element.
            if (i == anchors.length - 1) {
                removeActiveClass(anchors);
                anchors[i].classList.add("active");
            }
        } else {
            removeActiveClass(anchors);
            previousRefElement.classList.add("active");
            break;
        }
        
    }
}
body, html {
    margin: 0;
    padding: 0;
    height: 100%;
    width: 100%;
}
.menu {
    width: 100%;
    height: 75px;
    position: fixed;
    background-color:rgba(4, 180, 49, 0.6);
}
#menu-center {
    width: 980px;
    height: 75px;
    margin: 0 auto;
}
#menu-center ul {
    margin: 15px 0 0 0;
}
#menu-center ul li {
    list-style: none;
    margin: 0 30px 0 0;
    display: inline;
}
.active {
    font-size: 14px;
    color: #fff;
    text-decoration: none;
    line-height: 50px;
}
a {
    font-size: 14px;
    color: black;
    text-decoration: none;
    line-height: 50px;
}
.content {
    height: 100%;
    width: 100%;
}
#portfolio {background-color: grey;}
#about {background-color: blue;}
#contact {background-color: red;}
<div class="menu">
    <div id="menu-center">
        <ul>
            <li><a class="active" href="#home">Home</a></li>
            <li><a href="#portfolio">Portfolio</a></li>
            <li><a href="#about">About</a></li>
            <li><a href="#contact">Contact</a></li>
        </ul>
    </div>
</div>
<div id="home" class="content"></div>
<div id="portfolio" class="content"></div>
<div id="about" class="content"></div>
<div id="contact" class="content"></div>

#2


0  

This is not exactly menu type, it is the way how you can position objects by html.

这不是菜单类型,它是如何通过html定位对象的方式。

You can use position:Abosule property to achieve this effect: http://www.w3schools.com/css/tryit.asp?filename=trycss_position_fixed

您可以使用position:Abosule属性来实现此效果:http://www.w3schools.com/css/tryit.asp?filename = trycss_position_fixed

By this given divs are "flying" above the res of the page. In your case it could be a menu.

通过这个给定的div在页面的res之上“飞行”。在你的情况下,它可能是一个菜单。

EDIT:

To sync this you need to detect when given anchor is currently seen. It can be done by jQuery, this is sample draft of code, should explain clue of solution:

要同步这个,您需要检测当前是否看到给定锚点。它可以通过jQuery来完成,这是代码示例草案,应该解释解决方案的线索:

// list of header on page
var positions = [
    $("#anchor1").offset().top,
    $("#anchor2").offset().top,
    $("#anchor3").offset().top,
];
var menu_objects= [
    "#menu1",
    "#menu2",
    "#menu3"
];
var $w = $(window).scroll(function(){

// clear old
for(var v in menu_objects)
    $(v).css({"color","white"});

for(var i=positions.length-1;i>=0;i--)
{
    if(positions[i]>=$w.scrollTop())
    {
        $(menu_objects[i]).css({"color","red"});
        break;
    }
}
});