js+css makes navigation bar underline follow animation, App+H5 click effect

2023.2.7 update

This approach has many flaws. There are other better solutions, which have been updated in the new article. Interested friends can go to the new article to read↓

js+css makes navigation bar underline follow animation, adaptive element size change, custom underline style, Vue/Uniapp_Chiba KE's blog-CSDN blog navigation bar underline follow animation, adaptive element size change, custom underline stylehttps ://blog.csdn.net/qq1219579255/article/details/128822806


This is an underscore following effect made with Vue, no other plugins are used

Table of contents

1. Make an initial navbar

2. Add click style

3. Underline movement

final code

Precautions


This is the final effect


At the beginning, I checked other people's practices from the Internet, and most of them were realized by using the lower border, or the method of pseudo element + border.

If you simply use the border, the length of the border changes according to the length of the option content, which is not particularly good. Although it can be solved by writing a border in a pseudo-element, I think there is a disadvantage in doing so, that is, the border line cannot be set Rounded corners, so the aesthetics will be a little bit...

Back to the topic, I realized it like this↓


1. Make an initial navbar

<body>
    <div id="app">
      <div class="nav">
        <!-- 标题列表 -->
        <div class="nav-list">
          <div v-for="(item, index) in navList" :key="index">{
   
   { item }}</div>
        </div>
        <!-- 下划线 -->
        <div class="nav-line"></div>
      </div>
    </div>
</body>
<script>
    var vm = new Vue({
      el: "#app",
      data: {
        navList: ["首页", "头条", "特惠", "财经", "动漫"],
      },
    });
</script>
<style>
    * {
      box-sizing: border-box;
      padding: 0;
      margin: 0;
    }

    .nav {
      position: relative;
    }

    .nav-list {
      width: 100%;
      height: 50px;
      display: flex;
      justify-content: space-around;
      align-items: center;
    }

    .nav-line {
      width: 18px;
      height: 4px;
      border-radius: 2px;
      background-color: red;
      position: absolute;
      bottom: 0;
    }
</style>

The effect shown above is this


 2. Add click style

First of all, we need to add a click event to each option in the navigation, and then make the clicked item change color when clicked

  • Add event and dynamic class in HTML part
<div class="nav-list">
    <div v-for="(item, index) in navList" :key="index" @click="click(index)" :class="{ active : index==current }">{
   
   { item }}</div>
</div>
  •  Add variables and methods to Vue instances
data: {
        navList: ["首页", "头条", "特惠", "财经", "动漫"],
        current: 0,
},
methods: {
        // 点击时执行
        click(index) {
          this.current = index;
          this.lineMove();
        },
        // 计算下划线应该移动的距离
        lineMove() {
          
        },
},
  •  Add style to CSS part
.active {
      color: red;
      font-weight: bold;
}

Then we get something like this


After completing the first two steps, the font color has changed, and the next step is to make the underline move along with it

3. Underline movement

  • Add dynamic style to underline in HTML part

Because absolute positioning has been added to the underline before, you can use the left property for displacement here

<div class="nav-line" :style="{left:X+'px',transform : 'translateX(-50%)'}"></div>

Of course, you can also not use left, and only use translateX() that changes the attribute transform to achieve the same effect↓

<!-- 只使用transform的写法 -->
<div class="nav-line" :style="{transform : `translateX(${X}px) translateX(-50%)`}"></div>

Note that translateX() must be wrapped in quotation marks ' ' or template string ``, otherwise an error will be reported. translateX(-50%) is to move the underline to the left by 50% to ensure alignment. Everyone should understand this

  • Add variable X and method lineMove in Vue instance
data: {
        navList: ["首页", "头条", "特惠", "财经", "动漫"],
        X: 0,
        current: 0,
},
methods: {
        // 点击时执行
        click(index) {
          this.current = index;
          this.lineMove();
        },
        // 计算下划线应该移动的距离
        lineMove() {
          // 导航栏的宽度,因为是100%所以就是屏幕宽度
          let width = document.body.clientWidth;
          // 每个选项栏的宽度 = 导航栏宽度/选项个数
          let divWidth = width / this.navList.length;
          // 半个选项栏宽度
          let halfDivWidth = divWidth / 2;
          // 下划线移动的距离 = 半个选项栏宽度 + (单个选项栏宽度*当前index)
          this.X = halfDivWidth + divWidth * this.current;
        },
 }, 

Here let width = the width of .nav-list, because we defined the width of .nav-list as 100% in css before, so I got the current screen width in the example.

  • CSS adds transition effect to underline
.nav-line {
      width: 18px;
      height: 4px;
      border-radius: 2px;
      background-color: red;
      position: absolute;
      bottom: 0;
      transition: 0.3s all;
    }

get the effect

 After doing this, you can see that the effect has been realized, but there is still a small problem - the underline position is wrong when the page is initialized, it is on the leftmost side of the screen and half of it overflows the screen, the reason is also obvious, the initial value we set for variable X is 0.

Solve the problem: execute the lineMove method once in the life cycle created

created() {
        // 避免页面初始化会有显示问题,初始加载时就执行一次该方法
        this.lineMove();
      },

Note: It is recommended to execute in the created cycle, not in the mounted cycle, because mounted is executed after the initial loading of the page is completed, so when executed in mounted, we will see the underline briefly stay on the left side of the screen at the beginning.

Get the final effect ↓


final code

  <body>
    <div id="app">
      <div class="nav">
        <!-- 标题列表 -->
        <div class="nav-list">
          <div v-for="(item, index) in navList" :key="index" @click="click(index)" :class="{ active : index==current }">{
   
   { item }}</div>
        </div>
        <!-- 下划线 -->
        <div class="nav-line" :style="{left:X+'px',transform : 'translateX(-50%)'}"></div>
        <!-- <div class="nav-line" :style="{transform : `translateX(${X}px) translateX(-50%)`}"></div> -->
      </div>
    </div>
  </body>
  <script>
    var vm = new Vue({
      el: "#app",
      data: {
        navList: ["首页", "头条", "特惠", "财经", "动漫"],
        X: 0,
        current: 0,
      },
      methods: {
        // 点击时执行
        click(index) {
          this.current = index;
          this.lineMove();
        },
        // 计算下划线应该移动的距离
        lineMove() {
          // 导航栏的宽度,因为是100%所以就是屏幕宽度
          let width = document.body.clientWidth;
          // 每个选项栏的宽度 = 导航栏宽度/选项个数
          let divWidth = width / this.navList.length;
          // 半个选项栏宽度
          let halfDivWidth = divWidth / 2;
          // 下划线移动的距离 = 半个选项栏宽度 + (单个选项栏宽度*当前index)
          this.X = halfDivWidth + divWidth * this.current;
        },
      },
      created() {
        // 避免页面初始化会有显示问题,初始加载时就执行一次该方法
        this.lineMove();
      },
    });
  </script>
  <style>
    * {
      box-sizing: border-box;
      padding: 0;
      margin: 0;
    }

    .nav {
      position: relative;
    }

    .nav-list {
      width: 100%;
      height: 50px;
      display: flex;
      justify-content: space-around;
      align-items: center;
    }

    .active {
      color: red;
      font-weight: bold;
    }

    .nav-line {
      width: 18px;
      height: 4px;
      border-radius: 2px;
      background-color: red;
      position: absolute;
      bottom: 0;
      transition: 0.3s all;
    }
  </style>

Precautions

  1. The flex style of the navigation bar.nav -list  must use  justify-content: space-around;  otherwise, the subsequent calculation of the underline movement distance will be inaccurate
  2. You can define the style of the underline, or use the background-image attribute to make a gradient underline
  3. If the number (length) of the options in the navigation bar is different, the movement of the underline will also be inaccurate. It is best to unify the number (length) of the options, or each master can solve it by himself
  4. Welcome to leave a message, don't spray if you don't like it

Guess you like

Origin blog.csdn.net/qq1219579255/article/details/123486955