[重构倒数第30天] - 使用 Vue3 Composition API 重构 JS 选单

前言

该系列是为了让看过Vue官方文件或学过Vue但是却不知道怎麽下手去重构现在有的网站而去规画的系列文章,在这边整理了许多我自己使用Vue重构很多网站的经验分享给读者们。

用 Vue 跟用原生 JS 或是 JQuery 开发差在哪里?

网路上面已经有很多在介绍这些差异的文章了,我在这边我不会去重复太多论述,不过我要在这边讲一个在开发上面最重要的差异就是『以前我们是对DOM直接操作,而Vue我们是对资料去操作』,如果你对这句话不是很能理解,那接下来我们重构的细节,你可要看仔细了 !

接下来我们会使用 Vue3 的 Composition API 来进行web的重构

Vue3

首先我们先来看一般我们不使用 Vue 的话会如何做

html

<div id="app">
  <nav></nav>
</div>

javascript

const NavItemArr = [
  { name: "home", href: "javascript:;" },
  { name: "about", href: "javascript:;" },
  { name: "address", href: "javascript:;" },
  { name: "blog", href: "javascript:;" },
  { name: "works", href: "javascript:;" },
];
let html = "";
for (const nav of NavItemArr) {
  html += `<a href="${nav.href}">${nav.name}</a>`;
}
document.querySelector("nav").innerHTML = html;
const linkAll = document.querySelectorAll("nav > a");
linkAll[0].classList.add("active");
for (const link of linkAll) {
  link.addEventListener("click", (e) => {
    for (const item of linkAll) {
      item.classList.remove("active");
    }
    e.target.classList.add("active");
  });
}

  1. 首先会有选单内容的资料,里面包含有选单的名字以及连结

  2. 然後透过回圈把选单的html 给组起来,然後丢到指定的DOM里面

  3. 先针对预设第一个选单加入active class

  4. 等选单的DOM 渲染完成後,对每个选单监听一个click事件

  5. 点击选单後清除所有选单的active状态,然後对点击的选单加入active class

在这边你会发现我一下子要处理DOM的渲染,一下子也要处理DOM的监听事件,以及选单的切换状态。

再来我们看一下 Vue的版本

<div id="app">
  <nav>
    <a
       v-for="(item, idx) in NavItemArr"
       :key="item.name"
       :href="item.href"
       :class="{ active: activeIdx === idx }"
       @click="handleMenuFn(idx)"
       >
      {{ item.name }}
    </a>
  </nav>
</div>
<script>
  import { ref } from "Vue"; 
  // const { ref } = Vue;   用cdn可以在全域底下取的Vue
  const App = {
    setup() {
      const activeIdx = ref(0);
      
      const NavItemArr = ref([
        { name: "home", href: "javascript:;" },
        { name: "about", href: "javascript:;" },
        { name: "address", href: "javascript:;" },
        { name: "blog", href: "javascript:;" },
        { name: "works", href: "javascript:;" },
      ]);
      
      const handleMenuFn = (idx) => {
        activeIdx.value = idx;
      };
      
      return { activeIdx, NavItemArr, handleMenuFn };
    },
  };
  
  Vue.createApp(App).mount("#app");
</script>
  1. 我们在Vue的部分我们使用了 ref来定义选单的内容资料(NavItemArr)及目前选取的选单的索引(activeIdx),还有我点击选单的时候要执行function (handleMenuFn),然後把我们要在 template 中所使用的资料以及function都放入return 中,让我们可以在 template 中调用。

关於ref 请参考官方文件 https://v3.vuejs.org/api/refs-api.html#refs

  1. 然後我们可以透过 Vue 的模板语法v-for来让我们的<a>依照我们的 NavItemArr 这个阵列里面的资料来渲染相对应的DOM,将选单给产生出来。

我们使用v-for的时候会需要一个key的属性,这个key是需要一个唯一值来让Vue去对应你产生出来的DOM,以方便在你做资料更改的时候去辨识那些DOM是需要被更改,那些不要更改,进而透过最小幅度的消耗来修改画面。
关於key 请参考官方文件 https://v3.cn.vuejs.org/api/special-attributes.html#key

  1. 然後我们在<a>上面绑定@click事件,当点击的时候传入 v-for 回传的索引,透过 handleMenuFn 去改变我们的activeIdx 这个索引。

  2. 然後你会发现透过<a>面的 class 的判断,我去判断 v-for 回传的索引是否有等於我点击选单所传入的值,如果有,代表 activeIdx === idx 这个判断式是成立的,那这时候 active 就会被加入到该<a>身上,以达到我在点击其他选单的时候,active 也会被正确的加入到其他<a>身上。

到这边你会发现一件事,那就是从头到尾我并没有去针对DOM 去做任何的操作,我一直在操作的都是资料,渲染或修改DOM元素的一直都是Vue,不管是我们使用的v-for 以及 class上面的判断,又或是去修改索引的function,这些通通都是在操作资料,这就是用Vue跟用原生JS或JQ开发网站上面最大的不同,这样我们工程师在开发网站功能的时候就可以只专心处理资料的部分,就不用把资料的处理跟DOM的操作绑再一起,就呼应了我一开始说的『以前我们是对DOM直接操作,而Vue我们是对资料去操作』。

这个范例我有放在codepen上,有兴趣的朋友可以看看
https://codepen.io/MikeCheng1208/pen/PomXKZq

转换技术的过程是辛苦的

我们在转换主要开发的技术的时候都会有过渡期,基本上每个人在刚开始的时候都会遇到撞墙期,又或是想太多不敢往前踏出第一步,这种感觉我懂。

举例来说,我最常被问到的问题是上完Vue课程的时候,要如何开始第一步的去用Vue在实际的案子上面去使用,其实可以不用一开始就一定要整个网站全部打掉全部用Vue开始重作,可以先从网站的小区块一步步地慢慢练习,把原本用纯JS或是jQ的地方慢慢地改成Vue,这样子的话一开始的负担才不会太大,慢慢建立熟悉度还有信心,日後再慢慢挑战大规模的使用就好,当你跨过那个过渡期,代表你又更往前了一步。

还有,技术是为了解决问题而存在的,不是说学习了Vue就不需要学习JQ或是原生的JS了,我们在开发或是维护旧专案上面也是会需要看到JQ的code或是在使用Vue的时候都会需要了解许多JS的语法来进行开发,尤其是在写Vue3的时候,像是定义 let 或是 const 的时候你总要知道差别在哪里,在使用Array的时候总要会处理Array的几个函式吧,所以总归一句,都学啦XD

那如果对於Vue3不够熟的话呢?

Ps. 购买的时候请登入或注册该平台的会员,然後再使用下面连结进入网站点击「立即购课」,这样才可以让我获得更多的课程分润,还可以帮助我完成更多丰富的内容给各位。

我有开设了一堂专门针对Vue3从零开始教学的课程,如果你觉得不错的话,可以购买我课程来学习
https://hiskio.com/bundles/9WwPNYRpz?s=tc

那如果对於JS基础不熟的朋友,我也有开设JS的入门课程,可以参考这个课程
https://hiskio.com/bundles/b9Rovqy7z?s=tc

Mike Vue

订阅Mike的频道享受精彩的教学与分享

Mike 的 Youtube 频道
Mike的medium
MIke 的官方 line 帐号,好友搜寻 @mike_cheng


<<:  AI ninja project [day 1] 介绍

>>:  Day1 启蒙

网路是怎样连接的(八)TCP的性能优化(上)

思考重点 TCP具有那些性能优化机制? 滑动窗口的特色? 滑动窗口发生丢包怎麽办? 核心知识 一系列...

Day7-JDK查看正在运行的Java进程工具:jps

前言 在介绍JDK有哪些工具时,第二大列应该是『故障排查、分析、监控和管理工具』,但我想先从监控工具...

Day 25 进入开发者模式

Odoo选单选择 [设定] -> 画面右下角有个 [启用开发者模式], 选下去! 这就完成啦!...

[Day29] Scrum失败经验谈 – 没有经验的Scrum Master

这次最後一个要分享的Scrum失败经验,就是「没有一位具备经验的Scrum Master」,工程团队...

(Day4) 陈述式 /表达式

前言 JavaScript 的语句分成两种 陈述式、表达式,这两种语法区分并不困难,接下来会一一介绍...