在Angular JS中,有没有一种方法可以在不使用scope.watch的情况下监视DOM的更改?

时间:2019-12-06 17:34:14

标签: angularjs angularjs-directive angularjs-scope angular-ui-bootstrap

我正在尝试创建一个angularjs引导手风琴,当打开时将其滚动到顶部。

这些解决方案接近我想做的事情:

但是,它们使用超时或示波器监视。除非绝对必要,否则我想避免使用它们。

是否有一种无需使用$watchsetTimeout的方法即可实现?

这里是我想做的事,使用$ watch:https://plnkr.co/edit/XQpUdrdjqaCGom4L9yIJ

app.directive( 'scrollTop', scrollTop );

function scrollTop() {
    return {
        restrict: 'A',
        link: link
    };
}

function link( scope, element ) {
    scope.collapsing = false;
    var jqElement = $( element) ;
    scope.$watch( function() {
        return jqElement.find( '.panel-collapse' ).hasClass( 'collapsing' );
    }, function( status ) {
        if ( scope.collapsing && !status ) {
            if ( jqElement.hasClass( 'panel-open' ) ) {
                $( 'html,body' ).animate({
                    scrollTop: jqElement.offset().top - 30
                }, 500 );
            }
        }
        scope.collapsing = status;
    } );
}

2 个答案:

答案 0 :(得分:0)

指令可以简化为: 1

app.directive( 'scrollTop', function scrollTop($timeout) {
    return {
        restrict: 'A',
        link: postLink
    };
    function postLink(scope, elem, attrs) {
        elem.on("click", function(e) {
          if (scope.status.isOpen) {
            $timeout(function() {
              $( 'html,body' ).animate({
                scrollTop: elem.offset().top - 30
              }, 500 );
            });
          }
        });
    }
})
<uib-accordion>
  <div heading="Section Title" is-open="status.isOpen"
       ng-repeat="section in vm.sections"
       scroll-top
       uib-accordion-group>
    <uib-accordion-heading>
      <div ng-class="{isOpen: vm.isOpen}">
        <h3>{{section.sectionTitle}}</h3>
        <p>{{section.sectionSubHeader}}</p>
      </div>
    </uib-accordion-heading>
    <div class="clearfix">
      <b>Index+1={{$index+1}}</b> 
      Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor
      in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
    </div>
  </div>
</uib-accordion>

$timeout是必需的,因为浏览器需要先使用新打开和关闭的元素呈现DOM,然后才能计算正确的滚动偏移量。

DEMO on PLNKR

答案 1 :(得分:0)

我找到了一种从控制器执行此操作的方法。

我添加了一个在ng-click上触发的函数,用于报告手风琴的is-open状态。

使用组件生命周期挂钩$doCheck,我可以观察到vm.isOpen状态的变化。 $doCheck在每个摘要周期的结尾运行,因此我不需要设置$scope.watch$timeOut

$doCheck与问题中的指令基本运行相同的代码

app.controller('homeController', function($state, $element, sections, $transitions) {
  var vm = this;

  vm.$onInit = function() {
    vm.sections = sections.getSections();
  };

  function updateOpenStatus() {
    vm.collapsing = false;
    vm.isOpen = vm.sections.some(function(item) {
      return item.isOpen;
    });
  }

  vm.$doCheck = function() {
    if (vm.isOpen) {
      var elem = $element.find('.panel-collapse');
      var status = elem.hasClass('collapsing');
      if (vm.collapsing && !status) {
        var parentElem = elem.closest('.panel-open');
        if (elem.parent().hasClass('panel-open')) {
          $('html,body')
            .stop()
            .animate({
              scrollTop: parentElem.offset().top - 52
            }, 'fast');
        }
      }
      vm.collapsing = status;
    }
  };
});

我更新了uib-accordion以便在控制器中调用函数

<uib-accordion>
  <div heading="Section Title" is-open="section.isOpen" ng-repeat="section in vm.sections" scroll-top uib-accordion-group>
    <uib-accordion-heading>
      <div ng-class="{isOpen: section.isOpen}" ng-click="vm.toggleOpen()">
        <h3>{{section.sectionTitle}}</h3>
      </div>
    </uib-accordion-heading>
    <div class="clearfix">
      Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor
      in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
    </div>
  </div>
</uib-accordion>

更新的Plnkr:https://plnkr.co/edit/5EqDfmVOa0hzFfaQqdI0?p=preview