处理这个问题的最简洁的方法可能是编写一个指令来包装<input> 元素并添加延迟行为。这是我为相同目的编写的指令:
angular.module('MyModule')
.directive('easedInput', function($timeout) {
return {
restrict: 'E',
template: '<div><input class="{{externalClass}} my-eased-input" type="text" ng-model="currentInputValue" ng-change="update()" placeholder="{{placeholder}}"/></div>',
scope: {
value: '=',
timeout: '@',
placeholder: '@',
externalClass: '@class'
},
transclude: true,
link: function ($scope) {
$scope.timeout = parseInt($scope.timeout);
$scope.update = function () {
if ($scope.pendingPromise) { $timeout.cancel($scope.pendingPromise); }
$scope.pendingPromise = $timeout(function () {
$scope.value = $scope.currentInputValue;
}, $scope.timeout);
};
}
}
});
这个指令会像这样在你的 HTML 中被调用:
<eased-input value="myValue" timeout="500" placeholder="Please enter text..." />
剖析指令:
超时服务
该指令使用 Angular 的 $timeout 服务来处理计时:它是调用 setTimeout 的可注入、可模拟、惯用的替代方案。该服务被注入到指令构造函数中。
属性
该指令接受三个属性:value、timeout 和 placeholder。
这里的value 属性绑定到拥有封闭“上下文”的控制器范围内的变量。在这种情况下,它绑定到myValue,即绑定到负责此代码的任何控制器上的$scope.myValue。它具有双向绑定,由指令的scope 属性中的'=' 条目表示。这意味着当该指令更新value 时,更改会传播到拥有该指令的控制器;因此,$scope.myValue 将在指令内更改 value 时更改。
timeout 和 placeholder 属性具有单向绑定:指令从属性中读取它们的值,但不会改变它们。它们实际上是配置值。
HTML 模板
指令上的template 属性显示了一旦Angular 编译并链接它就会在其位置生成的HTML。它基本上只是一个input 元素,具有一些特殊且不那么特殊的属性。输入框中的值通过ng-model 绑定到指令的$scope 上的currentInputValue 变量。输入框上的change 事件通过ng-change 指令绑定到指令的$scope 上的update 函数。
链接功能
该过程的核心在于指令上的link 函数:我们定义了一个update 方法。如上所述,此方法绑定到指令的 HTML 模板中输入框的change 事件。因此,每次用户更改框中的输入时,都会调用update。
此方法使用$timeout 服务。它告诉$timeout 服务等待timeout 毫秒,然后应用设置$scope.value = $scope.currentInputValue 的回调。这类似于调用setTimeout(function () {$scope.value = $scope.currentInputValue}, timeout)。
$timeout 调用返回一个承诺。我们可以通过调用$timeout.cancel(p) 取消由$timeout 生成的承诺p,该承诺正在等待执行。这就是update 在第一行中所做的:如果我们有来自先前更改事件的承诺,我们会在创建新事件之前取消它。这意味着如果我们有例如500 毫秒超时,更新被调用两次,调用相隔 400 毫秒,我们将只有一个等待触发的承诺。
总体结果
承诺在解决时设置$scope.value = currentInputValue;即,它将“外部可见”value 属性设置为具有输入框内容的值。 value 只会改变 - 外部控制器只会看到 value 改变 - 在timeout 毫秒的静止期之后,我相信这是你所追求的行为。