UNPKG

3.08 kBJavaScriptView Raw
1import KEYCODE from './keycode';
2import { each } from './object';
3
4/**
5 * 用于切换页面元素的焦点
6 */
7
8/**
9 * 元素是否可见
10 * @private
11 * @param {Element} node
12 * @return {Boolean}
13 */
14function _isVisible(node) {
15 while (node) {
16 var _node = node,
17 nodeName = _node.nodeName;
18
19 if (nodeName === 'BODY' || nodeName === 'HTML') {
20 break;
21 }
22 if (node.style.display === 'none' || node.style.visibility === 'hidden') {
23 return false;
24 }
25 node = node.parentNode;
26 }
27 return true;
28}
29
30/**
31 * 元素是否可以获取焦点
32 * @private
33 * @param {Element} node
34 * @return {Boolean}
35 */
36function _isFocusable(node) {
37 var nodeName = node.nodeName.toLowerCase();
38 var tabIndex = parseInt(node.getAttribute('tabindex'), 10);
39 var hasTabIndex = !isNaN(tabIndex) && tabIndex > -1;
40
41 if (_isVisible(node)) {
42 if (nodeName === 'input') {
43 return !node.disabled && node.type !== 'hidden';
44 } else if (['select', 'textarea', 'button'].indexOf(nodeName) > -1) {
45 return !node.disabled;
46 } else if (nodeName === 'a') {
47 return node.getAttribute('href') || hasTabIndex;
48 } else {
49 return hasTabIndex;
50 }
51 }
52 return false;
53}
54
55/**
56 * 列出能获取焦点的子节点
57 * @param {Element} node 容器节点
58 * @return {Array<Element>}
59 */
60export function getFocusNodeList(node) {
61 var res = [];
62 var nodeList = node.querySelectorAll('*');
63
64 each(nodeList, function (item) {
65 if (_isFocusable(item)) {
66 var method = item.getAttribute('data-auto-focus') ? 'unshift' : 'push';
67 res[method](item);
68 }
69 });
70
71 if (_isFocusable(node)) {
72 res.unshift(node);
73 }
74
75 return res;
76}
77
78// 用于记录上一次获得焦点的无素
79var lastFocusElement = null;
80
81/**
82 * 保存最近一次获得焦点的无素
83 */
84export function saveLastFocusNode() {
85 lastFocusElement = document.activeElement;
86}
87
88/**
89 * 清除焦点记录
90 */
91export function clearLastFocusNode() {
92 lastFocusElement = null;
93}
94
95/**
96 * 尝试将焦点切换到上一个元素
97 */
98export function backLastFocusNode() {
99 if (lastFocusElement) {
100 try {
101 // 元素可能已经被移动了
102 lastFocusElement.focus();
103 } catch (e) {
104 // ignore ...
105 }
106 }
107}
108
109/**
110 * 在限制的范围内切换焦点
111 * @param {Element} node 容器节点
112 * @param {Event} e 键盘事件
113 */
114export function limitTabRange(node, e) {
115 if (e.keyCode === KEYCODE.TAB) {
116 var tabNodeList = getFocusNodeList(node);
117 var maxIndex = tabNodeList.length - 1;
118 var index = tabNodeList.indexOf(document.activeElement);
119
120 if (index > -1) {
121 var targetIndex = index + (e.shiftKey ? -1 : 1);
122 targetIndex < 0 && (targetIndex = maxIndex);
123 targetIndex > maxIndex && (targetIndex = 0);
124 tabNodeList[targetIndex].focus();
125 e.preventDefault();
126 }
127 }
128}
\No newline at end of file