<template>
<div class="header">
<ul>
<span
:style="{ left: positionToMove, width: sliderWidth }"
></span>
<li
v-for="menu in menuList"
:key="menu.name"
@click="menuMove(menu.name)"
:ref="menu.name"
:class="{'active':selectedIndex === menu.name}"
>
{{ menu.name }}
</li>
</ul>
</div>
</template>
<script>
export default {
name: "Menu",
data() {
return {
sliderPosition: 15,
selectedElementWidth: 78,
selectedIndex: "Home",
menuList: [
{ name: "Home" },
{ name: "About" },
{ name: "Product" },
{ name: "Contact" },
],
};
},
methods: {
menuMove(name) {
let el = this.$refs[`${name}`][0];
this.sliderPosition = el.offsetLeft;
this.selectedElementWidth = el.offsetWidth;
this.selectedIndex = name;
},
},
computed: {
positionToMove() {
return this.sliderPosition + "px";
},
sliderWidth() {
return this.selectedElementWidth + "px";
},
},
};
</script>
<style>
.header {
width: 400px;
position: fixed;
top: 350px;
left: 50%;
transform: translate(-50%, 0);
}
.header ul {
width: 100%;
display: flex;
align-items: center;
background: #fff;
justify-content: center;
gap: 20px;
border-radius: 20px;
padding: 10px 15px;
}
.header ul li {
width: 100%;
display: flex;
align-items: center;
justify-content: center;
gap: 100px;
border-radius: 15px;
padding: 10px 0;
font-size: 0.8rem;
position: relative;
z-index: 1;
cursor: pointer;
}
.header ul .active {
color:#fff;
transition:all 1.0s ease;
}
.header ul span {
background: #4577f6;
height: 30px;
display: inline-block;
position: absolute;
z-index: 0;
border-radius: 15px;
cursor: pointer;
transition:all 0.3s ease-in;
}
</style>
이것의 단점은 반응형에서 제대로 동작하지 않는 다는 점이다.
<template>
<div class="ranking-wrap">
<div class="btn-wrap">
<button v-for="item in menuRanking" :key="item.name" @click="slideMenuBg(item.name)" :class="{ active : currentMenu == item.name}">
{{ item.name }}
</button>
<span :style="{transform: moveLeft}"></span>
</div>
</div>
</template>
<script>
export default {
name: "Ranking",
data() {
return {
menuRanking: [{ name: "유저 랭킹" }, { name: "선수 랭킹" }],
moveLeft: 0,
currentMenu: '유저 랭킹'
};
},
methods: {
slideMenuBg(name){
this.currentMenu = name;
if(name == "유저 랭킹"){
this.moveLeft = 'translateX(0)';
}else{
this.moveLeft = 'translateX(100%)';
}
}
},
};
</script>
<style>
.ranking-wrap {
width: 800px;
margin: 300px auto 0 auto;
}
.ranking-wrap .btn-wrap{
display:grid;
grid-template-columns: 1fr 1fr;
position: relative;
border:1px solid #eee;
}
.ranking-wrap .btn-wrap span{
height:40px;
width:50%;
background:#00b776;
position:absolute;
transition:0.3s ease-in-out;
z-index: -1;
}
.ranking-wrap .btn-wrap button{
max-width: 100%;
background:none;
height:40px;
display:flex;
align-items:center;
justify-content:center;
cursor: pointer;
border:none;
color:#d5d8db;
}
.ranking-wrap .btn-wrap .active{
color:#fff;
transition:0.5s ease-in-out;
}
</style>
if문과 bg의 width를 퍼센테이지로 주니 잘 됨.
그러나 메뉴 리스트가 늘어났을 때 if로 하면 너무 지저분 할 것 같음.