Better way to get the viewport of a scrollable DIV in RTL mode?

不想你离开。 提交于 2020-01-03 08:06:55

问题


I need a better way to calculate a scrollable div's viewport.

Under normal circumstances, I would use the following attributes: (scrollLeft, scrollTop, clientWidth, clientHeight)

Using these numbers I can accurately determine which part of a scrollable DOM element's viewport is currently visible, I use this information to asynchronously load things that are visible to the user on demand when scrolling to the content horizontally or vertically. When the content of the DIV is massive, this will avoid an embarassing browser crashing bug because of too many DOM elements being loaded.

My component has worked for a while now with no issues, this build we are introducing RTL support. Now everything is thrown off because of browser inconsistencies.

To demonstrate, I have created a simple example which will output the scrollLeft attribute of a scrollable element in a JSFiddle.

The behavior of the scrollLeft attribute on this simple scrollable element is not consistent from one browser to the next. The 3 major browsers I've tried all behaved differently.

  1. FF-latest scrollLeft starts at 0 and goes negative when scrolling left
  2. IE 9 scrollLeft starts at 0 and goes positive when scrolling left
  3. Chrome-latest scrollLeft starts at a higher number and goes to 0 when scrolling left

I want to avoid having code like if(ie){...}else if(ff){...}else if (chrome){...} that would be horrible, and not maintainable in the long run in case browsers change behavior.

Is there a better way to figure out precisely which part of the DIV is currently visible?

Perhaps there is some other reliable DOM attribute other than scrollLeft?

Maybe there is a jQuery plugin that will do it for me, keeping in mind which browser version it is?

Maybe there is a technique I can use to figure out which of the cases it is at runtime without relying on some unreliable browser detection (i.e. userAgent)

Fiddle Example (code copied below)

HTML

<div id="box"><div id="content">scroll me</div></div>
<div id="output">Scroll Left: <span id="scrollLeft"></span></div>

CSS

#box {
    width: 100px; height: 100px;
    overflow: auto;
    direction: rtl;
}
#content { width: 300px; height: 300px; }

JS

function updateScroll() {
    $('#scrollLeft').text(box.scrollLeft());
}
var box = $('#box').scroll(updateScroll);
updateScroll();

回答1:


Here's a jQuery plugin which does not use browser detection: https://github.com/othree/jquery.rtl-scroll-type

Using this plugin you could replace jQuery's scrollLeft function with your own predictable version, like this:

var origScrollLeft = jQuery.fn.scrollLeft;
jQuery.fn.scrollLeft = function(i) {
    var value = origScrollLeft.apply(this, arguments);

    if (i === undefined) {
        switch(jQuery.support.rtlScrollType) {
            case "negative":
                return value + this[0].scrollWidth - this[0].clientWidth;
            case "reverse":
                return this[0].scrollWidth - value - this[0].clientWidth;
        }
    }

    return value;
};

I didn't include the code for setting the scroll offset, but you get the idea.

Here's the fiddle: http://jsfiddle.net/scA63/

Also, this lib may be of interest too.




回答2:


You can try this:-

         var initialScrollLeft = $('#box').scrollLeft(), negativeToZero, startFromZero;
            if(initialScrollLeft === 0){
                startFromZero = true; 
            } else if(initialScrollLeft < 0){
                negativeToZero = true;
            } 
            var box = $('#box').scroll(function(){
                if(startFromZero){
                    if(box.scrollLeft()>0){
                        $('#scrollLeft').text(- (box.scrollLeft()));
                    }else {
                        $('#scrollLeft').text(box.scrollLeft()); 
                    }
                } else if(negativeToZero){
                    $('#scrollLeft').text(box.scrollLeft()+(box[0].scrollWidth - box[0].clientWidth));  
                } else{
                    $('#scrollLeft').text(box.scrollLeft()-(box[0].scrollWidth - box[0].clientWidth));  
                }

            });



回答3:


Problem: (Ex. Scroll Width = 100)

Chrome - Most Right: 100 Most Left: 0.

IE- Most Right: 0 Most Left: 100.

Firefox - Most Right: 0 Most Left: -100.

Solution #1

As mentioned by @Lucas Trzesniewski.

You could use this Jquery plugin:

https://github.com/othree/jquery.rtl-scroll-type

The plugin is used to detect which type is the browser are using. Assign the result to jQuery's support object named 'rtlScrollType'. You will need the scrollWidth of the element to transform between these three types of value

Solution #2

Credits: jQuery.scrollLeft() when direction is rtl - different values in different browsers

I know you didn't want to include browser detection individually for each browser. With this example, only 2 extra lines of code are added for Safari and Chrome and it works like a charm!

Modified it to demonstrate it better for you.

$('div.Container').scroll(function () {
    st = $("div.Container").scrollLeft() + ' ' + GetScrollLeft($("div.Container"));
    $('#scrollLeft').html(st);
});

function GetScrollLeft(elem) {
    var scrollLeft = elem.scrollLeft();
    if ($("body").css("direction").toLowerCase() == "rtl") {
        // Absolute value - gets IE and FF to return the same values
        var scrollLeft = Math.abs(scrollLeft);

        // Get Chrome and Safari to return the same value as well
        if ($.browser.webkit) {
            scrollLeft = elem[0].scrollWidth - elem[0].clientWidth - scrollLeft;
        }
    }
    return scrollLeft;
}

JSFiddle:

http://jsfiddle.net/SSZRd/1/

The value on the left should be the same for all browser while the value on the right is the older value which is different on all browser. (Tested on Firefox, Safari, Chrome, IE9).



来源:https://stackoverflow.com/questions/24276619/better-way-to-get-the-viewport-of-a-scrollable-div-in-rtl-mode

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!