keyup 触发保存时保持光标位置的最佳实践
Best practice to maintain cursor position when keyup triggers save
我正在使用 Backbone.js。在我看来,我有一个 textarea
其 keyup
绑定到这样的函数(但请参阅下面的编辑):
this.model.save({text: self.$('textarea').val()}, {patch: true});
在视图的 initialize
函数中,我将模型的 change
事件绑定到视图的 render
函数:
initialize: function() {
this.listenTo(this.model, 'change', _.bind(this.render, this));
},
问题是,当用户键入 textarea
时,会发生以下事件序列:
keyup
事件触发。
keyup
处理程序在模型上调用 save
。
- 调用
save
触发模型的模型的 change
事件。
- 监听模型的
change
事件的视图调用 render
。
-
textarea
被替换为 DOM。
textarea
不再聚焦,文本光标位置丢失。
对于这种 texarea
的 keyup
事件需要触发同步的情况,最佳做法是什么?我考虑过的一些选项:
- 不要将
change
绑定到 render
。缺点:如果模型数据因用户输入以外的任何原因发生更改,则文本区域不会自动更新。
- 阅读并记住
render
开头的光标位置。将光标位置设置在render
的末尾。缺点:取决于浏览器支持参差不齐的光标操作功能。
- 在
keyup
处理程序中,在视图上设置一个临时 属性 告诉它不要重新渲染。保存模型后取消设置。缺点:感觉像意大利面条代码,对抗Backbone. 的结构
有没有我没有看到的选项?您推荐以上选项之一吗?
编辑:
我不想偏离主要观点,但由于它出现在其中一个答案中:我没有直接绑定到 keyup
,而是通过 _.debounce
进行中介.因此,事件处理程序仅在用户停止输入时运行,这是由自上次 keyup
.
以来经过的一定时间定义的。
首先,我不希望这样做,因为将您的模型保存在 keyup
上似乎是一种非常奇怪的行为。如果有一个确实需要这样做的用例,我建议至少使用 input
事件 - 否则每次用户按下箭头键,shift,ctrl 时你最终都会保存模型等等
我认为您还希望将输入事件去抖动 500 毫秒左右,这样您实际上并没有保存模型 每 一次击键。
要解决您在第 1 点中的评论:
Disadvantage: If the model data changes due to anything other than the
user typing, the textarea doesn't automatically update
您需要问问自己发生这种情况的可能性以及如果发生这种情况重新呈现视图的重要性。
最后,如果您认为这确实有可能 并且 重新渲染视图很重要,那么您可以尝试这样的操作
http://jsfiddle.net/nuewwdmr/2/
这里的一个重要部分是将模型属性名称映射到输入的名称字段。我在这里所做的是按照您上面描述的事件顺序进行的。不同之处在于,当模型更改时,我们检查更改的属性并更新模板中相应元素的值。
这在非常简单的情况下工作正常,即用户在输入中以 "normal" 方式输入的快乐路径。但是,如果用户决定返回到输入的开头并更改字母以将其大写,例如,在模型中发生更改事件后,光标将跳到字符串的末尾。
您在这里需要的行为实际上是双向数据绑定,这绝不是微不足道的,尤其是 Backbone 考虑到 Backbone 视图的功能如此之少。
我的建议就是你的观点 1
Don't bind change to render
编辑
如果您想进一步了解模型/视图绑定,您可以查看两个库:
我以前用过 stickit,它...很好。不是很好。简单绑定就可以了,例如将 "top-level" 模型属性绑定到输入元素。一旦进入嵌套属性,您将 运行 遇到问题,然后您将不得不研究 Backbone 深度模型。
就像我说的,Backbone 的 View 提供的东西不多。如果您有时间,我建议您考虑使用 React 组件代替 Backbone 视图,或者甚至看看 ampersand 必须提供的一些有趣的东西。
我正在使用 Backbone.js。在我看来,我有一个 textarea
其 keyup
绑定到这样的函数(但请参阅下面的编辑):
this.model.save({text: self.$('textarea').val()}, {patch: true});
在视图的 initialize
函数中,我将模型的 change
事件绑定到视图的 render
函数:
initialize: function() {
this.listenTo(this.model, 'change', _.bind(this.render, this));
},
问题是,当用户键入 textarea
时,会发生以下事件序列:
keyup
事件触发。keyup
处理程序在模型上调用save
。- 调用
save
触发模型的模型的change
事件。 - 监听模型的
change
事件的视图调用render
。 -
textarea
被替换为 DOM。 textarea
不再聚焦,文本光标位置丢失。
对于这种 texarea
的 keyup
事件需要触发同步的情况,最佳做法是什么?我考虑过的一些选项:
- 不要将
change
绑定到render
。缺点:如果模型数据因用户输入以外的任何原因发生更改,则文本区域不会自动更新。 - 阅读并记住
render
开头的光标位置。将光标位置设置在render
的末尾。缺点:取决于浏览器支持参差不齐的光标操作功能。 - 在
keyup
处理程序中,在视图上设置一个临时 属性 告诉它不要重新渲染。保存模型后取消设置。缺点:感觉像意大利面条代码,对抗Backbone. 的结构
有没有我没有看到的选项?您推荐以上选项之一吗?
编辑:
我不想偏离主要观点,但由于它出现在其中一个答案中:我没有直接绑定到 keyup
,而是通过 _.debounce
进行中介.因此,事件处理程序仅在用户停止输入时运行,这是由自上次 keyup
.
首先,我不希望这样做,因为将您的模型保存在 keyup
上似乎是一种非常奇怪的行为。如果有一个确实需要这样做的用例,我建议至少使用 input
事件 - 否则每次用户按下箭头键,shift,ctrl 时你最终都会保存模型等等
我认为您还希望将输入事件去抖动 500 毫秒左右,这样您实际上并没有保存模型 每 一次击键。
要解决您在第 1 点中的评论:
Disadvantage: If the model data changes due to anything other than the user typing, the textarea doesn't automatically update
您需要问问自己发生这种情况的可能性以及如果发生这种情况重新呈现视图的重要性。
最后,如果您认为这确实有可能 并且 重新渲染视图很重要,那么您可以尝试这样的操作
http://jsfiddle.net/nuewwdmr/2/
这里的一个重要部分是将模型属性名称映射到输入的名称字段。我在这里所做的是按照您上面描述的事件顺序进行的。不同之处在于,当模型更改时,我们检查更改的属性并更新模板中相应元素的值。
这在非常简单的情况下工作正常,即用户在输入中以 "normal" 方式输入的快乐路径。但是,如果用户决定返回到输入的开头并更改字母以将其大写,例如,在模型中发生更改事件后,光标将跳到字符串的末尾。
您在这里需要的行为实际上是双向数据绑定,这绝不是微不足道的,尤其是 Backbone 考虑到 Backbone 视图的功能如此之少。
我的建议就是你的观点 1
Don't bind change to render
编辑
如果您想进一步了解模型/视图绑定,您可以查看两个库:
我以前用过 stickit,它...很好。不是很好。简单绑定就可以了,例如将 "top-level" 模型属性绑定到输入元素。一旦进入嵌套属性,您将 运行 遇到问题,然后您将不得不研究 Backbone 深度模型。
就像我说的,Backbone 的 View 提供的东西不多。如果您有时间,我建议您考虑使用 React 组件代替 Backbone 视图,或者甚至看看 ampersand 必须提供的一些有趣的东西。