前言

 前几天用户反映在录入资料时一不小心错按Backspace键,就会直接回退到是一个页面,导致之前辛辛苦苦录入的资料全部丢失了。哦?居然还有这种情况。下面我们来一起探讨一下吧!

Windows系统下独有的行为

 Windows下的IE、FireFox和Chrome 52之前的浏览器,当焦点不在一个可编辑的元素上时,按Backspace键就会回退到上一个页面,按Shift+Backspace键则会前进到下一个页面。

 而Chrome 52以后的浏览器则屏蔽了BackspaceShift+Backspace的上述行为,而是采用Alt+Left实现回退和Alt+Right实现前进。如果想恢复Backspace回退,则需要安装Go Back With Backspace的Extension才行。

 对于FireFox而言,我们可以设置BackspaceShift+Backspace的行为。

  1. 在地址栏输入about:config
  2. 在搜索框输入browser.backspace_action,然后设置项目值即可。有3个可选项

    0,表示BackspaceShift+Backspace的行为对应页面回退和前进(Windows下的默认值)

    1,表示BackspaceShift+Backspace的行为对应页面向下滚动和向上滚动

    2或其他值,表示不响应BackspaceShift+Backspace(Ubuntu16下的默认值)

注意:Linux和OS X下的浏览器按BackspaceShift+Backspace不会触发页面的回退和前进。

如何应对

方案一:页面跳转时弹出二次确认

 通过beforeunload事件实现页面跳转时弹出二次确认模态窗,让用户有后悔的机会。但会截断其他正常跳转的操作流畅性,在确实没有办法时才使用!

方案二:直接屏蔽

 屏蔽BackspaceShift+Backspace的默认行为,仅当焦点落在可编辑区域中时才暂时取消屏蔽。

那么哪些算是能获得焦点的可编辑区域呢?就下面这些咯!!

  1. input[type=text]:not([readonly])
  2. input[type=password]:not([readonly])
  3. input[type=number]:not([readonly])
  4. input[type=email]:not([readonly])
  5. input[type=url]:not([readonly])
  6. input[type=search]:not([readonly])
  7. input[type=tel]:not([readonly])
  8. textarea:not([readonly])
  9. [contenteditable]:not([readonly])

就是说当焦点落在上述符合规则的元素上时,按BackspaceShift+Backspace的默认行为就不是页面跳转,因此不用屏蔽掉。

附加功能

 现在我们的目的是页面不会因为用户误操作而刷新,导致页面数据丢失。这里有两个组合键同样会的导致页面刷新

  1. ctrl+r刷新当前页面,可被阻止;
  2. ctrl+w关闭当前窗体或标签页,无法阻止。

代码时间.js

  1. ;window.nobsgb || (function(exports){
  2. var started = false
  3. exports.start = function(){started = true}
  4. exports.stop = function(){started = false}
  5. var KEYCODE = {
  6. BACKSPACE: 8,
  7. R: 82
  8. }
  9. // 判断type是否不受阻止
  10. var isEscapableType = function(rEscapableTypes){
  11. return function(type){
  12. return rEscapableTypes.test(type)
  13. }
  14. }(/text|textarea|tel|email|number|search|password|url/i)
  15. // 判断标签是否不受阻止
  16. var isEscapableTag = function(rEscapableTag){
  17. return function(tag){
  18. return rEscapableTag.test(tag)
  19. }
  20. }(/input|textarea/i)
  21. // 判断是否设置为content editable
  22. var isContentEditable = function(el){
  23. return el.isContentEditable
  24. }
  25. // 判断是否为不受阻止的Backspace
  26. var isEscapableBackspace = function(el){
  27. return or(isEscapableTag(el.tagName)
  28. &&
  29. or(!('type' in el)
  30. , ('type' in el) && isEscapableType(el.type) && !el.readOnly)
  31. , isContentEditable(el))
  32. }
  33. var isCtrlR = function(e, keycode){
  34. return e.ctrlKey && KEYCODE.R === keycode
  35. }
  36. var isArray = function(x){
  37. return /Array/.test(Object.prototype.toString.call(x))
  38. }
  39. var getEvt = function(e){
  40. return e || window.event
  41. }
  42. var getTarget = function(e){
  43. return e.target || e.srcElement
  44. }
  45. var getKeycode = function(e){
  46. return e.keyCode || e.which
  47. }
  48. var preventDefault = function(e){
  49. e.preventDefault && e.preventDefault()
  50. e.returnValue = false
  51. return false
  52. }
  53. var listen = function(listen){
  54. return function(evtNames, handler){
  55. if (!isArray(evtNames)){
  56. evtNames = [evtName]
  57. }
  58. var i = 0
  59. , len = evtNames.length
  60. for (; i < len; ++i){
  61. listen(evtNames[i], handler)
  62. }
  63. }
  64. }(function(evtName, handler){
  65. if (or(document['addEventListener'] && (document['addEventListener'].apply(document, arguments) || true)
  66. , document['attachEvent'] && (document['attachEvent'].apply(document, arguments) || true))){
  67. document['on'+evtName] = handler
  68. }
  69. })
  70. var or = function(){
  71. var ret = false
  72. , i = 0
  73. , len = arguments.length
  74. for (; !ret && i < len; ++i){
  75. ret = ret || arguments[i]
  76. }
  77. return ret
  78. }
  79. var handler = function(e){
  80. if (!started) return true
  81. var evt = getEvt(e)
  82. , el = getTarget(evt)
  83. , keyCode = getKeycode(evt)
  84. if (or(KEYCODE.BACKSPACE === keyCode && !isEscapableBackspace(el)
  85. , isCtrlR(evt, keyCode))){
  86. return preventDefault(evt)
  87. }
  88. }
  89. listen(['keydown'], handler)
  90. }(window.nobsgb = {}))

代码时间.cljs

core.cljs

  1. (ns nobsgb.core
  2. (:require [nobsgb.dom :as dom]
  3. [nobsgb.pred :as pred]))
  4. (def started false)
  5. (defn ^:export start []
  6. (set! started true))
  7. (defn ^:export stop []
  8. (set! started false))
  9. (defn handler
  10. "keydown事件响应函数"
  11. [e]
  12. (when started
  13. (let [evt (dom/get-evt e)
  14. el (dom/get-el evt)
  15. key-code (dom/get-key-code evt)
  16. ctrl-key (dom/get-ctrl-key evt)
  17. read-only (dom/get-read-only el)
  18. type (dom/get-type el)
  19. content-editable (dom/get-content-editable el)
  20. tag (dom/get-tag el)]
  21. (if-not
  22. (pred/escapable?
  23. key-code read-only type tag content-editable ctrl-key)
  24. (dom/prevent-default evt)
  25. true))))
  26. (defonce init
  27. (#(dom/listen! js/document "keydown" handler)))

dom.cljs

  1. (ns nobsgb.dom)
  2. (defn get-evt
  3. [e]
  4. (if (some? e) e (.event js/window)))
  5. (defn get-el
  6. [e]
  7. (let [el (.-target e)]
  8. (if (some? el) el (.-srcElement e))))
  9. (defn get-key-code
  10. [e]
  11. (.-keyCode e))
  12. (defn get-ctrl-key
  13. [e]
  14. (.-ctrlKey e))
  15. (defn get-read-only
  16. [el]
  17. (-> el (aget "readOnly") js/Boolean))
  18. (defn get-type
  19. [el]
  20. (let [type (.-type el)]
  21. (if (some? type) type "")))
  22. (defn get-tag
  23. [el]
  24. (.-tagName el))
  25. (defn get-content-editable
  26. [el]
  27. (.-isContentEditable el))
  28. (defn prevent-default
  29. [e]
  30. (if (some? (.-preventDefault e))
  31. (do
  32. (.preventDefault e)
  33. (set! (.-returnValue e) false)
  34. false)
  35. true))
  36. (defn listen!
  37. [el evt-name handler]
  38. (cond
  39. (fn? (.-addEventListener el)) (.addEventListener el evt-name handler)
  40. (fn? (.-attachEvent el)) (.attachEvent el (str "on" evt-name) handler)
  41. :else (aset el (str "on" evt-name) handler)))

pred.cljs

  1. (ns nobsgb.pred)
  2. ;;;; 断言
  3. (defonce ^:const KEYCODES
  4. {:backspace 8
  5. :r 82})
  6. (defn matches-key?
  7. "是否匹配指定键码"
  8. [indicated-key-code key-code]
  9. (= indicated-key-code key-code))
  10. (def ^{:doc "是否为退格键"}
  11. backspace?
  12. (partial matches-key? (:backspace KEYCODES)))
  13. (def ^{:doc "是否为字母R键"}
  14. r?
  15. (partial matches-key? (:r KEYCODES)))
  16. (defn with-ctrl?
  17. "是否在按ctrl的基础上按其他键"
  18. [ctrl-key]
  19. (or (= ctrl-key "1")
  20. (true? ctrl-key)))
  21. (defn ctrl+r?
  22. "是否为ctrl+r"
  23. [ctrl-key key-code]
  24. (and (with-ctrl? ctrl-key)
  25. (r? key-code)))
  26. (def not-ctrl+r? (complement ctrl+r?))
  27. (defn escapable-type?
  28. "是否为可跳过的type属性"
  29. [type]
  30. (some?
  31. (some->> type
  32. (re-matches #"(?i)text|password|tel|number|email|search|url"))))
  33. (defn escapable-tag?
  34. "是否为可跳过的tag"
  35. [tag]
  36. (some?
  37. (some->> tag
  38. (re-matches #"(?i)input|textarea"))))
  39. (def ^{:doc "是否设置为可编辑元素"}
  40. content-editable? identity)
  41. (def ^{:doc "是否设置为只读"}
  42. read-only? identity)
  43. (def writable? (complement read-only?))
  44. (defn escapable-backspace?
  45. [key-code read-only type tag content-editable]
  46. (and (backspace? key-code)
  47. (writable? read-only)
  48. (or (escapable-type? type)
  49. (escapable-tag? tag)
  50. (content-editable? content-editable))))
  51. (defn escapable?
  52. [key-code read-only type tag content-editable ctrl-key]
  53. (or
  54. (and (not-ctrl+r? ctrl-key key-code)
  55. (not (backspace? key-code)))
  56. (escapable-backspace? key-code read-only type tag content-editable)))

总结

 尊重原创,转载请注明来自:http://www.cnblogs.com/fsjohnhuang/p/6890699.html _肥仔John

前端魔法堂:屏蔽Backspace导致页面回退的更多相关文章

  1. 前端魔法堂:解秘FOUC

    前言  对于问题多多的IE678,FOUC(flash of unstyled content)--浏览器样式闪烁是一个不可忽视的话题,但对于ever green的浏览器就不用理会了吗?下面尝试较全面 ...

  2. 前端魔法堂:可能是你见过最详细的WebWorker实用指南

    前言 JavaScript从使用开初就一直基于事件循环的单线程运行模型,即使是成功进军后端开发的Nodejs也没有改变这一模型.那么对于计算密集型的应用,我们必须创建新进程来执行运算,然后执行进程间通 ...

  3. 前端魔法堂:onsubmit和submit事件处理函数怎么不生效呢?

    前言  最近在用Polymer增强form,使其支持表单的异步提交,但发现明明订阅了onsubmit和submit事件,却怎么也触发不了.下面我们将一一道来. 提交表单的方式 表单仅含一个以下的元素时 ...

  4. 前端javascript如何阻止按下退格键页面回退 但 不阻止文本框使用退格键删除文本

    这段代码可以: document.onkeydown = function (e) { e.stopPropagation(); // 阻止事件冒泡传递 e.preventDefault(); // ...

  5. 【JS】【1】JavaScript屏蔽Backspace键(避免点击后页面产生回退)

    前言: 1,参考资料:JavaScript屏蔽Backspace键 - 孤傲苍狼 - 博客园(http://www.cnblogs.com/xdp-gacl/p/3785806.html) 2,参考的 ...

  6. CSS魔法堂:更丰富的前端动效by CSS Animation

    前言  在<CSS魔法堂:Transition就这么好玩>中我们了解到对于简单的补间动画,我们可以通过transition实现.那到底多简单的动画适合用transtion来实现呢?答案就是 ...

  7. 阻止按下backspace键造成页面回退相像

    在IE浏览器中,会出现当你使用鼠标选中input标签或者是textarea标签,或者啥也没选中的时候,按下backspace键会触发浏览器的回退. 针对以上问题的解决思路:     1. 当按下键盘时 ...

  8. HTML5魔法堂:全面理解Drag & Drop API

    一.前言    在HTML4的时代,各前端工程师为了实现拖拽功能可说是煞费苦心,初听HTML5的DnD API觉得那些痛苦的日子将一去不复返,但事实又是怎样的呢?下面我们一起来看看DnD API的真面 ...

  9. CSS魔法堂:说说Float那个被埋没的志向

    前言  定位系统中第一难理解就是Normal flow,而第二就非Float莫属了,而Float难理解的原因有俩,1. 一开头我们就用错了:2. 它跟Normal flow靠得太近了.本文尝试理清Fl ...

随机推荐

  1. 关于JavaScript的模块化

    为什么需要模块化 最近在学习网易微专业的<前端系统架构>课程,里面讲到了关于JavaScript的模块化问题.具体指的是当随着Web系统不断强大起来,需要在客户端进行的操作就多了起来(比如 ...

  2. mock.js-无需等待,随机产生数据,让前端独立于后端进行开发

    mock.js所做的 基于 数据模板 生成模拟数据. 基于 HTML模板 生成模拟数据. 拦截并模拟 ajax 请求. Mock.js官方网址:http://mockjs.com/ 1.Mock.js ...

  3. ajax 大洋与小样的第二步

    一.Ajax的对象 XMLHttpRequest的方法 方法 描述 abort() 停止当前请求 getAllResponseHeaders() 把 HTTP请求的所有响应首部作为健/值对返回 get ...

  4. Ackerman 函数 (双递归函数)

    public static int ackerman(int n,int m){  if(n==1&&m==0){return 2;}  else if(n==0&&m ...

  5. Java 静态代理与动态代理

    代理模式 设想你的项目依赖第三方,但是你需要对其接口做一些数据检验.性能数据记录.异常处理等,合适的方法就是使用设计模式里的代理模式. 代理模式是常用的java设计模式,代理类与委托类有同样的接口,代 ...

  6. JS获取URL中参数值(QueryString)的4种方法

    方法一:正则法 function getQueryString(name) {    var reg = new RegExp('(^|&)' + name + '=([^&]*)(& ...

  7. c++中关于值对象与其指针以及const值对象与其指针的问题详细介绍

    话不多说,先附上一段代码与运行截图 //1 const int a = 10; //const 值对象 int *ap = (int *)&a;//将const int*指针强制转化为int* ...

  8. php 启动过程 - reqeust RINIT 过程

    php 启动过程 - reqeust RINIT 过程 概述 apache 接收到请求之后, 交给 php 处理 php 模块在接收到请求后, 会对请求进行初始化, 及 RINIT 过程 调用触发 a ...

  9. Java设计模式:桥接模式

    问题提出 生活中有很多事物集合,设为A1,A2......Am ,而每个事物都有功能F1,F2....Fn. 例如邮局的发送业务.简单模拟有两类事物:信件和包裹,均有平邮和挂号邮寄功能.程序设计中如何 ...

  10. IT职场经纬 |阿里web前端面试考题,你能答出来几个?

    有很多小伙伴们特别关心面试Web前端开发工程师时,面试官都会问哪些问题.今天小卓把收集来的"阿里Web前端开发面试题"整理贴出来分享给大家伙看看,赶紧收藏起来做准备吧~~ 一.CS ...