>  기사  >  웹 프론트엔드  >  네이티브 js는 시뮬레이션된 스크롤 bar_javascript 기술을 구현합니다.

네이티브 js는 시뮬레이션된 스크롤 bar_javascript 기술을 구현합니다.

WBOY
WBOY원래의
2016-05-16 15:55:022040검색

페이지에 스크롤 막대가 많아 서로 중첩되어 보기 흉한 경우 스크롤 막대를 시뮬레이션하고 스크롤 막대에 보기 좋은 스타일을 부여하여 페이지를 아름답게 만듭니다.

스크롤 막대를 시뮬레이션하려면 jquery 플러그인을 사용한 다음 몇 줄의 코드를 작성하는 경우가 많습니다. 하지만 mvvm의 급속한 발전으로 인해 jquery를 사용하기에는 너무 게을러질 때가 많습니다. 이것이 이 글의 동기입니다. 이 기사에서는 jquery에 의존하지 않고 mvvm(avalon) API에만 의존하는 간단한 코드를 사용하려고 노력합니다. 간단한 스크롤 막대를 완성합니다.

요구사항:

1. 마우스 휠을 사용하면 스크롤바가 작동하고 인터페이스가 스크롤됩니다

2. 마우스로 스크롤바를 드래그하여 인터페이스를 스크롤할 수 있습니다

3. 페이지 크기가 조정되면 스크롤 막대가 페이지 크기에 따라 변경되며 계속 작동할 수 있습니다.

효과:

물론 이 컴포넌트는 드래그를 기반으로 하기 때문에 다시 작성하고 싶지 않아서 UI 프레임워크의 드래그를 변경해야 합니다. 여기서 변경한 것은 easy js ui의 드래그 컴포넌트입니다. 댓글이 많고 코드가 간결하기 때문에 Easy js를 사용합니다.

이 글에서는 easy js ui의 drag 컴포넌트에 있는 해당 메소드를 avalon api의 메소드로 대체하고 프로토타입에서 중복되는 코드와 메소드를 삭제합니다

define('drag',['avalon-min'],function(avalon){
  function getBoundary(container, target) {
    var borderTopWidth = 0, borderRightWidth = 0, borderBottomWidth = 0, borderLeftWidth = 0, cOffset = avalon(container)
    .offset(), cOffsetTop = cOffset.top, cOffsetLeft = cOffset.left, tOffset = avalon(target)
    .offset();
    borderTopWidth = parseFloat(avalon.css(container,'borderTopWidth'));
    borderRightWidth = parseFloat(avalon.css(container,'borderRightWidth'));
    borderBottomWidth = parseFloat(avalon.css(container,'borderBottomWidth'));
    borderLeftWidth = parseFloat(avalon.css(container,'borderLeftWidth'));
    cOffsetTop = cOffsetTop - tOffset.top + parseFloat(avalon(target).css('top'));
    cOffsetLeft = cOffsetLeft - tOffset.left + parseFloat(avalon(target).css('left'));
    return {
      top : cOffsetTop + borderTopWidth,
      right : cOffsetLeft + avalon(container).outerWidth() - avalon(target).outerWidth()
      - borderRightWidth,
      left : cOffsetLeft + borderLeftWidth,
      bottom : cOffsetTop + avalon(container).outerHeight() - avalon(target).outerHeight()
      - borderBottomWidth
    };
  }
  var drag = function(target, options) {
    var defaults = {
      axis:null,
      container:null,
      handle:null,
      ondragmove:null
    };
    var o =avalon.mix(defaults,options),
    doc = target.ownerDocument,
    win = doc.defaultView || doc.parentWindow,
    originHandle=target,
    isIE =!-[1,],
    handle = isIE ? target :doc,
    container = o.container ?o.container: null, 
    count = 0,
    drag = this,    
    axis = o.axis,    
    isMove = false, 
    boundary, zIndex, originalX, originalY,
    clearSelect = 'getSelection' in win ? function(){
      win.getSelection().removeAllRanges();
    } : function(){
      try{
        doc.selection.empty();
      }
      catch( e ){};
    },
    down = function( e ){
      o.isDown = true;        
      var newTarget = target,
      left, top, offset;
      o.width = avalon(target).outerWidth();
      o.height = avalon(target).outerHeight();
      o.handle = handle;
      left = avalon(newTarget).css( 'left' );
      top = avalon(newTarget).css( 'top' );     
      offset = avalon(newTarget).offset();
      drag.left = left = parseInt( left );
      drag.top = top = parseInt( top );
      drag.offsetLeft = offset.left;
      drag.offsetTop = offset.top;
      originalX = e.pageX - left;
      originalY = e.pageY - top; 
      if( (!boundary && container)){
        boundary = getBoundary(container, newTarget ); 
      } 
      if( axis ){
        if( axis === 'x' ){
          originalY = false;
        }
        else if( axis === 'y' ){
          originalX = false;
        }
      }
      if( isIE ){
        handle.setCapture();
      }
      avalon.bind(handle,'mousemove',move);
      avalon.bind(handle,'mouseup',up);
      if( isIE ){
        avalon.bind(handle,'losecapture',up);
      }
      e.stopPropagation();
      e.preventDefault();  
    },
    move = function( e ){
      if( !o.isDown ){
        return;
      }      
      count++;
      if( count % 2 === 0 ){
        return;
      }
      var currentX = e.pageX,
      currentY = e.pageY,
      style = target.style,
      x, y, left, right, top, bottom;
      clearSelect();
      isMove = true;
      if( originalX ){
        x = currentX - originalX;
        if( boundary ){
          left = boundary.left;
          right = boundary.right;
          x = x < left &#63; left : 
          x > right &#63; right :
          x;
        }  
        drag.left = x;
        drag.offsetLeft = currentX - e.offsetX;
        style.left = x + 'px';
      }
      if( originalY ){
        y = currentY - originalY;
        if( boundary ){
          top = boundary.top;
          bottom = boundary.bottom;
          y = y < top &#63; top : 
          y > bottom &#63; bottom :
          y;
        }  
        drag.top = y;
        drag.offsetTop = currentY - e.offsetY;
        style.top = y + 'px';
      }
      o.ondragmove.call(this,drag);
      e.stopPropagation();  
    },
    up = function( e ){
      o.isDown = false;
      if( isIE ){
        avalon.unbind(handle,'losecapture' );
      }
      avalon.unbind( handle,'mousemove');
      avalon.unbind( handle,'mouseup');
      if( isIE ){
        handle.releaseCapture();
      }
      e.stopPropagation();        
    }; 
    avalon(originHandle).css( 'cursor', 'pointer' );
    avalon.bind( originHandle,'mousedown', down );
    drag.refresh=function(){
      boundary=getBoundary(container,target);
    };  
  };
  return drag;
});

또한 마지막으로 노출된 드래그에 새로 고침() 메서드가 추가되어 크기 조정 중에 스크롤 막대의 드래그 가능 범위를 업데이트하는 데 사용됩니다. 이 메서드는 스크롤바의 업데이트 보기에서 사용됩니다.

    drag.refresh=function(){
      boundary=getBoundary(container,target);
    }; 

또한 스크롤바 드래그 과정에서 외부에서 듣기 기능을 추가할 수 있도록 후크를 추가합니다. 드래그 시 듣기 기능이 실행되고 드래그 매개변수가 전달됩니다.

o.ondragmove.call(this,drag);

그럼 scrollbar.js

define('scrollbar',['avalon-min','drag'],function(avalon,drag){
  function scrollbar(wrap,scrollbar,height_per_scroll){//容器,滚动条,每次滚轮移动的距离
    this.scroll_height=0;//滚动条高度
    this.dragger=null;//drag组件实例
    wrap.scrollTop=0;
    //容器的位置要减去浏览器最外面的默认滚动条垂直方向位置
    var self=this,wrap_top=avalon(wrap).offset().top-avalon(document).scrollTop();
    function ondragmove(drag){//drag组件拖动时的监听函数,更新容器视图
      wrap.scrollTop=(parseFloat(scrollbar.style.top)-wrap_top)*
      (wrap.scrollHeight -wrap.clientHeight)/(wrap.clientHeight-self.scroll_height);
    };
    function setScrollPosition(o) {//更新滚动条位置
      scrollbar.style.top =o.scrollTop*wrap.clientHeight/wrap.scrollHeight+wrap_top+ 'px';
    }
    function inti_events(){
      avalon.bind(wrap,'mousewheel',function(e){
        if(e.wheelDelta < 0)
          wrap.scrollTop+=height_per_scroll;
        else
          wrap.scrollTop-=height_per_scroll;
        setScrollPosition(wrap);
        e.preventDefault(); 
      });
      self.dragger=new drag(scrollbar,{container:wrap,axis:'y',ondragmove:ondragmove});
      window.onresize=function(){
        self.refresh_views();
        self.dragger.refresh();
      };
    }
    this.refresh_views=function(){//更新组件所有部分视图,并暴露供外部调用
      //容器高度这里设置成浏览器可视部分-容器垂直方向位置,没有考虑容器有border,padding,margin.可根据相应场景修改
      wrap.style.height=document.documentElement.clientHeight-wrap_top+'px';
      self.scroll_height=wrap.clientHeight*wrap.clientHeight/wrap.scrollHeight;
      //容器高度等于滚动条高度,隐藏滚动条
      if(self.scroll_height==wrap.clientHeight)
        scrollbar.style.display='none';
      else
        scrollbar.style.display='block';
      scrollbar.style.height=self.scroll_height+'px';
      setScrollPosition(wrap);
    }
    function init(){
      self.refresh_views();
      inti_events();
    }
    init();
  }
  return scrollbar;
});

크기 조정 중에 스크롤 막대의 드래그 가능 범위를 업데이트하기 위해 드래그 구성요소의 새로 고침 메소드가 호출되는 것을 볼 수 있습니다. 새로 고침_views() 메서드는 뷰를 수동으로 업데이트해야 하는 외부 상황을 처리하기 위해 여기에 노출됩니다. 예를 들어 채팅 그룹의 축소 및 확장이 있습니다.

이렇게 하면 간단한 스크롤바가 완성됩니다. 코드는 매우 간단하며 문제가 발생하여 버그를 수정하거나 사용자 정의해야 하는 경우 쉽습니다.

위 내용은 이 글의 전체 내용입니다. 모두 마음에 드셨으면 좋겠습니다.

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.