You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Vue中实现搜索栏向上移动并缩小的过渡效果?

Vue搜索栏顶部移动+缩小过渡实现方案

核心修改点

  • 改用Vue响应式class绑定替代原生DOM操作,契合Vue开发规范
  • 完善定位与过渡动画CSS规则,实现平滑的移动+缩放效果
  • 调整搜索栏内部元素尺寸,匹配整体缩小的视觉一致性

修改后的完整代码

<template>
  <div id="app" class="container">
    <div class="input-group centered" :class="{ 'top': isFocused }">
      <div class="transition">
        <form action="" class="search-bar">
          <input type="text" 
                 class="form-control col-md-6 shadow-none" 
                 @keyup.prevent="search"
                 @focus="isFocused = true"
                 @blur="isFocused = false"
                 v-model="query" placeholder="Zoeken naar..." name="q"/>
          <button type="submit">X</button>
        </form>
      </div>
    </div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      query: '',
      isFocused: false
    }
  },
  methods: {
    search() {
      console.log(this.query);
      return this.query;
    }
  }
}
</script>

<style>
:root {
  --gray: #808080;
  --lightgray: #f9f9f9;
  --darkgray: #A9A9A9;
  --silver: #C0C0C0;

  --b: 0.1em;
  --c: #C0C0C0;
}

.container {
  width: 100%;
  min-height: 100vh;
  padding: 5%;
  background: var(--lightgray);
  background-position: center;
  background-size: cover;
  display: flex;
  align-items: center;
  justify-content: center;
  position: relative; /* 作为绝对定位元素的父容器 */
}

.transition {
  width: 100%;
  max-width: 700px;
  color: #0000;
  padding-block: var(--b);
  background: 
    linear-gradient(var(--c) 50%,#000 0) 0% calc(100% - var(--_p,0%))/100% 200%,
    linear-gradient(var(--c) 0 0) 0% var(--_p,0%)/var(--_p,0%) var(--b) no-repeat;
  -webkit-background-clip: text,padding-box;
          background-clip: text,padding-box;
  transition: .3s var(--_s,0s) linear,background-size .3s calc(.3s - var(--_s,0s));
}
.transition:hover {
  --_p: 100%;
  --_s: .3s;
}

.search-bar {
  width: 100%;
  max-width: 700px;
  background-color: rgba(255, 255, 255, 0.2) !important;
  display: flex;
  align-items: center;
  border-radius: 60px;
  padding: 10px 20px;
  transition: all 0.3s ease; /* 搜索栏自身过渡动画 */
}

/* 初始居中状态 */
.input-group.centered {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%) scale(1);
  transition: all 0.3s ease; /* 容器过渡动画 */
  width: 100%;
  max-width: 700px;
}

/* 聚焦后顶部缩小状态 */
.input-group.top {
  top: 20px;
  left: 50%;
  transform: translate(-50%, 0) scale(0.8);
  max-width: 560px; /* 匹配scale(0.8)的宽度 */
}

/* 聚焦后内部元素尺寸适配 */
.input-group.top .search-bar {
  padding: 8px 16px;
}
.input-group.top .search-bar input {
  padding: 16px 16px;
  font-size: 16px;
}
.input-group.top .search-bar button {
  width: 48px;
  height: 48px;
  font-size: 14px;
}

.search-bar input {
  background: transparent;
  flex: 1;
  border: 0;
  outline: none;
  padding: 24px 20px;
  font-size: 20px;
  color: var(--darkgray);
  border-top-style: hidden;
  border-right-style: hidden;
  border-left-style: hidden;
  border-bottom-style: groove;
  transition: all 0.3s ease;
}
.search-bar input:focus{
  background: transparent !important;
  flex: 1;
  border: 0;
  outline: none;
  color: var(--darkgray);
  border-top-style: hidden;
  border-right-style: hidden;
  border-left-style: hidden;
  border-bottom-style: groove;
}
::placeholder {
  color: #cac7ff;
}
.search-bar button {
  border: 0;
  border-radius: 50%;
  width: 60px;
  height: 60px;
  background: var(--gray);
  cursor: pointer;
  transition: all 0.3s ease;
}
</style>

关键改动说明

  1. 响应式状态管理

    • 新增isFocused响应式变量,通过@focus和@blur控制状态切换
    • 用:class="{ 'top': isFocused }"替代原生DOM操作,遵循Vue数据驱动理念
  2. 定位与过渡动画

    • 给.container添加position: relative,让搜索栏容器的绝对定位基于页面
    • 给.input-group.centered设置初始居中定位,并添加过渡属性实现平滑动效
    • .input-group.top定义顶部位置和缩放比例,同步调整最大宽度保证布局协调
  3. 内部元素适配

    • 给搜索栏、输入框、按钮都添加过渡动画,确保整体缩放时元素尺寸同步变化
    • 聚焦后调整输入框内边距、字体大小,按钮宽高,保证视觉效果统一

内容的提问来源于stack exchange,提问作者M4xx

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 10:50:46