哪里是更新从$scope函数调用的dom的方法的最佳位置



我有一个表单,其中的部分在用户与之交互时会自动滚动和排列。我希望在指令中定义所有逻辑,但目前还不知道如何从控制器中获取一些DOM操作逻辑。大多数函数都可以附加到滚动、点击或焦点事件上,但如果我的控制器中没有DOM逻辑,我如何将函数附加到我的作用域以触发一些DOM操作?

我目前拥有的是

$scope.scrollToNextSection = function(section){
//DOM manipulation logic to scroll to next section.
}

我有有效吗

directiveDOMObject.scrollToNextSection = function(section){
//DOM manipulation logic to scroll to next section.
}

然后用从我的控制器上调用它

$scope.scrollToNextSection = function(section){
directiveDOMObject.scrollToNextSection(section);
}

把一个函数附加到像这样的DOM对象上,这样我所有的DOM操作都可以包含在指令中吗?是否存在用于触发控制器指令中定义的DOM操作逻辑的标准模式?

HTML使用名称锚来处理页面内的滚动。<a name="sectionX"><a href="#sectionX">如果你使用路由器,它们在SPA中会被大量(错误)使用。

作用域/控制器不知道dom,不能/不应该更改它。常见问题解答说:

DOM操作

停止尝试使用jQuery修改控制器中的DOM。真正地这包括添加元素、删除元素、检索它们内容,显示和隐藏它们。使用内置指令,或写入在必要时,您可以自己操作DOM。请参阅以下关于复制功能。

有人编写了ngScrollTo指令,该指令将逻辑保持在view+指令中。我还没有试过,但看起来还是不错的。

另请参阅Angularjs中的锚链接?寻找替代解决方案。

像这样将函数附加到DOM对象,这样我的所有DOM操作都可以包含在指令中

这里的简短回答是否定的,不是真的。如果控制器有业务逻辑,那么它就不应该关心DOM中发生的事情。

是否有标准模式用于触发控制器指令中定义的DOM操作逻辑?

不确定它们是否是标准的,但它们有几种方法。它们的共同主题是,直接或通过服务处理业务逻辑的控制器实际上并不调用指令,也不知道DOM/视图中发生了什么。它只是以一种或另一种形式提供"钩子",因此指令可以做出适当的反应。

据我所知,

  1. 对作用域上变量的变化做出反应。所以你可以有一个变量,比如state

    <div scroll-listen-to="state"> .... </div>
    

    和一个指令scrollListenTo,具有如下范围+链接功能:

    scope: {
    scrollListenTo: '='
    },
    link: function postLink(scope, iElement, iAttrs) {
    scope.$watch('scrollListenTo', function(newValue, oldValue) {
    // Do something, maybe with scrolling?
    });
    }
    
  2. 对来自控制器的事件$broadcast作出反应。这将事件发送到子作用域(因此发送作用域内的指令中的作用域)。此事件的名称也可以进行配置。因此,例如

    <div ng-controller="MyController">
    <input scroller-event="MyController::stateChanged" />
    </div>
    

    然后在MyController中,在适当的点:

    $scope.$broadcast('MyController::stateChanged', 'someData');
    

    在指令中:

    scope: {
    'eventName': '@scrollerEvent'
    },
    link: function postLink(scope, iElement, iAttrs) {
    scope.$on(scope.eventName, function(e, data) {
    // Do something the data
    });
    }
    
  3. 对来自控制器的事件$emit作出反应。这与$broadcast非常相似,但事件是通过层次结构向上发出的。您可以"包装"几个控制器,然后它们可以将事件发送到包装它们的指令。

    <div scroller-event="MyController::stateChanged">
    <div ng-controller="MyController">
    </div> 
    <div ng-controller="MyController">
    </div> 
    </div>
    

    然后在MyController 中

    $scope.$emit('MyController::stateChanged', 'someData');
    

    在这种情况下,您可能不应该在指令中使用scope参数,因为这会创建一个孤立的范围,而在这种情况中,这可能是不需要的。该指令可能有类似的内容

    link: function postLink(scope, iElement, iAttrs) {
    var eventName = iAttrs.scrollerEvent;
    scope.$on(eventName, function(e, data) {
    // Do something with the data, like scrolling.
    });
    }
    
  4. 你说你在使用一个表单。你可以创建一组交互的自定义指令,就像ngModel和ngForm交互一样。例如,你可以有:

    <div scroller-container>
    <input scroll-on-focus />
    <input scroll-on-focus />
    </div>
    

    然后在scrollOnFocus指令

    require: '^scrollerContainer',
    link: function(scope, iElement, iAttrs, scrollerContainerController) {
    iElement.on('focus', function() {
    scrollerContainerController.scrollTo(iElement);
    });
    }
    

    scollerContainer指令中,必须在其控制器上定义scrollTo

    controller: function() {
    this.scrollTo = function(element) {
    // Some code that scrolls the container so the element is visible
    };
    }
    

我意识到以上方法并不是特别针对你的滚动问题:它们更通用,老实说,我还不确定在任何特定情况下应该推荐哪种。

最新更新