vue 슬라이드 메뉴

해적왕·2022년 12월 4일
0
post-custom-banner

<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로 하면 너무 지저분 할 것 같음.

profile
프론트엔드
post-custom-banner

0개의 댓글