我正在尝试创建一个angularjs引导手风琴,当打开时将其滚动到顶部。
这些解决方案接近我想做的事情:
但是,它们使用超时或示波器监视。除非绝对必要,否则我想避免使用它们。
是否有一种无需使用$watch
或setTimeout
的方法即可实现?
这里是我想做的事,使用$ 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;
} );
}
答案 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,然后才能计算正确的滚动偏移量。
答案 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