scrollIntoView 实现「建议收藏」

scrollIntoView 实现「建议收藏」1.应用场景: 相信大家都曾经遇到过要将屏幕的某一部分滚到到用户视窗里,例如聊天信息的自动滚屏等,这个有不少解决方案: 1.聊天面板的scrolltop=scrollheight2.消息最后加一个element,然后element.scrollIntoView但是如果想要任一容器中间的一个元素,滚到该容器的视窗显示部分…

大家好,又见面了,我是你们的朋友全栈君。

1.应用场景:

 

相信大家都曾经遇到过要将屏幕的某一部分滚到到用户视窗里,例如 聊天信息的自动滚屏 等,这个有不少解决方案:

 

1.聊天面板的scrolltop=scrollheight

2.消息最后加一个element,然后element.scrollIntoView


但是如果想要 任一容器中间的一个元素,滚到该容器的视窗显示部分 应该应用不广泛。


2.Extjs API:


extjs的核心 Element 包含了这一方法。


scrollIntoView[Mixed container ] , [Boolean hscroll ]  ) : Ext.Element

Scrolls this element into view within the passed container.
Scrolls this element into view within the passed container.

Parameters:
  • container : Mixed
    (optional) The container element to scroll (defaults to document.body). Should be a string (id), dom node, or Ext.Element.
  • hscroll : Boolean
    (optional) False to disable horizontal scroll (defaults to true)

Returns:

  • Ext.Element
    this


这个函数的效果就是将父区域内的子区域显示到父区域的视窗部分。

 

 

3.Extjs 实现详解:

 

 

子区域在父区域内大概分为三种关系:


1.子区域在父区域视窗底部,且子区域没有父区域视窗高,

scrollIntoView 实现「建议收藏」


2.子区域比父区域视窗高

scrollIntoView 实现「建议收藏」

 

3.子区域顶部在父区域视窗顶部以上,且子区域没有父区域视窗高

scrollIntoView 实现「建议收藏」

 

 

对于这三种情况,要分别处理,其中 二和三最终的处理方式一样的。

 

那么现在就可以分析extjs处理滚动高度部分的代码了:

 

scrollIntoView : function(container, hscroll){
        var c = Ext.getDom(container) || Ext.getBody().dom;
        var el = this.dom;
				
//子区域渲染后在屏幕上和父区域视窗的左边距和上边距,
//为负时,表示子区域有上部分在父区域视窗上面,如第三种情况
        var o = this.getOffsetsTo(c),
        
        //分别计算子区域相对父区域结点的坐标(不是父区域视窗)
            l = o[0] + c.scrollLeft,
            t = o[1] + c.scrollTop,
            b = t+el.offsetHeight,
            r = l+el.offsetWidth;

        var ch = c.clientHeight;
        var ct = parseInt(c.scrollTop, 10);
        var cl = parseInt(c.scrollLeft, 10);
        var cb = ct + ch;
        var cr = cl + c.clientWidth;


        //二三种情况,如果子区域比父区域视窗还高或者,
        //区域有上部分在父区域视窗上面,就把子区域顶部和父区域视窗顶部对齐
        //注意:子区域比父区域视窗还高,优先显示子区域顶部部分内容,比较合理。
        if(el.offsetHeight > ch || t < ct){
        
        	c.scrollTop = t;
        	
        	
        }else 
        
        //第一种情况,如果子区域在父区域视窗下面,或者有下部分在父区域视窗下面,
        //且子区域没有父区域视窗高,就把子区域底部和父区域视窗底部对齐
        if(b > cb){
            c.scrollTop = b-ch;
        }
}

宽度调整同理。

 

 

4.总结:

 

scrollIntoView 实现「建议收藏」

 

关键为初始根据scrollTop以及offsetTo得到元素和容器内容上边界的固定差值,之后只需赋值 scrollTop,在容器内容条上滑动 容器显示区域 到一定位置使得元素和容器的上(下)边对其即可。

 

PS1: scrollIntoView 原生解释

 


将一个元素滚动到视窗,如果参数为true则元素会被滚动到视窗的顶部,否则他会被滚动到视窗底部,默认为true。


当该方法被调用时,作用元素必须引起调用者的注意。


在读屏器中,可使得当前的播放位置重置到作用元素的开头。


在可视化的用户代理中,如果参数为false,用户代理必须滚动窗体使得元素的顶部和底部在当前视窗都可见,并且底部和视窗的底部对齐。如果当前视窗不能完全显示元素,或者元素参数被忽略则默认为true,那么用户代理应该将元素的顶部和视窗的顶部排列,如果当前页面可以完全显示在视窗中,那么用户代理不应该进行任何滚动。可视化用户代理应该同样进一步进行水平滚动使得该元素能够引起用户注意。


非可视化用户代理可以忽略调用参数,或者以合适的媒体特性来区别对待。

 

模拟原生 scrollView 的 kissy 实现

 

 

/**
         * Makes elem visible in the container
         * @refer http://www.w3.org/TR/2009/WD-html5-20090423/editing.html#scrollIntoView
         *        http://www.sencha.com/deploy/dev/docs/source/Element.scroll-more.html#scrollIntoView
         *        http://yiminghe.iteye.com/blog/390732
         */
        scrollIntoView: function(elem, container, top, hscroll) {
            if (!(elem = S.get(elem)) || !elem[OWNER_DOCUMENT]) return;

            container = S.get(container);
            hscroll = hscroll === undefined ? true : !!hscroll;
            top = top === undefined ? true : !!top;

            // default current window,use native for scrollIntoView(elem, top)
            if (!container || container === win) {
                // 注意:
                // 1. Opera 不支持 top 参数
                // 2. 当 container 已经在视窗中时,也会重新定位
                return elem.scrollIntoView(top);
            }
            //document 归一化到 window
            if (container.nodeType && container.nodeType == 9) {
                container = getWin(container);
            }
            //support iframe's win    
            var notWin = !('scrollTo' in container && container[DOCUMENT]),
                elemOffset = DOM.offset(elem),
                cl = notWin ? container.scrollLeft : DOM.scrollLeft(container),
                ct = notWin ? container.scrollTop : DOM.scrollTop(container),
                //import! viewport should has
                containerOffset = notWin ? DOM.offset(container) : {left:cl,top:ct},
                diff = {
                    left:elemOffset.left - containerOffset.left  ,
                    top:elemOffset.top - containerOffset.top
                },
                eh = elem.offsetHeight,
                ew = elem.offsetWidth,
                //left
                l = diff.left + cl,
                //top
                t = diff.top + ct,
                b = t + elem.offsetHeight,
                r = l + elem.offsetWidth,
                ch = notWin ? container.clientHeight : DOM.viewportHeight(container),
                cw = notWin ? container.clientWidth : DOM.viewportWidth(container),
                //container视窗下doc高度下限
                cb = ct + ch,
                //container视窗下doc右边限
                cr = cl + cw;
            //used if container is window
            var wl = 0,wt = 0;
            if (eh > ch || top) {
                if (notWin)
                    container.scrollTop = t;
                else
                    wt = t;
            } else {
                if (notWin)
                    container.scrollTop = t - (ch - eh);
                else
                    wt = t - (ch - eh);
            }

            if (ew > cw || l < cl) {
                if (notWin)
                    container.scrollLeft = l;
                else
                    wl = l;
            } else if (r > cr) {
                if (notWin)
                    container.scrollLeft = l;
                else
                    wl = l;
            }
            if (!notWin && (wl || wt)) {
                container.scrollTo(wl, wt);
            }

        }
    });

 


PS2:原生使用注意


使用原生的 element.scrollIntoView() 时,会同时使 element 所在容器也会进行 scrollIntoView 操作,特别当 elment 为处于 iframe 中的一个元素,则当调用 element.scrollIntoView() ,不但使得 iframe 内的窗口滚动到 element 所在处,同时也会使主窗口滚动到 iframe 处,某些场景这也许不是我们所期望的(编辑器工具栏操作编辑区iframe内元素),这时模拟实现的scrollIntoView就有用武之地了,调用:

new Node(element).scrollIntoView(iframe.contentWindow);

 
使得只滚动 iframe 内的窗口,而保持主窗口不变。


版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/148687.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 小米刷原生android系统下载地址,小米6刷原生安卓8.0下载|小米6刷原生安卓p 免费版_附教程_最火软件站…

    小米刷原生android系统下载地址,小米6刷原生安卓8.0下载|小米6刷原生安卓p 免费版_附教程_最火软件站…小米6刷原生安卓系统是一款专门为小米6手机整理的刷机包,利用这款工具可以帮助小米6手机用户将自己的手机系统升级为原生安卓8.0、9.0等,让手机使用更加的方便,需要的用户快来最火网站下载吧!小米6刷原生安卓8.0简介小米6刷安卓9.0文件是为小米6用户提供的刷最新的安卓系统所需的文件,18年上线的安卓系统对于很多安卓粉丝来说还是很有吸引力的,如果你手上正好有一台小米6手机,可来下载这款文件来将自己…

    2022年6月19日
    34
  • 全网最全Linux 运行jar包的几种方式[通俗易懂]

    全网最全Linux 运行jar包的几种方式[通俗易懂]一、Linux运行jar包的几种方式方式一:java-jarxxx.jar最常用的启动jar包命令,特点:当前ssh窗口被锁定,可按CTRL+C打断程序运行,或直接关闭窗口,程序退出方式二:java-jarxxx.jar&&代表在后台运行,ctrl+c后程序也会继续运行方式三:nohupjava-jarxxx.jar&nohup即nohangup不挂断,关闭SSH客户端连接,程序不会中止运行缺省情况下该作业的所

    2022年10月5日
    3
  • docker下载安装教程_docker镜像存储位置

    docker下载安装教程_docker镜像存储位置前言Docker提供轻量的虚拟化,你能够从Docker获得一个额外抽象层,你能够在单台机器上运行多个Docker微容器,而每个微容器里都有一个微服务或独立应用,例如你可以将Tomcat运行在一个D

    2022年7月30日
    11
  • qt多线程编程实例_lgbt

    qt多线程编程实例_lgbt一、线程基础1、GUI线程与工作线程每个程序启动后拥有的第一个线程称为主线程,即GUI线程。QT中所有的组件类和几个相关的类只能工作在GUI线程,不能工作在次线程,次线程即工作线程,主要负责处理GUI线程卸下的工作。2、数据的同步访问每个线程都有自己的栈,因此每个线程都要自己的调用历史和本地变量。线程共享相同的地址空间。二、QT多线程简介QT通过三种形式提供了对线程…

    2022年5月3日
    51
  • linux系统如何修改用户名_两种方案对比报告

    linux系统如何修改用户名_两种方案对比报告在安装系统的时候,经常会无意识的随便起个用户名,后面如果发现该用户名不好或因为环境需要须重起个用户名,经过查找资料和亲自测试发现有两种方案可选:手动修改和使用usermod等命令自动修改。方案一:手动修改各个关联用户文件以root身份登录系统文件的修改需要root权限,这里不管是原root用户登录还是普通用户切换到root下都可以,只要有修改权限就行。修改/etc/passwd这个文件中的用户名部

    2022年9月13日
    2
  • idea主题下载导入工具

    idea主题下载导入工具http://www.soft-hub.cn/

    2022年5月31日
    41

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号