处理这个问题的最简洁的方法可能是编写一个指令来包装<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
具有一些特殊和不那么特殊属性的元素。输入框中的值绑定到currentInputValue
指令$scope
via上的变量ng-model
。输入框上的事件通过指令change
绑定到update
指令上的函数。$scope
ng-change
链接功能
该过程的核心在于link
指令上的函数:我们定义了一个update
方法。如上所述,此方法绑定到change
指令的 HTML 模板中的输入框事件。因此,每次用户更改框中的输入时,update
都会调用。
此方法使用$timeout
服务。它告诉$timeout
服务等待timeout
几毫秒,然后应用一个回调来设置$scope.value = $scope.currentInputValue
. 这类似于调用setTimeout(function () {$scope.value = $scope.currentInputValue}, timeout)
.
该$timeout
调用返回一个承诺。我们可以通过调用来取消p
等待$timeout
执行的promise $timeout.cancel(p)
。这就是update
它的第一行所做的:如果我们有来自先前更改事件的承诺,我们会在创建新事件之前取消它。这意味着,如果我们有一个 500 毫秒的超时,并且更新被调用了两次,调用相隔 400 毫秒,我们将只有一个等待触发的承诺。
总体结果
承诺在解决时设置$scope.value = currentInputValue
;即,它将“外部可见”value
属性设置为具有输入框内容的值。只会在几毫秒的静止期后发生value
变化——外部控制器只会看到变化,我相信这是你所追求的行为。value
timeout