在RTL模式下获得可滚动DIV的视图的更好方法
Better way to get the viewport of a scrollable DIV in RTL mode?
我需要一个更好的方法来计算可滚动div的视口。
在正常情况下,我会使用以下属性:(scrollLeft, scrollTop, clientWidth, clienttheight)
使用这些数字,我可以准确地确定一个可滚动的DOM元素的视口的哪一部分是当前可见的,我使用这个信息异步加载的东西,当滚动到水平或垂直的内容时,对用户可见的需求。当DIV的内容非常大时,这将避免由于加载太多DOM元素而导致浏览器崩溃的尴尬bug。
我的组件已经工作了一段时间了,现在没有问题,这个版本我们正在引入RTL支持。现在,由于浏览器的不一致,一切都被打乱了。
为了演示,我创建了一个简单的示例,它将输出JSFiddle中可滚动元素的scrollLeft属性。
这个简单的可滚动元素的scrollLeft属性的行为在不同浏览器之间是不一致的。我试过的3个主要浏览器都有不同的表现。
- FF-latest scrollLeft从0开始,当向左滚动时变为负值
- ie9 scrollLeft从0开始,当向左滚动时变为正
- Chrome-latest scrollLeft从一个更高的数字开始,当向左滚动时变为0
我想避免像if(ie){...}else if(ff){...}else if (chrome){...}
这样的代码,这将是可怕的,并且在浏览器改变行为的情况下无法长期维护。
有没有更好的方法来精确地找出DIV的哪一部分是当前可见的?
也许有一些其他可靠的DOM属性,而不是scrollLeft?
也许有一个jQuery插件会为我做,记住它是哪个浏览器版本?
也许有一种技术,我可以用它来找出哪些情况下,它是在运行时不依赖于一些不可靠的浏览器检测(即userAgent)
小提琴示例(代码复制如下)
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();
这是一个不使用浏览器检测的jQuery插件:https://github.com/othree/jquery.rtl-scroll-type
使用这个插件你可以用你自己的可预测的版本替换jQuery的scrollLeft
函数,像这样:
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;
};
我没有包括设置滚动偏移量的代码,但是您可以理解。
小提琴在这里:http://jsfiddle.net/scA63/
你可以试试:-
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));
}
});
问题:(例滚动宽度= 100)
Chrome - Most Right: 100 Most Left: 0.
IE- Most Right: 0 Most Left: 100.
Firefox -最右:0最左:-100.
解决方案# 1
正如@Lucas Trzesniewski所提到的。
你可以使用这个Jquery插件:
https://github.com/othree/jquery.rtl-scroll-type插件用于检测浏览器正在使用的类型。将结果赋值给jQuery的支持对象rtlScrollType。您将需要元素的滚动宽度来进行转换这三种类型的值
解决方案# 2
credit: jQuery.scrollLeft()当方向是rtl -不同的浏览器有不同的值
我知道你不想为每个浏览器单独包含浏览器检测。在这个例子中,只需要为Safari和Chrome添加2行额外的代码,它就像一个魅力!
修改了它,以便更好地为您演示。
$('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/左边的值在所有浏览器中应该是相同的,而右边的值是在所有浏览器中不同的旧值。(在Firefox, Safari, Chrome, IE9上测试)
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 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
供参考:Chrome 85(最终于2020年8月发布)修复了这个错误,并将行为与Firefox和Safari以及规范保持一致。
见https://www.chromestatus.com/feature/5759578031521792
是否有可用的特征检测?
是的,例如,使用这里提供的两张纸条中的一张(来自frac Wang):https://people.igalia.com/fwang/scrollable-elements-in-non-default-writing-modes/在这function scroll_coordinates_behavior_with_scrollIntoView() {
/* Append a RTL scrollable 1px square containing two 1px-wide descendants on
the same line, reveal each of them successively and compare their
scrollLeft coordinates. The scrollable square has 'position: fixed' so
that scrollIntoView() calls don't scroll the viewport. */
document.body.insertAdjacentHTML("beforeend", "<div style='direction: rtl;'
position: fixed; left: 0; top: 0; overflow: hidden; width: 1px; height: 1px;'>'
<div style='width: 2px; height: 1px;'><div style='display: inline-block;'
width: 1px;'></div><div style='display: inline-block; width: 1px;'></div>'
3</div></div>");
var scroller = document.body.lastElementChild;
scroller.firstElementChild.children[0].scrollIntoView();
var right = scroller.scrollLeft;
scroller.firstElementChild.children[1].scrollIntoView();
var left = scroller.scrollLeft;
/* Per the CSSOM specification, the standard behavior is:
- decreasing coordinates when scrolling leftward.
- nonpositive coordinates for scroller with leftward overflow. */
var result = { "decreasing": left < right, "nonpositive": left < 0 };
document.body.removeChild(scroller);
return result;
}
或
function scroll_coordinates_behavior_by_setting_nonpositive_scrollLeft() {
/* Append a RTL scrollable 1px square containing a 2px-wide child and check
the initial scrollLeft and whether it's possible to set a negative one.*/
document.body.insertAdjacentHTML("beforeend", "<div style='direction: rtl;'
position: absolute; left: 0; top: 0; overflow: hidden; width: 1px;'
height: 1px;'><div style='width: 2px; height: 1px;'></div></div>");
var scroller = document.body.lastElementChild;
var initially_positive = scroller.scrollLeft > 0;
scroller.scrollLeft = -1;
var has_negative = scroller.scrollLeft < 0;
/* Per the CSSOM specification, the standard behavio999r is:
- decreasing coordinates when scrolling leftward.
- nonpositive coordinates for scroller with leftward overflow. */
var result = { "decreasing": has_negative ||
initially_positive, "nonpositive": has_negative };
document.body.removeChild(scroller);
return result;
}
- 添加文字和评论功能更新Div
- 如何使用javascript从主svg对象动态创建svg视图框
- 正在使用$location.path(.)路由ng视图
- angular.js没有'无法在PhoneGap中处理视图标记
- 如何包含特定于每个视图angularjs的javascript文件
- 在Rails中更新Div,而不更改更新请求后的视图
- 从移动视图中删除 Div
- 如何使用JQuery.Load访问Div中加载URL的UL“id”,“name”等,以设置JQuery树视图
- Div 使用滚动视图插件进行整理
- 在网格视图中的页面上弹出 Div 位置
- 使用javascript数组和单选按钮切换DIV的视图
- 当Div进入视图时,pushState
- 如果仍在视图中,则用于更改DIV偏移的JQuery算法
- Dojo Div在刷新页面后切换视图
- 骨干视图中的Div id持久化
- 在RTL模式下获得可滚动DIV的视图的更好方法
- 树视图在右侧打开它各自的Div
- 将部分视图加载到 Div AngularJS 中
- Javascript 数组单选按钮切换 DIV 的视图
- 如何只运行一个脚本,如果DIV是在视图