开发者

Custom-Scroll three lists using one javascript

I have just come a little bit unstuck, I have a list which I populate with PHP, and a javascript file which creates the scrolling effect on the list so I can scroll up and down.

But I n开发者_StackOverfloweed three of these list boxes on the same page, and when I go to put another 2 of the lists in, they are not generated only the first is. I need to be able to have all three on the page. Any help with this would be fantastic!

Kind regards, Alistair

<div id="mContainer"> 
<div id="upArrow"></div> 
<div id="nContainer"> 
<ul id="listContainer"> 
<?php
connect();
$sql="SELECT drivers_id, firstname,image FROM drivers"; 
$result=mysql_query($sql); 
while ($row=mysql_fetch_array($result)){
echo "<li><a id='".$row['drivers_id']."' onclick='return showPic(this)' onfocus='this.hideFocus=true;' href='".$row['image']."'>".$row['firstname']."</a></li>";
}
?>
</ul> 
</div> 
<div id="downArrow"> 
</div> 
</div> 

**JAVASRIPT FILE BELOW**

window.onload=init;

var d=document;
var lContainer;             // object reference for the UL

var currentTop=0;           // the current Y position of the UL
var zInterval = null;       // animation thread interval
var direction;              // direction we're scrolling the UL. 0==up, 1==down
var startTop=0;             // the starting top of the UL
var scrollRate=8;           // initial rate of scrolling
var scrollTick=0;           // keeps track of long we've scrolled so we can    slow it down accordingly
var listHeight=60;          // the current height of the UL
var MAX_SCROLL_TICK=4;      // the maximum value of scrollTick before it's   reset
var MIN_LIST_HEIGHT=145;    // contracted height of the list
var REBOUND = 0;            // the value of scrollRate when we stop scrolling

function init() {
if(!d.getElementById)return; // bail out if this is an older browser

up=d.getElementById("upArrow");
down=d.getElementById("downArrow");

// apply onclick behaviors to the up arrow, down arrow and expansion control     elements
down.onmousedown=function(){
scrollObjects(0);
}
up.onmousedown=function(){
scrollObjects(1);
}

lContainer = d.getElementById("listContainer");

d.getElementById("nContainer").style.height=MIN_LIST_HEIGHT+"px";
}

function scrollObjects(dir) {
if(zInterval)return; // already scrolling.
if((!dir && currentTop<=-300) || (dir && currentTop==0))
return; // dont scroll up if we're at the top or down if at the bottom of the list

direction=dir;
zInterval=setInterval("animate()",20);
}

function animate() {
// increment or decrement currentTop based on direction
if(!direction) {
currentTop-=scrollRate;
} else {
currentTop+=scrollRate;
}
scrollTick++;   
if(scrollTick>=MAX_SCROLL_TICK) {
scrollRate--; // slow the scroll rate down for a little style
scrollTick=0;
}

lContainer.style.top=currentTop+"px";
if(scrollRate<=REBOUND) {
// scroll is finished. clear the interval and reset vars for the next    scroll
clearInterval(zInterval);
zInterval=null;
startTop=currentTop;
scrollTick=0;
scrollRate=8;
}
}


First, step up to jQuery. You'll eventually be immensely glad you did.

Next, don't use inline JavaScript! Ditto on the gladness part.

Here's the existing functionality in jQuery. The multi-list version is below the fold.

Add:

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js" type="text/javascript"></script>

(or load a version of the jQuery file to your own website.)

PHP:

<div id="mContainer">
  <div id="upArrow"></div>
  <div id="nContainer">
    <ul id="listContainer">
      <?php
        connect();
        $sql    = "SELECT drivers_id, firstname, image FROM drivers";
        $result = mysql_query($sql);
        while ($row=mysql_fetch_array($result) ) {
          echo "<li><a id='".$row['drivers_id']."' href='".$row['image']."'>".$row['firstname']."</a></li>";
        }
      ?>
    </ul>
  </div>
  <div id="downArrow"></div>
</div>

Additional CSS:

ul#listContainer li > a:focus {
    outline: none;
}

JavaScript:

$(document).ready (init);

//--- Global variables!
var lContainer;                 // object reference for the UL
var currentTop      = 0;        // the current Y position of the UL
var zInterval       = null;     // animation thread interval
var direction;                  // direction we're scrolling the UL. 0==up, 1==down
var startTop        = 0;        // the starting top of the UL
var scrollRate      = 8;        // initial rate of scrolling
var scrollTick      = 0;        // keeps track of long we've scrolled so we can    slow it down accordingly
var listHeight      = 60;       // the current height of the UL
var MAX_SCROLL_TICK = 4;        // the maximum value of scrollTick before it's   reset
var MIN_LIST_HEIGHT = 145;      // contracted height of the list
var REBOUND         = 0;        // the value of scrollRate when we stop scrolling

function init() {

    //-- Activate click and focus handlers on the li elements.
    $("ul#listContainer li > a").click ( function () { showPic (this); } )
                                // This next is IE only!  use CSS.
                                .focus ( function () { this.hideFocus=true; } );

    //-- Apply onclick behaviors to the up/down arrow and expansion control elements.
    $("#downArrow").mousedown ( function () { scrollObjects (0); } );
    $("#upArrow")  .mousedown ( function () { scrollObjects (1); } );

    lContainer = $("#listContainer");

    $("#nContainer").css ('height', MIN_LIST_HEIGHT + "px");
}

function scrollObjects(dir) {
    if (zInterval) return; // already scrolling.

    // dont scroll up if we're at the top or down if at the bottom of the list
    if ((!dir && currentTop <= -300) || (dir && currentTop == 0)) return;

    direction = dir;
    zInterval = setInterval (animate, 20);
}

function animate() {
    // increment or decrement currentTop based on direction
    if (!direction) {
        currentTop -= scrollRate;
    } else {
        currentTop += scrollRate;
    }
    scrollTick++;
    if (scrollTick >= MAX_SCROLL_TICK) {
        scrollRate--; // slow the scroll rate down for a little style
        scrollTick = 0;
    }

    lContainer.css ('top', currentTop + "px");
    if (scrollRate <= REBOUND) {
        // scroll is finished. clear the interval and reset vars for the next scroll
        clearInterval(zInterval);
        zInterval = null;
        startTop = currentTop;
        scrollTick = 0;
        scrollRate = 8;
    }
}


See this in action at jsFiddle.




Multi-List Version:

And now, with the awesome might of jQuery, we will:

  1. Enable multi-list operation.
  2. Reduce the dependence on "magic number" dimensions.
  3. Fix the apparent over-scroll problem.
  4. Make click-and-hold work the way the user expects.

First, change all the container and arrow ids to classes, like so:

<div class="mContainer">
    <div class="upArrow"></div>
    <div class="nContainer">
        <ul class="listContainer">
            ... ...
        </ul>
    </div>
    <div class="downArrow"></div>
</div>

Be sure to change the CSS to match, and don't use inline JS, that's handled below.

Then the JavaScript becomes:

$(document).ready (init);

function init() {

    //-- Activate click and focus handlers on the li elements.
    $("ul.listContainer li > a").click ( function () { showPic (this); } )
                                // This next is IE only!  use CSS.
                                .focus ( function () { this.hideFocus=true; } );

    //-- Initialize the scroll controls for every list in an mContainer.
    $("div.mContainer").each ( function (J) {
        var jNode   = $(this);
        jNode.data ('OurScrollObject', new ListScroll (jNode) );
    } );
}


/*--- ListScroll object.  This lets us (1) avoid global variables, and (2) keep each
    each list's data separate.
*/
function ListScroll (   contNode,           //--Required: jQuery wrapper of the container node.
                        INIT_SCROLL_RATE,   //--Optional: Initial rate of scrolling.
                        MAX_SCROLL_TICK,    //--Optional: The maximum value of scrollTick before it's reset.
                        MIN_LIST_HEIGHT,    //--Optional: Contracted height of the list.
                        REBOUND             //--Optional: The value of scrollRate when we stop scrolling.
                    )
{
    //--- Set constants to default values as needed.
    var INIT_SCROLL_RATE    = INIT_SCROLL_RATE  ||    8;
    var MAX_SCROLL_TICK     = MAX_SCROLL_TICK   ||    4;
    var MIN_LIST_HEIGHT     = MIN_LIST_HEIGHT   ||  145;
    var REBOUND             = REBOUND           ||    0;

    var listHeight          = contNode.find ("ul.listContainer").outerHeight (true);
    var scrollUpLimit       = MIN_LIST_HEIGHT - listHeight;

    //--- Init state variables.
    var currentTop          = 0;    // The current Y position of the UL.
    var startTop            = 0;    // The starting top of the UL.
    var scrollTick          = 0;    // Keeps track of how long we've scrolled so we can slow down accordingly.
    var scrollRate          = INIT_SCROLL_RATE;
    var bGoDown             = true; // Are we scrolling down?
    var zInterval           = null; // Tracks the animation, interval timer.
    var bStopRequested      = false;

    //--- Apply onclick behaviors to the up/down arrow elements.
    contNode.find (".upArrow, .downArrow").bind ("mousedown mouseup", scrollObjects);

    //--- Set the list's visible height.
    contNode.find (".nContainer").height (MIN_LIST_HEIGHT);


    function scrollObjects (zEvent) //-- zEvent is sent to event listeners automatically.
    {
        var bClickUpBtn = $(this).hasClass ('upArrow');
        var bMouseUp    = (zEvent.type == 'mouseup');

        /*--- Here are the states we want to act on:
            1) Were we already scrolling this list?
            2) Has the user signaled a desire to scroll (mousedown)?
            3) Has the user signaled to scroll scrolling (mouseup)?
            4) Has the user signaled to STOP RIGHT NOW, by clicking the opposite direction
               from the scroll direction?
        */
        if (bMouseUp  &&  ! zInterval) {
            //--- Already stopped before user released the mouse.
            return;
        }
        if (! bMouseUp  &&  zInterval  &&  bGoDown != bClickUpBtn) {
            //--- Already scrolling in the currently-commanded direction.
            return;
        }

        if (zInterval) {
            //--- Already scrolling
            if (bMouseUp) {
                //--- Soft stop commanded (can coast down).
                bStopRequested = true;
            }
            else {
                //--- User must clicked in the opposite direction of the current scroll.
                stopScroll ();
                return;
            }
        }
        else {
            //--- Not scrolling yet

            if (bBoundsCheck (bClickUpBtn) ) {
                //--- Don't scroll beyond the top or bottom of the list.
                return;
            }
            bGoDown     = ! bClickUpBtn;
            zInterval   = setInterval (scrollList, 20);
        }
    }


    function bBoundsCheck (bGoingUp) {
        /*--- Keeps the list from scrolling out of bounds.
            returns true if clipping (would have) occured.
        */
        if (bGoingUp    &&  currentTop <= scrollUpLimit) {
            currentTop  = scrollUpLimit;
            return true;
        }
        if ( ! bGoingUp &&  currentTop >= 0) {
            currentTop  = 0;
            return true;
        }
        return false;
    }


    function stopScroll () {
        //--- Resets the state variables and clears the animation timer.
        clearInterval (zInterval);
        zInterval       = null;
        startTop        = currentTop;
        scrollTick      = 0;
        scrollRate      = INIT_SCROLL_RATE;
        bStopRequested  = false;
    }


    function scrollList () {
        //--- Increment or decrement currentTop based on direction.
        if (bGoDown)    currentTop += scrollRate;
        else            currentTop -= scrollRate;

        if (bBoundsCheck ( ! bGoDown) ) {
            stopScroll ();
            contNode.find (".listContainer").css ('top', currentTop + "px");
            return;
        }
        contNode.find (".listContainer").css ('top', currentTop + "px");

        scrollTick++;
        //if (scrollTick >= MAX_SCROLL_TICK  ||  bStopRequested) { NO! Not ergo.
        if (bStopRequested) {
            scrollRate--; // slow the scroll rate down for a little style
            scrollTick = 0;
        }

        if (scrollRate <= REBOUND) {
            // Scroll is finished. clear the interval and reset vars for the next scroll.
            stopScroll ();
        }
    }
}


See it in action at jsFiddle.

Here's a handy jQuery Reference.


Update:
To change which arrow goes what direction, change this line:

var bClickUpBtn = $(this).hasClass ('upArrow');

To:

var bClickUpBtn = $(this).hasClass ('downArrow');  

See the Fiddle.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜