vue封裝圓形菜單組件


參考地址:https://www.html5tricks.com/html5-css3-circle-menu.html

 
一、效果

 

二、參考

  上面有一個鏈接地址,我參考了這個插件的源碼,沒有做太多的改變,只是修改為了適合我當前的需求,並且把步驟和思路大概整理了一下。

  因為我本人是個前端小白,對於美僅限於欣賞。

三、第一步

  首先構建一個樣子出來。

<template>
  <div class="wrapper">
    <a href="#" class="show">START</a>
    <ul>
        <!-- 一級列表 -->
        <li>
            <a href="#">A</a>
            <!-- 二級列表 -->
            <ul>
                <li><a href="#">A-1</a></li>
                <li><a href="#">A-2</a></li>
                <li><a href="#">A-3</a></li>
                <li><a href="#">A-4</a></li>
                <li><a href="#">A-5</a></li>
            </ul>
        </li>
        <li>
            <a href="#">B</a>
            <ul>
                <li><a href="#">B-1</a></li>
                <li><a href="#">B-2</a></li>
                <li><a href="#">B-3</a></li>
                <li><a href="#">B-4</a></li>
                <li><a href="#">B-5</a></li>
            </ul>
        </li>
    </ul>
  </div>
</template>
html
<style scoped>
ul{
    list-style: none;
}
a {
  width: 120px;
  height: 120px;
  position: absolute;
  background: rgba(255, 255, 255, 0.9);
  text-align: center;
  text-decoration: none;
  align-items: center;
  justify-content: center;
  border-radius: 120px;
  display: none; /*默認所有的a都不顯示*/
  text-decoration: none;
  color: #333;
  transition: all 1s ease;
  box-shadow: 0 0 15px #222;
  font-family: "segoe ui";
  font-weight: 200;
  font-size: 16px;
}
.wrapper {
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  position: absolute;
}
a.show {
  display: flex !important; /*因為開始設置了a標簽為none,這里重置display可以讓他顯示*/
}
</style>
css

四、第二步

  做環繞效果。

<template>
  <div class="wrapper">
    <a href="#" class="">START</a>
    <ul>
      <!-- 一級列表 -->
      <li>
        <a href="#" class="selected">A</a>
        <!-- 二級列表 -->
        <ul>
          <li>
            <a href="#">A-1</a>
          </li>
          <li>
            <a href="#">A-2</a>
          </li>
          <li>
            <a href="#">A-3</a>
          </li>
          <li>
            <a href="#">A-4</a>
          </li>
          <li>
            <a href="#">A-5</a>
          </li>
        </ul>
      </li>
      <li>
        <a href="#">B</a>
        <ul>
          <li>
            <a href="#">B-1</a>
          </li>
          <li>
            <a href="#">B-2</a>
          </li>
          <li>
            <a href="#">B-3</a>
          </li>
          <li>
            <a href="#">B-4</a>
          </li>
          <li>
            <a href="#">B-5</a>
          </li>
        </ul>
      </li>
    </ul>
  </div>
</template>
html
<style scoped>
ul {
  list-style: none;
}
a {
  width: 120px;
  height: 120px;
  position: absolute;
  background: rgba(255, 255, 255, 0.9);
  text-align: center;
  text-decoration: none;
  align-items: center;
  justify-content: center;
  border-radius: 120px;
  display: none; /*默認所有的a都不顯示*/
  text-decoration: none;
  color: #333;
  transition: all 1s ease;
  box-shadow: 0 0 15px #222;
  font-family: "segoe ui";
  font-weight: 200;
  font-size: 16px;
}
.wrapper {
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  position: absolute;
}
a.show {
  display: flex !important; /*因為開始設置了a標簽為none,這里重置display可以讓他顯示*/
}
/*對所有的li標簽加動畫效果*/
.wrapper li {
  -webkit-transform: translate3d(0, 0, 0); /*調用GPU提升動畫性能*/
  transform: translate3d(0, 0, 0);
  transition: all 1s ease;
  /*下面的方法好像也可以提升性能,具體並沒有比較*/
  /* backface-visibility: hidden;
    perspective: 1000; */
}
/*設置選中樣式*/
.selected {
  background: rgba(51, 51, 51, 0.9);
  display: flex;
  /*調整中心圓形的位置*/
  top: calc(50% - 50px);
  left: calc(50% - 60px);
  color: #f1f1f1;
  animation: light 1s infinite;
}
/*讓當前選中的子集列表顯示*/
.selected + ul > li > a {
    /*讓當前選中的子選項顯示,因為默認是 display:none*/
    display: flex;
}
/*設置 li 的位置,rotate是順/逆時針旋轉,translateX是沿x軸平移*/
.selected + ul > li:nth-child(1) {
    -webkit-transform: rotate(-120deg) translateX(80px);
    transform: rotate(-120deg) translateX(80px);
}
/*設置a標簽內字體的位置,應為容器旋轉后,字體傾斜了,需要調整回來*/
/*這里有一個小技巧:字體的旋轉角度正好和外部容器的旋轉角度相反,但是最后一個的位置需要調整*/
 .selected + ul > li:nth-child(1) > a {
    -webkit-transform: rotate(120deg);
    transform: rotate(120deg);
}

 .selected + ul > li:nth-child(2) {
    -webkit-transform: rotate(-40deg) translateX(80px);
    transform: rotate(-40deg) translateX(80px);
}
 .selected + ul > li:nth-child(2) > a {
    -webkit-transform: rotate(40deg);
    transform: rotate(40deg);
}

 .selected + ul > li:nth-child(3) {
    -webkit-transform: rotate(40deg) translateX(80px);
    transform: rotate(40deg) translateX(80px);
}
 .selected + ul > li:nth-child(3) > a {
    -webkit-transform: rotate(-40deg);
    transform: rotate(-40deg);
}

 .selected + ul > li:nth-child(4) {
    -webkit-transform: rotate(120deg) translateX(120px);
    transform: rotate(120deg) translateX(120px);
}
 .selected + ul > li:nth-child(4) > a {
    -webkit-transform: rotate(-120deg);
    transform: rotate(-120deg);
}
 .selected + ul > li:nth-child(5) {
    -webkit-transform: rotate(180deg) translateX(120px);
    transform: rotate(180deg) translateX(120px);
}
 .selected + ul > li:nth-child(5) > a {
    -webkit-transform: rotate(180deg);
    transform: rotate(180deg);
}
</style>
css

 

五、第三步

  加動畫,以及實現級聯。  

<template>
  <div class="wrapper">
    <a href="#" class="show" @click="Bubblings($event)">START</a>
    <ul>
      <!-- 一級列表 -->
      <li>
        <a href="#" @click="Bubblings($event)">A</a>
        <!-- 二級列表 -->
        <ul>
          <li>
            <a href="#" @click="Bubblings($event)">A-1</a>
          </li>
          <li>
            <a href="#" @click="Bubblings($event)">A-2</a>
          </li>
          <li>
            <a href="#" @click="Bubblings($event)">A-3</a>
          </li>
          <li>
            <a href="#" @click="Bubblings($event)">A-4</a>
          </li>
          <li>
            <a href="#" @click="Bubblings($event)">A-5</a>
          </li>
        </ul>
      </li>
      <li>
        <a href="#" @click="Bubblings($event)">B</a>
        <ul>
          <li>
            <a href="#" @click="Bubblings($event)">B-1</a>
          </li>
          <li>
            <a href="#" @click="Bubblings($event)">B-2</a>
          </li>
          <li>
            <a href="#" @click="Bubblings($event)">B-3</a>
          </li>
          <li>
            <a href="#" @click="Bubblings($event)">B-4</a>
          </li>
          <li>
            <a href="#" @click="Bubblings($event)">B-5</a>
          </li>
        </ul>
      </li>
    </ul>
  </div>
</template>
html
<script>
export default {
    name:'bubbling',
    methods:{
        Bubblings(e){
            //獲取點擊的DOM對象
            let self = e.target
            //檢查點擊的是否是選中的圓
            if (self.classList.contains('selected')) {
                //如果是移除當前選中效果,返回上級菜單
                self.classList.remove('selected')
                //判斷它的父級元素是不是頂級元素
                if (!self.parentNode.classList.contains('wrapper')) {
                    //如果不是頂級元素,展示對應的菜單列表
                    self.parentNode.parentNode.parentNode
                        .querySelector('a')
                        .classList.add('selected')
                } else {
                    //如果是頂級元素,僅顯示最頂級元素
                    self.classList.add('show')
                }
            } else {
                //如果點擊的不是選中的圓
                self.classList.add('selected')
                //判斷是否點擊的是頂級元素
                if (!self.parentNode.classList.contains('wrapper')) {
                    //如果不是頂級元素,展開所點擊的菜單列表
                    // a(self) -> li(parent) -> ul(parent) -> li(parent) -> a(target)
                    self.parentNode.parentNode.parentNode
                        .querySelector('a')
                        .classList.remove('selected')
                } else {
                    //點擊頂級元素展開一級菜單列表
                    self.classList.remove('show')
                }
            }
            return false
        }
    }
}
</script>
script
<style scoped>
ul {
  list-style: none;
}
a {
  width: 120px;
  height: 120px;
  position: absolute;
  background: rgba(255, 255, 255, 0.9);
  text-align: center;
  text-decoration: none;
  align-items: center;
  justify-content: center;
  border-radius: 120px;
  display: none; /*默認所有的a都不顯示*/
  text-decoration: none;
  color: #333;
  transition: all 1s ease;
  box-shadow: 0 0 15px #222;
  font-family: "segoe ui";
  font-weight: 200;
  font-size: 16px;
}
.wrapper {
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  position: absolute;
}
a.show {
  display: flex !important; /*因為開始設置了a標簽為none,這里重置display可以讓他顯示*/
}
/*對所有的li標簽加動畫效果*/
.wrapper li {
  -webkit-transform: translate3d(0, 0, 0); /*調用GPU提升動畫性能*/
  transform: translate3d(0, 0, 0);
  transition: all 1s ease;
  /*下面的方法好像也可以提升性能,具體並沒有比較*/
  /* backface-visibility: hidden;
    perspective: 1000; */
}
/*設置選中樣式*/
.selected {
  background: rgba(51, 51, 51, 0.9);
  display: flex;
  /*調整中心圓形的位置*/
  top: calc(50% - 50px);
  left: calc(50% - 60px);
  color: #f1f1f1;
  animation: light 1s infinite;
}
/*讓當前選中的子集列表顯示*/
.selected + ul > li > a {
  /*讓當前選中的子選項顯示,因為默認是 display:none*/
  display: flex;
}
/*設置 li 的位置,rotate是順/逆時針旋轉,translateX是沿x軸平移*/
.selected + ul > li:nth-child(1) {
  -webkit-transform: rotate(-120deg) translateX(80px);
  transform: rotate(-120deg) translateX(80px);
}
/*設置a標簽內字體的位置,應為容器旋轉后,字體傾斜了,需要調整回來*/
/*這里有一個小技巧:字體的旋轉角度正好和外部容器的旋轉角度相反,但是最后一個的位置需要調整*/
.selected + ul > li:nth-child(1) > a {
  -webkit-transform: rotate(120deg);
  transform: rotate(120deg);
}

.selected + ul > li:nth-child(2) {
  -webkit-transform: rotate(-40deg) translateX(80px);
  transform: rotate(-40deg) translateX(80px);
}
.selected + ul > li:nth-child(2) > a {
  -webkit-transform: rotate(40deg);
  transform: rotate(40deg);
}

.selected + ul > li:nth-child(3) {
  -webkit-transform: rotate(40deg) translateX(80px);
  transform: rotate(40deg) translateX(80px);
}
.selected + ul > li:nth-child(3) > a {
  -webkit-transform: rotate(-40deg);
  transform: rotate(-40deg);
}

.selected + ul > li:nth-child(4) {
  -webkit-transform: rotate(120deg) translateX(120px);
  transform: rotate(120deg) translateX(120px);
}
.selected + ul > li:nth-child(4) > a {
  -webkit-transform: rotate(-120deg);
  transform: rotate(-120deg);
}
.selected + ul > li:nth-child(5) {
  -webkit-transform: rotate(180deg) translateX(120px);
  transform: rotate(180deg) translateX(120px);
}
.selected + ul > li:nth-child(5) > a {
  -webkit-transform: rotate(180deg);
  transform: rotate(180deg);
}
</style>
css

六、第四步

  綁定數據,以及完整代碼。

<template>
  <div class="wrapper">
    <a href="#" class="show" @click="Bubblings($event)">START</a>
    <ul>
      <!-- 一級列表 -->
      <li v-for="(item,index) of list" :key="index">
        <a href="#" @click="Bubblings($event)">{{ item.name }}</a>
        <!-- 二級列表 -->
        <ul>
          <li v-for="(child,index) of item.childs" :key="index">
            <a href="#" @click="Bubblings($event)">{{ child.name }}</a>
          </li>
        </ul>
      </li>
    </ul>
  </div>
</template>
<script>
export default {
    name:'bubbling',
    data(){
        return {
            list:[
                {
                    name:'A',
                    childs:[
                        {
                            name:'A-1'
                        },
                        {
                            name:'A-2'
                        },
                        {
                            name:'A-3'
                        }
                    ]
                },
                {
                    name:'B',
                    childs:[
                        {
                            name:'B-1'
                        },
                        {
                            name:'B-2'
                        },
                        {
                            name:'B-3'
                        }
                    ]
                }
            ]
        }
    },
    methods:{
        Bubblings(e){
            //獲取點擊的DOM對象
            let self = e.target
            //檢查點擊的是否是選中的圓
            if (self.classList.contains('selected')) {
                //如果是移除當前選中效果,返回上級菜單
                self.classList.remove('selected')
                //判斷它的父級元素是不是頂級元素
                if (!self.parentNode.classList.contains('wrapper')) {
                    //如果不是頂級元素,展示對應的菜單列表
                    self.parentNode.parentNode.parentNode
                        .querySelector('a')
                        .classList.add('selected')
                } else {
                    //如果是頂級元素,僅顯示最頂級元素
                    self.classList.add('show')
                }
            } else {
                //如果點擊的不是選中的圓
                self.classList.add('selected')
                //判斷是否點擊的是頂級元素
                if (!self.parentNode.classList.contains('wrapper')) {
                    //如果不是頂級元素,展開所點擊的菜單列表
                    // a(self) -> li(parent) -> ul(parent) -> li(parent) -> a(target)
                    self.parentNode.parentNode.parentNode
                        .querySelector('a')
                        .classList.remove('selected')
                } else {
                    //點擊頂級元素展開一級菜單列表
                    self.classList.remove('show')
                }
            }
            return false
        }
    }
}
</script>
<style scoped>
ul {
  list-style: none;
}
a {
  width: 120px;
  height: 120px;
  position: absolute;
  background: rgba(255, 255, 255, 0.9);
  text-align: center;
  text-decoration: none;
  align-items: center;
  justify-content: center;
  border-radius: 120px;
  display: none; /*默認所有的a都不顯示*/
  text-decoration: none;
  color: #333;
  transition: all 1s ease;
  box-shadow: 0 0 15px #222;
  font-family: "segoe ui";
  font-weight: 200;
  font-size: 16px;
}
.wrapper {
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  position: absolute;
}
a.show {
  display: flex !important; /*因為開始設置了a標簽為none,這里重置display可以讓他顯示*/
}
/*對所有的li標簽加動畫效果*/
.wrapper li {
  -webkit-transform: translate3d(0, 0, 0); /*調用GPU提升動畫性能*/
  transform: translate3d(0, 0, 0);
  transition: all 1s ease;
  /*下面的方法好像也可以提升性能,具體並沒有比較*/
  /* backface-visibility: hidden;
    perspective: 1000; */
}
/*設置選中樣式*/
.selected {
  background: rgba(51, 51, 51, 0.9);
  display: flex;
  /*調整中心圓形的位置*/
  top: calc(50% - 50px);
  left: calc(50% - 60px);
  color: #f1f1f1;
  animation: light 1s infinite;
}
/*讓當前選中的子集列表顯示*/
.selected + ul > li > a {
  /*讓當前選中的子選項顯示,因為默認是 display:none*/
  display: flex;
}
/*設置 li 的位置,rotate是順/逆時針旋轉,translateX是沿x軸平移*/
.selected + ul > li:nth-child(1) {
  -webkit-transform: rotate(-120deg) translateX(80px);
  transform: rotate(-120deg) translateX(80px);
}
/*設置a標簽內字體的位置,應為容器旋轉后,字體傾斜了,需要調整回來*/
/*這里有一個小技巧:字體的旋轉角度正好和外部容器的旋轉角度相反,但是最后一個的位置需要調整*/
.selected + ul > li:nth-child(1) > a {
  -webkit-transform: rotate(120deg);
  transform: rotate(120deg);
}

.selected + ul > li:nth-child(2) {
  -webkit-transform: rotate(-40deg) translateX(80px);
  transform: rotate(-40deg) translateX(80px);
}
.selected + ul > li:nth-child(2) > a {
  -webkit-transform: rotate(40deg);
  transform: rotate(40deg);
}

.selected + ul > li:nth-child(3) {
  -webkit-transform: rotate(40deg) translateX(80px);
  transform: rotate(40deg) translateX(80px);
}
.selected + ul > li:nth-child(3) > a {
  -webkit-transform: rotate(-40deg);
  transform: rotate(-40deg);
}

.selected + ul > li:nth-child(4) {
  -webkit-transform: rotate(120deg) translateX(120px);
  transform: rotate(120deg) translateX(120px);
}
.selected + ul > li:nth-child(4) > a {
  -webkit-transform: rotate(-120deg);
  transform: rotate(-120deg);
}
.selected + ul > li:nth-child(5) {
  -webkit-transform: rotate(180deg) translateX(120px);
  transform: rotate(180deg) translateX(120px);
}
.selected + ul > li:nth-child(5) > a {
  -webkit-transform: rotate(180deg);
  transform: rotate(180deg);
}
</style>

七、總結

  更多的是對CSS動畫的操作,以及DOM的結構和布局。歡迎留言討論。

 

謙良恭卑,信誠實至;生活不易,共勉同求。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM