点击搜索按钮展开搜索输入框这样一个简单的功能,如果让你实现你会怎么实现呢?欢迎在评论区留言讨论
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gpaadC1O-1658297401556)(https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/4e6e1a4c20f443719481caac3b5eadea~tplv-k3u1fbpfcp-zoom-in-crop-mark:4536:0:0:0.image)]
首先分析整个搜索输入框可以发现,我们至少需要一个输入框和一个搜索按钮,所以可以考虑把它们放进一个容器里面,然后给容器添加一个特殊的类名.active
,用来区分搜索框点击和未被点击时的样式,这个容器就叫.search-container
吧
为什么是给容器添加.active
而不是单独给输入框和搜索按钮添加呢?因为点击搜索按钮后,不仅仅涉及到将输入框展开,还涉及到搜索按钮的位置变动,都是属于容器激活时才要处理的样式,所以将类名添加在.active
上更为合适
然后我们还需要理清一下整个功能涉及到哪些事件:
.active
类名,并且在css
中为这个类名添加样式,将输入框的宽度变大,同时使用transition
添加过渡效果input
输入框中.active
类名移除,让输入框和搜索按钮恢复原来的状态根据以上的思路分析,我们可以先写出整体的HTML
结构
结构很简单,没什么好说的
由于我们希望搜索按钮会动起来,那么就涉及到一个问题,它应该相对于谁动?肯定是容器!所以我们首先要将容器的position
设置为relative
,这样就可以让按钮相对于容器动起来
.search-container {
position: relative;
height: 50px;
}
由于按钮是容器的直接子元素,所以position
设置成absolute
后会相对于容器进行定位
.btn {
position: absolute;
inset: 0 auto auto 0;
width: 50px;
height: 100%;
transition: transform 0.5s ease;
}
inset: 0 auto auto 0
相当于top: 0; left: 0
,auto
相当于不设置,整个inset
的四项指代的是上、右、下、左属性
由于按钮位置会发生变化,所以添加transition
属性让过渡更加自然,由于我们是通过transform: translateX
进行位置变换的,所以这里transition
的作用目标是transofrm
,如果采用lef
进行位置变更,就将它改成left
即可
既然要让按钮动起来,那肯定要有一个类名来控制,当这个类名出现的时候就移动到一个位置,消失时又移动回来,所以写出如下样式:
.search-container.active .btn {
transform: translateX(160px);
}
意思是当父容器有active
类名的时候,将按钮的位置向右偏移160px
当容器有active
类名时,改变输入框的宽度
.search-container.active .search-input {
width: 200px;
}
再写好输入框的完整样式:
.search-input {
height: 100%;
width: 50px;
border: 0;
padding: 15px;
font-size: 24px;
background-color: #fff;
transition: width 0.5s ease;
border-radius: 20px;
}
这里由于涉及到变化的属性只是width
,所以transition
作用的目标属性是width
首先我们要获取到整个功能涉及的元素,搜索按钮肯定要的了,因为我们要监听它的点击事件,输入框也是肯定要的,因为我们要监听它的失去焦点blur
事件,容器更是少不了,因为我们的特殊类名.active
就是添加在它身上
明确了要获取的元素之后,就可以写出如下代码:
/** @type HTMLElement */
const oBtn = document.querySelector('.btn')
/** @type HTMLElement */
const oSearchInput = document.querySelector('.search-input')
const oSearchContainer = document.querySelector('.search-container')
这里使用了jsdoc
的方式显示指明了元素的类型,这样能够获得明确的类型提示,比如添加事件监听器的时候,因为默认的querySelector
获取到的是Element
类型的对象,那么事件只有fullscreenchange
和fullscreenerror
两种 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-l7zoKcgF-1658297401556)(https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/3ce06a66e53d442b870d1ab81d2e60e2~tplv-k3u1fbpfcp-zoom-in-crop-mark:4536:0:0:0.image)] 如果显式声明元素类型后,就可以获得更加友好的类型提示 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vzGXCKzp-1658297401557)(https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/de3fd0da2a1749dea235ed2dcb4ef1f2~tplv-k3u1fbpfcp-zoom-in-crop-mark:4536:0:0:0.image)]
通过前面的分析我们已经知道,首先需要给容器添加.active
类名
其次,还要将元素焦点聚焦至输入框中,这个可以通过DOM
元素对象的focus
方法实现
/**
* @description 点击搜索按钮给容器添加 active 类名
*/
const handleBtnClick = () => {
oSearchContainer.classList.add('active')
oSearchInput.focus()
}
当输入框失去焦点的时候,我们就应当移除容器的active
类名,这样就会由相应的CSS
将元素归为
/**
* @description 搜索输入框失去焦点时移除容器的 active 类名
*/
const handleBlur = () => {
oSearchContainer.classList.remove('active')
}
至此,一个简单的点击展开搜索框特效就实现完成了,完整代码如下
hidden-search
* {
box-sizing: border-box;
}
body {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
background-color: #292d3e;
margin: 0;
padding: 0;
}
.search-container {
position: relative;
height: 50px;
}
.search-input {
height: 100%;
width: 50px;
border: 0;
padding: 15px;
font-size: 24px;
background-color: #fff;
transition: width 0.5s ease;
border-radius: 20px;
}
.btn {
position: absolute;
inset: 0 auto auto 0;
width: 50px;
height: 100%;
cursor: pointer;
font-size: 24px;
border: 0;
background-color: #fff;
transition: transform 0.5s ease;
border-radius: 20px;
}
.btn:focus,
.search-input:focus {
outline: none;
}
.search-container.active .search-input {
width: 200px;
}
.search-container.active .btn {
transform: translateX(160px);
}
;(() => {
/** @type HTMLButtonElement */
const oBtn = document.querySelector('.btn')
/** @type HTMLInputElement */
const oSearchInput = document.querySelector('.search-input')
const oSearchContainer = document.querySelector('.search-container')
/**
* @description 点击搜索按钮给容器添加 active 类名
*/
const handleBtnClick = () => {
oSearchContainer.classList.add('active')
oSearchInput.focus()
}
/**
* @description 搜索输入框失去焦点时移除容器的 active 类名
*/
const handleBlur = () => {
oSearchContainer.classList.remove('active')
}
const bindEvent = () => {
oBtn.addEventListener('click', handleBtnClick)
oSearchInput.addEventListener('blur', handleBlur)
}
const init = () => {
bindEvent()
}
init()
})()