gpt4 book ai didi

javascript - 我如何在 AngularJS 中创建和聚焦新元素?

转载 作者:行者123 更新时间:2023-11-30 21:14:43 25 4
gpt4 key购买 nike

我有一个包含动态输入数量的表单,由 AngularJS 控制。

<body ng-app="mainApp" ng-controller="CreatePollController" ng-init="init(3)">
<form id="createPollForm">
<input class="create-input" ng-repeat="n in questions" id="q_{{$index}}" name="q_{{$index}}" type="text" ng-keypress="createInputKeypress($event);"/>
<a href="javascript:void(0);" ng-click="addQuestion()">Add Question</a>
</form>
</body>

这是由以下 Angular 代码控制的:

app.controller('CreatePollController', function($scope) {
$scope.questions = [];

$scope.init = function(numOfInputs){
for(var i = 0; i < numOfInputs; i++){
$scope.questions.push({
"questionText":""
});
}
};

$scope.addQuestion = function(){
$scope.questions.push({
"questionText":""
});
};

$scope.createInputKeypress = function(e){
if(e.keyCode === 13){
e.preventDefault();

var idx = Number(e.target.id.replace("q_", ""));
if(idx === this.questions.length - 1){
this.addQuestion();
}

// Wait for angular update ????

var nextId = "#q_" + (++idx);
$(nextId).focus();
}
};
});

目前,当用户在关注文本输入时按下 Enter 键时,会调用 createInputKeypress 函数,浏览器会关注表单中的下一个输入。但是,如果您当前专注于表单中的最后一个元素,它会向 questions 数组添加一个新问题,这将导致在 DOM 中生成另一个输入。

但是,当创建这个新元素时,focus() 调用不起作用。我怀疑这是因为 angular 没有立即添加新元素,所以尝试使用 jQuery 定位和聚焦新元素不起作用。

有没有办法等待 DOM 更新,然后聚焦新元素?

最佳答案

您可能已经知道,javascript 是基于轮流的,这意味着浏览器将轮流(循环)执行 JS 代码。目前,在下一个 javascript 周期中准备回调的方法是使用我们希望在超时中在下一个周期运行的代码设置回调,我们可以通过调用 setTimeout 来实现。以 0 毫秒为间隔,这将强制在下一个 javascript 轮次中调用给定的回调,在浏览器完成(从) 当前的回调之后。

为了保持简单,一个浏览器周期按给定顺序执行这些操作:

  1. 脚本(发生 JS 的地方)
  2. 渲染(HTML 和 DOM 渲染)
  3. 绘画(在窗口中绘制呈现的 DOM)
  4. 其他(内部浏览器的东西)

看看这个例子:

console.log(1);
console.log(2);

setTimeout(function () {
console.log(3);
console.log(4);
}, 0);

console.log(5);
console.log(6);

/** prints in the console
* 1 - in the current JS turn
* 2 - in the current JS turn
* 5 - in the current JS turn
* 6 - in the current JS turn
* 3 - in the next JS turn
* 4 - in the next JS turn
**/

3和4打印在5和6之后,即使知道没有间隔 (0) 在 setTimeout 中,因为 setTimeout 基本上准备给定回调,仅在当前 javascript 轮次完成后调用。如果在下一回合,当前时间与setTimeout指令绑定(bind)回调的时间差小于setTimeout传入的时间间隔,则回调不会被调用,它会等待下一个回合,重复这个过程,直到时间间隔小于那个差值,然后才调用回调!

由于 AngularJS 是一个包装我们所有代码的框架, Angular 更新通常发生在我们的代码执行之后,在每个 javascript 轮次结束时,这意味着对 HTML 的 Angular 更改只会发生在当前的 javascript 回合结束。

AngularJS 也有一个内置的超时服务,叫做 $timeout , difference between the native setTimeout and angular's $timeout service最后一个是服务函数,它恰好调用原生的 setTimeout 和一个 angular 的内部回调,这个回调又负责执行我们传入的回调 $timeout 然后确保我们在 $scope 中所做的任何更改都将反射(reflect)在其他地方!然而,由于在我们的例子中我们实际上并不想更新 $scope,我们不需要使用这个服务,一个简单的 setTimeout 恰好更有效!

了解所有这些信息后,我们可以使用 setTimeout 来解决我们的问题。像这样:

$scope.createInputKeypress = function(e){
if(e.keyCode === 13){
e.preventDefault();

var idx = Number(e.target.id.replace("q_", ""));
if(idx === this.questions.length - 1){
this.addQuestion();
}

// Wait for the next javascript turn
setTimeout(function () {
var nextId = "#q_" + (++idx);
$(nextId).focus();
}, 0);
}
};

为了让它更语义化,我们可以包装setTimeout逻辑在具有更多上下文化名称的函数中,例如 runAfterRender:

function runAfterRender (callback) {
setTimeout(function () {
if (angular.isFunction(callback)) {
callback();
}
}, 0);
}

现在我们可以使用这个函数来准备下一个 javascript 轮次的代码执行:

app.controller('CreatePollController', function($scope) {
// functions
function runAfterRender (callback) {
setTimeout(function () {
if (angular.isFunction(callback)) {
callback();
}
}, 0);
}

// $scope
$scope.questions = [];

$scope.init = function(numOfInputs){
for(var i = 0; i < numOfInputs; i++){
$scope.questions.push({
"questionText":""
});
}
};

$scope.addQuestion = function(){
$scope.questions.push({
"questionText":""
});
};

$scope.createInputKeypress = function(e){
if(e.keyCode === 13){
e.preventDefault();

var idx = Number(e.target.id.replace("q_", ""));
if(idx === this.questions.length - 1){
this.addQuestion();
}

runAfterRender(function () {
var nextId = "#q_" + (++idx);
$(nextId).focus();
});
}
};
});

关于javascript - 我如何在 AngularJS 中创建和聚焦新元素?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45803620/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com