通过 js 让元素失去焦点

今天做项目,遇到一个需求。点击输入框获取焦点,按下回车后,执行搜索,失去焦点。

为什么会有这样的需求

以下内容,不考虑部分输入法等兼容性问题

项目大致要求是这样子的:

  • 页面提供搜索框,同时提供搜索历史方便直接选择;
  • 输入内容后,按回车,自动进行搜索,结果显示在下方区域。同时历史记录隐藏;
  • 再次进行输入内容时候,搜索结果移除,继续显示搜索记录提供方便选择。

问题点

梳理需求后,其实可以简单理解整个流程,用一个状态进行表示:

搜索框获得焦点 => 显示历史记录

搜索框失去焦点 => 显示搜索结果

这个状态改变的规则为:

搜索框输入完毕(回车) => 搜索框失去焦点

搜索框被点击 => 搜索框获得焦点

第一版代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
<!DOCTYPE html>
<html>

<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>test</title>
<style>
* {
margin: 0;
padding: 0;
font-size: 16px;
}

h1 {
font-size: 18px;
}

.wrapper {
margin: 8px;
}

.search {
width: 100%;
border: 0;
border-bottom: 1px solid #333;
outline: none;
}
</style>
</head>

<body>
<div class="wrapper">
<h1>搜索:</h1>
<input class="search" id="J_Search" type="search" autocomplete="off">
</div>

<div class="wrapper" id="J_History">
<h1>搜索历史:</h1>
<div>历史 bala bala...</div>
</div>

<div class="wrapper" id="J_Result">
<h1>搜索结果:</h1>
<div>结果 bala bala...</div>
</div>

<script>
let $search = document.querySelector('#J_Search')
let $history = document.querySelector('#J_History')
let $result = document.querySelector('#J_Result')

// 搜索框数据提交
const searchSubmit = word => {
$history.style.display = 'none'
$result.style.display = 'block'
}

// 搜索框获得焦点
$search.addEventListener('focus', () => {
$history.style.display = 'block'
$result.style.display = 'none'
})

// 搜索框输入
$search.addEventListener('keyup', e => {
if (e.keyCode === 13) {
// 判断按回车键
searchSubmit(e.target.value)
}
})

// 默认显示形态
$search.focus()
</script>
</body>

</html>

整体逻辑没问题,唯独就是,输入完毕提交后,输入框不会失去焦点,也就无法通过点击再次出发 focus 事件了。

第二版调整

考虑到要让输入框失去焦点,采用增加一个元素,并让其获得焦点即可。

但是增加的元素要有一些要求:

  • 这个元素能获得焦点,那就得是控件元素
  • 这个元素必须在页面内,还必须得显示,否则不能获得焦点

综合这两点,我选择 input-radio 控件,比较小巧不明显,而且不会触发移动端的输入法,同时,只能定位到屏幕外侧。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
// new
// 失去焦点元素
const createBlurElment = () => {
let $input = document.createElement('input')
$input.type = 'radio'
$input.style.position = 'absolute'
$input.style.top = '-1000px'
$input.style.height = '0'
document.body.appendChild($input)
return $input
}

let $search = document.querySelector('#J_Search')
let $history = document.querySelector('#J_History')
let $result = document.querySelector('#J_Result')
// new
let $blurElement = createBlurElment()

// 搜索框数据提交
const searchSubmit = word => {
$history.style.display = 'none'
$result.style.display = 'block'
}

// 搜索框获得焦点
$search.addEventListener('focus', () => {
$history.style.display = 'block'
$result.style.display = 'none'
})

// 搜索框输入
$search.addEventListener('keyup', e => {
if (e.keyCode === 13) {
// 判断按回车键
searchSubmit(e.target.value)
// new
$blurElement.focus()
}
})

// 默认显示形态
$search.focus()

这样就曲线救国,通过 js 让指定元素失去焦点了。