Vue开发前端导航栏设计【常见问题+示例代码】
书接上回
上一次在文章中,我们讲解了Vue前端的容器搭建,在本文中,我们将继续细化设计,逐步完成一个较为完善的导航栏。
组件引用
组件引用是为了在较大规模开发时避免代码塞在一个文件里边,增加可读性。
在引用的主文件里的 js部分import,然后直接在 tmplate部分调用即可,代码如下
<template>
<div>
<navigator></navigator>
</div>
</template>
<style scoped>
</style>
<script setup>
// 导入组件
import navigator from "@/page/navigator/navigator.vue"
</script>
在需要被调用的组件中,记得一定要有<script setup>部分
<template>
<div class="navigator">
</div>
</template>
<style scoped>
</style>
<script setup>
</script>
调试浏览器,发现调用成功
导航栏框架搭建
这里提供一个简单的导航栏框架设计,本文将详细讲解微调过程。
先展示初版效果:
提几个要点:
- 导航栏可以做个下端阴影,这样就算全白也会有区分度,看起来比较舒服
- 搜索框的border可以粗一点弄成圆的,用的element-plus组件所以需要使用::deep贯穿
<template>
<div class="navigator">
<div class="logo">
<img src="../../asset/board/logo.png" style="height:400%;margin-top: -21%;margin-left: 15%;user-select: none;">
</div>
<div class="search">
<el-input
v-model="keyword"
placeholder="请输入搜索内容"
suffix-icon="Search"
class="round-input"
style="width:100%; height:60%; margin-top:3%">
</el-input>
</div>
<div class="selectionSet">
<el-tabs v-model="activeName" class="demo-tabs" @tab-click="handleClick" style="margin-top: 3%;margin-left: 10%">
<el-tab-pane label="首页" name="first"> </el-tab-pane>
<el-tab-pane label="资料库" name="second"> </el-tab-pane>
<el-tab-pane label="讨论区" name="third"> </el-tab-pane>
<el-tab-pane label="收藏夹" name="fourth"> </el-tab-pane>
</el-tabs>
<img src="../../asset/board/碳治郎1.png"
style="height:90%;margin-left: 10%;margin-top: 0.5%">
</div>
</div>
</template>
<style scoped>
.navigator {
display: flex;
align-items: center;
/* background-color: #d5e4f4;*/
background-color: #ffffff;
height: 9%;
/* 添加底部阴影效果 */
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
}
.logo {
width: 30%;
height: 100%;
display: flex;
padding-left: 3%;
}
.search {
display: flex;
width: 30%;
height: 100%;
}
:deep(.round-input .el-input__wrapper) {
border-radius: 20px !important;
background-color: #FFFFFF;
box-shadow: 0 0 0 1.5px rgb(210, 203, 241) !important;
}
.selectionSet {
display: flex;
width: 40%;
height: 100%;
}
:deep(.el-tabs__item) {
color: #000000;
font-size: 25px;
transition: color 0.3s ease;
}
::v-deep .el-tabs__active-bar {
background-color: #064fe1 !important;
}
:deep(.el-tabs__nav-wrap::after) {
position: static !important;
}
</style>
<script setup>
import { ref } from 'vue';
const keyword = ref('');
const activeName = ref('first');
const handleClick = (tab) => {
console.log(' 当前选中标签:', tab.name);
};
</script>
图片文字取消点击光标闪烁
比如点击右上tab,发现光标是闪烁的,看的很不舒服,这里可以内联为元素设置一下
之后就不可选中了,图像貌似不可以这样解决,可以给图像设计一个点击跳转或点击放大,就不会出现光标闪烁了
user-select: none
输入框偏斜
如题所示,解决方案为在外边包的div上设置user-select:none ;这个偏斜实际上是选中了这个div
输入框悬停和聚焦流光动画
以下展示为全代码,方便CV
<template>
<div class="navigator">
<div class="logo">
<img src="../../asset/board/logo.png" style="height:100%;margin-left: 20%;">
</div>
<div class="search">
<el-input
v-model="keyword"
placeholder=" biuuuu~ 灵 光 乍 现"
suffix-icon="Search"
:class="{ 'round-input':true,'animated-placeholder': isSearchHover,'is-focused': isFocused }"
style="width:100%; height:60%; margin-top:3%"
@focus="handleFocus"
@blur="handleBlur"
>
</el-input>
</div>
<div class="selectionSet">
<el-tabs v-model="activeName" class="demo-tabs" @tab-click="handleClick" style="margin-top: 3%;margin-left: 13%">
<el-tab-pane label="首页" name="first"> </el-tab-pane>
<el-tab-pane label="资料库" name="second"> </el-tab-pane>
<el-tab-pane label="讨论区" name="third"> </el-tab-pane>
<el-tab-pane label="收藏夹" name="fourth"> </el-tab-pane>
</el-tabs>
<img src="../../asset/board/碳治郎1.png"
style="height:90%;margin-left: 10%;margin-top: 0.5%;user-select: none;">
</div>
</div>
</template>
<style scoped>
.navigator {
display: flex;
align-items: center;
background-color: #ffffff;
height: 9%;
/* 添加底部阴影效果 */
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
}
.logo {
width: 30%;
height: 100%;
display: flex;
padding-left: 3%;
}
.search {
display: flex;
width: 30%;
height: 100%;
user-select: none;
}
:deep(.round-input .el-input__wrapper) {
border-radius: 20px !important;
background-color: #FFFFFF;
box-shadow: 0 0 0 1.5px rgb(210, 203, 241) !important;
}
.selectionSet {
display: flex;
width: 40%;
height: 100%;
}
:deep(.el-tabs__item) {
color: #000000;
font-size: 20px;
transition: color 0.4s ease;
user-select: none;
}
::v-deep .el-tabs__active-bar {
background-color: rgb(2, 90, 255) !important;
}
:deep(.el-tabs__nav-wrap::after) {
position: static !important;
}
@keyframes placeholderSlide {
0% { transform: translateX(0); opacity: 0.6 }
100% { transform: translateX(-10px); opacity: 0.2 }
}
:deep(.round-input .el-input__wrapper) {
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); /* 平滑过渡 */
}
/* 悬停状态增强 */
:deep(.round-input:hover .el-input__wrapper) {
box-shadow: 0 0 0 2px rgba(2, 90, 255, 0.3) !important;
transform: scale(1.02);
}
/* 聚焦状态动画 */
:deep(.round-input.is-focused .el-input__wrapper) {
box-shadow: 0 0 0 3px rgba(2, 90, 255, 0.2) !important;
background-color: #f8f9fa;
}
/* 动态placeholder动画 */
.animated-placeholder::placeholder {
font-size: 14px;
transition: all 0.3s ease;
text-align: center;
}
/* 悬停时placeholder动画 */
:deep(.round-input:hover) .animated-placeholder::placeholder {
animation: placeholderSlide 0.8s infinite alternate;
text-align: left;
padding-left: 28px;
}
/* 聚焦时placeholder消失动画 */
:deep(.round-input:focus-within) .animated-placeholder::placeholder {
opacity: 0;
transform: translateX(20px);
transition: all 0.2s ease;
}
@keyframes streaming-light {
0% { background-position: 0% 50%; }
50% { background-position: 100% 50%; }
100% { background-position: 0% 50%; }
}
/* 流光容器 */
:deep(.round-input) .el-input__wrapper {
position: relative;
overflow: hidden;
transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
}
/* 流光伪元素 */
:deep(.round-input) .el-input__wrapper::after {
content: '';
position: absolute;
top: -2px;
left: -2px;
right: -2px;
bottom: -2px;
background: linear-gradient(
45deg,
rgba(2,90,255,0.1) 0%,
rgba(255,255,255,0.8) 25%,
rgba(2,90,255,0.3) 50%,
rgba(255,255,255,0.8) 75%,
rgba(2,90,255,0.1) 100%
);
background-size: 400% 400%;
opacity: 0;
z-index: 1;
transition: opacity 0.8s ease;
pointer-events: none;
border-radius: 22px;
}
/* 触发动画的条件 */
:deep(.round-input.is-focused) .el-input__wrapper::after,
:deep(.round-input:hover) .el-input__wrapper::after {
opacity: 1;
animation: streaming-light 8s linear infinite;
}
/* 输入框内容层提升层级 */
:deep(.el-input__inner) {
position: relative;
z-index: 2;
background: transparent !important;
}
</style>
<script setup>
import { ref } from 'vue';
let isSearchHover=ref(false);
let isFocus=ref(false);
const keyword = ref('');
const activeName = ref('first');
const isFocused = ref(false);
const handleFocus = () => {
isFocused.value = true;
};
const handleBlur = () =>
{
isFocused.value = false;
};
</script>
总结
本文中实现了一个前端代码比较完善的Nav开发,展示了各种可能遇到的问题,希望能对读者有所帮助