preface

The summary of the last interview, we look at the line, because the amount is very large, mistakes are inevitable, I hope you can tell me if you find mistakes, my email is [email protected], a small front-end hope.

Get to the point

As usual, we’ll go straight to the renderings and then start today’s sharing of the project on Github

Component analysis

  1. An interface
  2. Logical analysis
  3. Finally realize
An interface

From the figure above, we can see that the interface is mainly divided into Menu and Item2. The animation of Menu is autobiography, and the animation of Item is displacement. Then, we position the whole control in four corners through absolute layout

.menu_container {
    position: absolute;
    z-index: 100;
    border-radius: 50%;
    transition-duration: 400ms;
    text-align: center;
    border: #efefef 3px solid;
    box-shadow: aliceblue 1px 1px 1px;
  }

  .menu_item {
    position: absolute;
    border-radius: 50%;
    z-index: 99;
    border: #efefef 3px solid;
    text-align: center;
    box-shadow: aliceblue 1px 1px 1px;
  }
Copy the code
Logical analysis

Here, I will separate several properties of this control for the convenience of next development, including the background of menu, which corner of the whole control on the screen, the width and height of menu, the distance between item and Menu displacement, the background color of Menu, and the background color of item. The related content of item is controlled by data. The details will be explained directly in the implementation below.

Finally realize

I’m going to use code and comments here to help you understand, and TEMPLATE is just a little bit of an introduction

<div>
    <div class="menu_container" ref="menuHome" @click="toggleMenu">
      <img :src="menuSrc"><! - menu figure -- -- >
    </div>
    <div class="menu_item" v-for="(item,index) in menuItems" :id="item.name" @click="clickMenu(item,index)">
      <img :src="item.src"><! - item figure -- -- >
    </div>
  </div>
Copy the code

Through analysis of the core implementation, it can be concluded that the offset of each item should be horizontal X: base value * sin(Angle value) Vertical Y: base value * cos(Angle value) Angle value: (length of array -1- current subscript) * Angle occupied by each piece * radian indicates that radian indicates: 2 * Math.PI / 360

export default{... props: {// Open attributes for easy customization
      menuSrc: {
        default: require('.. /assets/menu.png')},position: {
        default: 'LT'// Select LT, LB, RT, RB4 corners
      },
      width: {
        default: 50,},baseDistance: {
        default: 150,},menuBg: {
        default: 'white'
      },
      itemBg: {
        default: 'white'
      },
      menuItems: {
        type: Array,
      }
    },
    data() {
      return {
        openFlag: false.// Expand the merge flag
        operators: ['+'.'+'].// record the XY direction of the animation as it unfolds
      }
    },
    mounted() {
      // Initialize various styles for each content according to props
      this.$refs.menuHome.style.width = this.width + 'px';
      this.$refs.menuHome.style.height = this.width + 'px';
      this.$refs.menuHome.style.lineHeight = this.width + 'px';
      this.$refs.menuHome.style.background = this.menuBg;
      this.menuItems.forEach((item) = > {
        let el = document.getElementById(item.name);
        el.style.width = `The ${this.width * 0.8}px`;
        el.style.height = `The ${this.width * 0.8}px`;
        el.style.lineHeight = `The ${this.width * 0.8}px`;
        el.style.background = this.itemBg;
      });
      // Select different positions according to position
      switch (this.position) {
        case 'LT':
          this.$refs.menuHome.style.left = '20px';
          this.$refs.menuHome.style.top = '20px';
          this.menuItems.forEach((item) = > {
            let el = document.getElementById(item.name);
            el.style.left = '26px';
            el.style.top = '26px';

          });
          this.operators = ['+'.'+'];
          break; . }},methods: {
      toggleMenu() {
        if (!this.openFlag) {// To merge, click expand
          this.menuItems.forEach((item, index) = > {
            this.toggleMenuTransition(item.name, index, false)});// Menu itself rotates once
          this.$refs.menuHome.style.transform = 'rotate(360deg)';
        } else {
          this.menuItems.forEach((item, index) = > {
            this.toggleMenuTransition(item.name, index, true)});/ / the menu
          this.$refs.menuHome.style.transform = 'rotate(0)';
        }
        this.openFlag = !this.openFlag;
      },
      toggleMenuTransition(name, index, revert) {
        let oneArea = 90 / (this.menuItems.length - 1);// The Angle occupied by each piece
        let axisX = Math.sin((this.menuItems.length - 1 - index) * oneArea * 2 * Math.PI / 360);// The scale offset by the abscissa
        let axisY = Math.cos((this.menuItems.length - 1 - index) * oneArea * 2 * Math.PI / 360);// The ratio of cheapness on the y-coordinate
        let el = document.getElementById(name);// If the name is always passed, an error will be reported.
        let that = this;
        if(! revert) { setTimeout(function () {
            el.style.transitionDuration = '200ms';
            el.style.transform = `translate(${that.operators[0]}${that.baseDistance * axisX}px,${that.operators[1]}${that.baseDistance * axisY }px)`;// Animate
          }, index * 100)// Through the timer mode, to achieve a pop-up effect
        } else {
          / / the item back
          el.style.transitionDuration = '200ms';
          el.style.transform = ` ` translate (0, 0);
        }
      },
      clickMenu(item, index) {
        // Expose the method to the parent component for the click event operation
        this.$emit('clickMenu', item, index)
      }
    }
  }
Copy the code

Add it to the parent component and you’re done. Dance for a while to burn off your calories

Parent component call

The introduction of the component

import toggleMenu from './toggleMenu'
Copy the code

The components statement

components: {
     toggleMenu
},
Copy the code

The template used in

{name: 'menu1', SRC: require('../assets/emoji.png')}, {name: 'menu2', SRC: {name: 'menu2', SRC: require('../assets/cart.png')}, {name: 'menu3', src: require('../assets/folder.png')}, {name: 'menu4', src: require('../assets/home.png')}, {name: 'menu5', src: require('../assets/my.png')}, ] <toggle-menu :menuItems="menuItems" @clickMenu="clickMenu" ></toggle-menu>Copy the code

Properties and methods column

The property name use The default value Whether must
position Four directions (LT, LB, RT, RB) LT no
menuBg Menu background white no
menuSrc Menu pictures A menu image no
itemBg Button background white no
width Width of the button 50px no
baseDistance Displacement distance, if there are many items, can be appropriately increased 150px no
menuItems Menu array There is no is
The method name use parameter
clickMenu Clicking on item triggers the event item,index

Okay, so that’s about it,

My Github, ask stamp, ask star