vue3公司自用專案實戰入門(vue3+router4+antdv+pinia實現)

彬哥頭髮多發表於2023-01-02

一.為什麼學typescript

var三大框架都是用ts寫的,做個類比,如果你不知道阿拉伯數字和加減法,怎麼解應用題?同理不會ts如何使用vue開發工作專案?

二.開發環境準備

1.安裝node,https://nodejs.org/en/,下載安裝,一路預設下一步 ,輸入node -v顯示版本成功

2.安裝ts,npm install -g typescript,輸入tsc -v顯示版本 說明成功

3.安裝vscode https://code.visualstudio.com/

三.新建一個Helloworld 資料夾,用vscode開啟,然後新建app.ts,裡面就寫一句

console.log('hello world')

然後在vscode 終端輸入 tsc app.ts ,如果報錯 先輸入 set-ExecutionPolicy RemoteSigned

最後看到生成一個編譯同名app.js說明成功了。你說我想看看列印效果,整個index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="app.js"></script>
</head>
<body>
    
</body>
</html>

console.log('hello world')改成console.log('真香')終端按上箭頭,重新tsc app.ts,看瀏覽器控制檯,能看到真香。

三、typescript基礎知識

1.模組管理

傳統教程該講資料型別了,我們先放放直接將核心的模組管理,因為基礎的資料型別number string 不講你也會,高階的資料型別講到了現在你也不明白怎麼用。就說一件事,ts下怎麼定義各種資料型別省的遇見ts裡面型別報錯,你就懵圈了,這裡跟js是不一樣的。

就簡要提一嘴,常見的就是定義陣列:

let num = 0;
let str = '彬哥好帥';
//上面的沒區別,下面說不一樣的
//js這麼寫是沒問題的:

//定義陣列,第一種:
let person: string[] = ['張三', '帥彬'];
//第一種有個缺點,比如我要處理一個陣列過程中split的時候,可能會出現,[1,'張三',2,'帥彬'],這樣你定義成string就報錯兩種型別
let worker: [number, string] = [1, "張三",2,"帥彬"];
//記住以上兩種陣列就夠用了,接下來我們說說陣列裡面套物件{},這個最常用,以前我們在js下定義一個陣列含物件
//js下
let worker = [
    {1, "張三"},
    {2, "帥彬"}  
];

//ts下 這樣寫
interface Worker {
  id: number;
  name: string;
}
let worker: Worker[] = [
  { id: 1, name: "張三" },
  { id: 2, name: "帥彬" }
];
//你在專案中很可能遇到一種情況就是你透過物件的key的值去索引物件的value,比如worker[//這裡是什麼也可能是動態的變數],
//這種情況怎麼定義?
interface Worker {
  id: number;
  [key: string]: string;//關鍵是這一句,後面你甭管它叫啥只要是string型別編譯就不錯
}

let worker: Worker[] = [
  { id: 1, name: "張三" },
  { id: 2, jobName: "帥彬" }
];

最後一句,資料型別你不知道也不要用any,不要用any,不要用any,因為往往報any的時候,意味著你程式碼寫的有問題。

我們回到vue中立刻就要會用到的模組管理,也就是元件。

我們先定義一個元件,你叫一個檔案也好,一個模組也好不用管它叫啥,反正就這麼個玩意,就叫mod1.ts

各個檔案裡面程式碼是這樣子的:

//mod1.ts
//我定義了一個a 並匯出
export let a = 12;
//app.ts
//因為我定義的是a 所以匯入的名字也必須跟mod1.ts裡面的一致,也得是a還得用花括號括起來,另外mod1路徑用./同級 mod1不用加字尾
import {a} from './mod1'
console.log(a);
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script type="module" src="app.js"></script>  
</body>
</html>

index.html注意一下幾點:

1.script type="module" 必須寫

2.要扔到body裡面

3.要想支援import和export 必須用伺服器環境類似這樣 http://localhost/HelloWorld/,可以隨便裝個wamp之類的然後扔到www資料夾下

4.這些都記不住也沒事按照我說的做即可,我只是說明mod1.ts和app.ts裡面的內容,這兩個檔案內容是核心

vscode終端輸入:

tsc --module ES2015 app.ts

這個命令也不用記,就是為了讓程式跑起來,我們繼續核心,修改下mod1.ts

export let a = 12; //mod1.ts//我定義了一個a 並匯出export let a = 12;

每次改東西tsc 太費勁,我們用監視命令,依然不用記,只看檔案中原始碼即可,用了這個命令你就不用管tsc了,改動自動變

tsc  --w --module ES2015 app.ts mod1.ts

修改mod1.ts

export let a = 12;
export let b = 5;
export let c = 8;

修改app.ts

import {a,b,c} from './mod1'
console.log(a,b,c);

瀏覽器控制檯,出現 12,5,8,大家看從mod1裡面匯入了三個mod1中匯出的, a,b,c等匯出的名字太多了記不住怎麼辦?我也不想去mod1.ts裡面去找匯出的叫什麼名字,那就不記了,直接修改app.ts,這樣都被我放到了arrAbc陣列裡

import * as arrAbc from './mod1'
console.log(arrAbc.a,arrAbc.b,arrAbc.c);//12,5,8

你說 我想預設一個匯出,也不想記名字,怎麼辦?

修改mod1.ts

let a = 666;
export default a;
export let b = 5;
export let c = 8;

修改,app.ts

// import * as arrAbc from './mod1'
// console.log(arrAbc.a,arrAbc.b,arrAbc.c);
import numA from './mod1'
import{b,c} from './mod1'
console.log(numA,b,c);

刷瀏覽器,出現666,12,5,8

總結一下:

1.透過 export default方式匯入,在匯入時不需要加 {} 在一個檔案或模組中,名字隨便起,比如numA

2.export default只能有一個 export default後面不能跟const或let的關鍵詞

export default 一個檔案只能有一個

對了,你不定義名字都沒事,比如,修改mod1.ts

let a = 666;
export default {
    "name":"大彬哥",
    "age":18
};
export let b = 5;
export let c = 8;

修改app.ts

import teacher from  './mod1'
console.log(teacher.name,teacher.age);

刷瀏覽器,結果就出來了,大彬哥 18,這種方式 vue中用的最多

2.型別定義(vue用到再說)

總結,到這裡你就徹底明白了vue中 import了或者export 什麼import * as 什麼的。就有了寫元件或者引用別人庫的基礎。有了這個基礎我們就可以做應用題了,我們裝上Vue最新版,看看還有啥用不明白的。

四、vue基礎知識

一、我們怎麼建立vue專案?

npm create vite@latest

你不用管上面vite不vite,你就按照這個命令跑一把梭,然後你就會看到,

1install.png

我們從index.html看,有這麼一句,

<script type="module" src="/src/main.ts"></script>

是不是我們剛才說的模組管理的東西?順藤摸瓜,看看main.ts

import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
createApp(App).mount('#app')

引入了vue模組下的 createApp,還有其它一堆,明顯我們現在只關心

import App from './App.vue'

繼續順藤摸瓜,App.vue,依然是三段論,script、template、style

<script setup lang="ts">
import HelloWorld from './components/HelloWorld.vue'
</script>

<template>
  <div>
    <a href="https://vitejs.dev" target="_blank">
      <img src="/vite.svg" class="logo" alt="Vite logo" />
    </a>
    <a href="https://vuejs.org/" target="_blank">
      <img src="./assets/vue.svg" class="logo vue" alt="Vue logo" />
    </a>
  </div>
  <HelloWorld msg="Vite + Vue" />
</template>

<style scoped>
.logo {
  height: 6em;
  padding: 1.5em;
  will-change: filter;
}
.logo:hover {
  filter: drop-shadow(0 0 2em #646cffaa);
}
.logo.vue:hover {
  filter: drop-shadow(0 0 2em #42b883aa);
}
</style>

核心就兩句話,第一句:

<script setup lang="ts">
import HelloWorld from './components/HelloWorld.vue'
</script>

這裡引入了一個元件,setup是啥你也不用管,反正你知道引入了HelloWorld.vue就OK(後面我會講),然後是

<HelloWorld msg="Vite + Vue" />

給HelloWorld的msg屬性服了一個"Vite + Vue" 的值,再努力一下就到底了!看看components裡面的HelloWorld元件,敲黑板劃,重點來了:

<script setup lang="ts">
  import { ref } from "vue";
  defineProps<{ msg: string }>();
  const count = ref(0);
</script>

<template>
  <h1>{{ msg }}</h1>
  <div class="card">
    <button type="button" @click="count++">count is {{ count }}</button>
  </div>
</template>

<style scoped>
  .read-the-docs {
    color: #888;
  }
</style>

當然我們寫專案不可能這麼簡單,更多情況下是一個父元件透過陣列迭代子元件,就像下面這樣,App.vue裡面:

<script setup lang="ts">
import { ref } from "vue";
import HelloWorld from './components/HelloWorld.vue'
const fatherItems = ref([
  { id: 1, title: "春天", content: "我把褲衩一脫,春姑娘就來了"},
  { id: 2, title: "夏天", content: "我把短褲一穿,夏姑娘就來了" }
])
</script>
<template>
  <HelloWorld v-for="item in fatherItems" :key="item.id" :title="item.title" :content="item.content" />
</template>
<style scoped>
</style>

Helloword.vue

<script setup>
defineProps(["title","content"]);
</script>
<template>
  <h4>{{ title }}</h4>
  <p>{{ content }}</p>
</template>

展示效果如下:

2demo.png

好了,到這我們做專案就夠用,整太複雜就懵逼了。接下來我們就直接擼專案。

五、開始擼專案

1.看看市場需求文件

我們看看需求文件,bula,bula一堆,我看到的是:

第一個問題:我為什麼要開發霍蘭德職業興趣測試系統?
1.手工測試速度太慢(客戶和自己),開發著玩玩
2.值得我做一天搞定
3.市面上的都需要付費,搞完以後我可以讓別人付費

說白了就是
想做
能做
值得做

第二個問題:要實現什麼內容?
功能:https://baike.baidu.com/item/...
翻譯翻譯:
原理:據興趣的不同,人格可分為研究型
第一步:人分六種,(I)、藝術型(A)、社會型(S)、企業型(E)、傳統型(C)、現實型(R)六個維度
第二步:十題一測 每種透過10道題測試,最後判斷你是哪一種,得出你是什麼人格,比如SEC
第三步:對號入座,根據索引找對應工作

因為是我自己用,所以沒什麼要說的。但是你要是公司開發,咋說呢,活當然要乾的漂亮,但是不好開發的儘量開發之前就砍掉,不管你是威逼還是理由,反正儘可能扼殺需求在搖籃之中,如果額殺不了也要記住,需求上的失誤,不要到程式碼實現層去溝通。

你只是大自然的搬運工,把市場需求搬運給計算機,不用帶太多腦子。

2.整個產品文件

原理:據興趣的不同,人格可分為研究型
第一步:人分六種,(I)、藝術型(A)、社會型(S)、企業型(E)、傳統型(C)、現實型(R)六個維度
第二步:十題一測 每種透過10道題測試,最後判斷你是哪一種,得出你是什麼人格,比如SEC
第三步:對號入座,根據索引找對應工作

3.專案開發文件

接到市場需求和產品需求文件,我的想法:你們給我圓潤的走開,翻滾吧牛寶寶。我不想幹活。(簡稱,滾犢子),既然推不掉就想怎麼實現:

在使用 Vue.js 來實現霍蘭德職業測試的應用程式時,我考慮到的:
1.準備問卷:需要準備一份問卷,其中包含若干個問題,用於測試人的興趣、傾向和人格
特點。(用ant-design-vue,本場演出就我自己,又不想介面醜爆了)
2.建立表單:你需要使用 Vue.js 的模板語法來建立表單,包括問卷中的各個問題和答案選項。
3.處理表單提交:當使用者完成填寫並提交表單時,你需要使用 Vue.js 的方法來處理表單提
交,並計算出測試結果。(用pinia狀態管理,肯定會用到跨元件通訊,順便還可以裝下13)
4.展示測試結果:最後,你可以使用 Vue.js 的指令來展示測試結果,並向使用者提供建議的職
業列表。(用個vue-chartjs雷達圖,用了很多次很穩定,也是一款裝13的利器)

以上純屬腦袋中意淫,咳咳,頭腦風暴。然後開始寫專案開發文件。大家以為我是這麼想的:

開發思路:
1.建立 Vue.js 專案:使用 構建工具建立 Vue.js 專案。
2.準備測試題目和選項:準備好測試題目和選項,可以使用陣列格式儲存。
3.建立元件:建立一個測試元件,用於顯示測試題目和選項,並處理使用者的選擇。
4.實現元件邏輯:在元件中實現邏輯,包括顯示當前測試題目和選項,處理使用者的選擇,計
算測試結果等。
5.顯示測試結果:使用另一個元件顯示測試結果,可以根據測試結果提供建議的職業。

其實我是這樣想的:

1.有沒有現成的開源的專案,我改吧改吧完事兒
2.有沒有網上現成的,讓我扒一個改吧改吧,能實現完事兒

但是我是一個脫離了低階趣味的人呢,我決定自己實現一個,畢竟我的頭髮還允許我再折騰一把。順著剛才的開發思路,要實現這個目標我得有三個步驟:

第一步:先整一個vue表單元件,能夠輸入資料,能切換上一題下一題
第二步:把輸入資料能裝一個陣列,完成各種計算,提供給雷達圖
第三步:透過雷達圖展示資料

想明白了,就一把梭上程式碼。
別的不說我先用router 搭一個 三個頁面切換的SPA應用。首先我們先在src>views下建立三個檔案,分別是Home.vue,CareerTest.vue和About.vue

其中Home.vue 內容如下,其餘只是文字不同,略。

<template>
  <div>{{ msg }}</div>
</template>
  
<script lang="ts">
import { defineComponent } from "vue";
export default defineComponent({
  setup() {
    // 在 `setup` 方法裡宣告變數
    const msg = "我是Home頁";
    // 將需要在 `<template />` 裡使用的變數 `return` 出去
    return {
      msg,
    };
  },
});
</script>  
<style scoped>
</style>

注意這裡我沒有用

<script setup>
const msg = "我是Home頁";
</script>
<template>
    <div>{{msg}}</div>
</template>

這樣的語法糖,不寫setup是標準的寫法,兩種都寫寫,大家就都會用了。至於區別也不用特意記,寫著寫著也就會了。其實你一對比就知道,無非就是省了return,還有不用寫setup方法,當然還有元件不用註冊跟this什麼的,這些你不用記,記住:

魯迅說過,只要專案中你用不到又不影響你擼專案效率和效果的功能,那就是沒有用的功能。

配置路由,src>router(src下面建一個router資料夾,下面都這麼簡寫),下面兩個檔案 index.vue和routes.vue,為什麼這麼做,因為這樣最適合實際工作架構清晰

其中 index.ts 是路由的入口檔案,如果路由很少,那麼可以只維護在這個檔案裡,但對複雜專案來說,往往需要配置上二級、三級路由,邏輯和配置都放到一個檔案的話,太臃腫了。

所以如果專案稍微複雜一些,可以像上面這個結構一樣拆分成兩個檔案: index.ts 和 routes.ts ,在 routes.ts 裡維護路由樹的結構,在 index.ts 匯入路由樹結構並啟用路由,同時可以在該檔案裡配置路由鉤子。

如果專案更加複雜,例如做一個 Admin 後臺,可以按照業務模組,再把 routes 拆分得更細,例如 game.ts / member.ts / order.ts 等業務模組,再統一匯入到 index.ts 檔案裡。這裡我用最新的router4 寫法,傳統的寫法,這裡會報錯,你不用擔心為什麼我這麼寫,你照貓畫HelloKity就行了。

//router>index.ts
import { createRouter, createWebHistory } from 'vue-router'
import type { RouteRecordRaw } from 'vue-router'
import routes from './routes';
const router = createRouter({
  routes,//核心就這個單詞而已別的可以都不用管,這個來自於routes.vue
})
export default router;

別寫那些引入vue啦 引入vue-router等寫法,那個是過去式的寫法了,她就像你的前任,忘了她吧。彬哥敲程式碼養你。

我們再看看routes.vue怎麼寫

import Home from '../views/Home.vue';
import CareerTest from '../views/CareerTest.vue';
import About from '../views/About.vue';
// 有多少路由都可以在這裡面配置
const routes = [
    {
        path: '/',
        name: 'Home',
        component: Home
    },
    {
        path: '/Career-Test',
        name: 'CareerTest',
        component: CareerTest
    },
    {
        path: '/about',
        name: 'About',
        component: About
    }
];
export default routes;

我們搭了三個頁面,又配置了路由,總得弄個導航點選才能切換吧,往App.ts裡面寫,


<script setup lang="ts">
</script>
<template>
  <div>
    <router-link to="/">首頁</router-link>
    <router-link to="/career-test">職業測評</router-link>
    <router-link to="/about">關於我們</router-link>
    <router-view />
  </div>
</template>

<style scoped>
</style>

然後,你要再main.js上搞事情,就game over了。你得通知整個SPA應用,我要全域性使用路由,如下:

import { createApp } from 'vue'
import App from './App.vue'
// import './assets/main.css'
import router from './router';
createApp(App).use(router).mount('#app')

頁面會報錯,因為我們用了router但是沒有裝啊!

npm create vite@latest

裝的是小純潔版本,什麼都自己裝,自己開發,省的專案臃腫。

我們先整一個router裝上,官網:https://router.vuejs.org/zh/i...

命令:

npm install vue-router@4

最後,切換好用了

3router就裝好了.png

總結一下:

1.用components下面預設的HelloWorld.vue,在新建的views下面另存三個頁面,Home、About和CareerTest.vue

2.新建資料夾router,下面兩個檔案一個是index.ts做入口配置,一個是routers.vue專門寫路徑對應

3.App.vue下面弄三個router-link和一個router-view,三個連結切換,一個顯示。

4.main.ts裡面import和use router。

5.安裝router

大家注意我是從專案角度倒著操作的,一般教程是會告訴你先裝router然後在弄main.ts,但是那樣容易讓你懵逼。我們從功能出發,缺什麼補什麼,你就明白為什麼這麼做了。比如現在這麼醜爆的LowB,你是不是想整個美觀的介面?我們就用ant-design-vue UI庫造一下。

1.在四vue基礎知識的基礎上,先裝個ant-design-vue先搭個架子。

npm i --save ant-design-vue@next

2.開啟官網複製程式碼,https://2x.antdv.com/componen... 到App.vue,

<style scoped>
</style>
<template>
  <a-layout>
    <a-layout-header :style="{ position: 'fixed', zIndex: 1, width: '100%' }">
      <div class="logo" />
      <a-menu
        theme="dark"
        mode="horizontal"
        v-model:selectedKeys="selectedKeys"
        :style="{ lineHeight: '64px' }"
      >
        <router-link to="/"
          ><a-menu-item key="1">首頁</a-menu-item></router-link
        >
        <router-link to="/Career-Test"
          ><a-menu-item key="2">職業測評</a-menu-item></router-link
        >
        <router-link to="/About"
          ><a-menu-item key="3">關於我們</a-menu-item></router-link
        >
      </a-menu>
    </a-layout-header>
    <a-layout-content :style="{ padding: '0 50px', marginTop: '64px' }">
      <a-breadcrumb :style="{ margin: '16px 0' }">
        <a-breadcrumb-item>Home</a-breadcrumb-item>
        <a-breadcrumb-item>List</a-breadcrumb-item>
        <a-breadcrumb-item>App</a-breadcrumb-item>
      </a-breadcrumb>
      <div :style="{padding: '24px', minHeight: '380px' }">
        <router-view />
      </div>
    </a-layout-content>
    <a-layout-footer :style="{ textAlign: 'center' }">
      彬哥頭髮多 ©2022 Created by Leolau
    </a-layout-footer>
  </a-layout>
</template>
<script lang="ts">
import { defineComponent, ref } from "vue";
export default defineComponent({
  setup() {
    return {
      selectedKeys: ref<string[]>(["2"]),
    };
  },
});
</script>
<style>
#components-layout-demo-fixed .logo {
  width: 120px;
  height: 31px;
  background: rgba(255, 255, 255, 0.2);
  margin: 16px 24px 16px 0;
  float: left;
}
.site-layout .site-layout-background {
  background: #fff;
}

[data-theme="dark"] .site-layout .site-layout-background {
  background: #141414;
}
</style>

顯然頁面是亂的因為我們只是裝了antdv沒有使用它,怎麼搞?開啟main.ts,引入元件和css,然後全域性use一下。

import { createApp } from 'vue'
import App from './App.vue'
import router from './router';
import Antd from 'ant-design-vue';
import 'ant-design-vue/dist/antd.css'
createApp(App).use(router).use(Antd).mount('#app')//注意這裡我用了兩個use,沒用.use(Antd,router),還是那句話坑我給你遮蔽了你不需要知道用就好了

重新整理,頁面如下就鳥了:

4切換完成.png

這個就是套Html的活兒,細心點就行。

總結,

1.其實上面的路由配置寫法很多,但是我沒講是因為不想增加複雜度同時很多寫法都有坑我給遮蔽了你不需要知道

2.你是要開發專案,不是為了秀技術,知不知道茴香豆的茴字有四種寫法不影響你寫好文章

到這裡,基本的架子打完了,剩下的活無非就是,拉元件,然後寫邏輯。接下來我們先把元件結構搞清楚。

六、整站的元件組織結構

5網站架構.png

架構解釋兩點:

1.為什麼我要從CareerTest跳到HollandTest?因為一級導航只想作為page頁解釋說明和展示,涉及業務的跳轉到對應的page,這樣業務page和元件一體化同時避免了 CareerTest的臃腫與混亂

2.資料和樣式分別放到單獨的資料夾,同理。尤其是資料這塊拆分處理實際專案尤其重要,比如這個專案60個選擇題,如果都扔到components裡面就太臃腫了。也利於未來資料互動與擴充套件。

啥也不說先擼一個CareerTest的介面,我們使用antdv的cart元件,有UI庫擼程式碼就是快,直接複製貼上程式碼地址:

https://2x.antdv.com/componen... 裡面的柵格卡片

<template>
  <div class="gutter-example">
    <p class="title">人格的六種型別</p>
    <p>
      霍蘭德職業興趣自測(Self-Directed Search)是由美國職業指導專家霍蘭德(John
      Holland)根據他本人大量的職業諮詢經驗及其職業型別理論編制的測評工具。霍蘭德認為,個人職業興趣特性與職業之間應有一種內在的對應關係。根據興趣的不同,人格可分為研究型(I)、藝術型(A)、社會型(S)、企業型(E)、傳統型(C)、現實型(R)六個維度,每個人的性格都是這六個維度的不同程度組合。
    </p>
    <a-row :gutter="[16, 16]" type="flex" justify="center">
      <a-col :span="12">
        <router-link to="/holland-test"
          ><a-button type="primary" class="testBtn" block size="large"
            >進入測試系統</a-button
          >
        </router-link>
      </a-col>
    </a-row>
    <div style="padding: 0px 20px 20px 20px">
      <a-row :gutter="16">
        <a-col :span="8" class="vGap">
          <a-card title="現實型(Realistic)" :bordered="false">
            <span>共同特徵:</span>
            <p>
              願意使用工具從事操作性工作,動手能力強,做事手腳靈活,動作協調。偏好於具體任務,不善言辭,做事保守,較為謙虛。
            </p>
          </a-card>
        </a-col>
        <a-col :span="8" class="vGap">
          <a-card title="研究型(Investigative)" :bordered="false">
            <span>共同特徵:</span>
            <p>
              思想家而非實幹家,抽象思維能力強,求知慾強,肯動腦,善思考,不願動手。喜歡獨立的和富有創造性的工作。
            </p>
          </a-card>
        </a-col>
        <a-col :span="8" class="vGap">
          <a-card title="藝術型(Artistic)" :bordered="false">
            <span>共同特徵:</span>
            <p>
              有創造力,樂於創造新穎、與眾不同的成果,渴望表現自己的個性,實現自身的價值。做事理想化,追求完美,不重實際。
            </p>
          </a-card>
        </a-col>
        <a-col :span="8" class="vGap">
          <a-card title="社會型(Social)" :bordered="false">
            <span>共同特徵:</span>
            <p>
              喜歡與人交往、不斷結交新的朋友、善言談、願意教導別人。喜歡關心社會問題、渴望發揮自己的社會作用。
            </p>
          </a-card>
        </a-col>
        <a-col :span="8" class="vGap">
          <a-card title="企業型(Enterprise)" :bordered="false">
            <span>共同特徵:</span>
            <p>
              追求權力、權威和物質財富,具有領導才能。喜歡競爭、敢冒風險、有野心、抱負。
            </p>
          </a-card>
        </a-col>
        <a-col :span="8" class="vGap">
          <a-card title="傳統型(Conventional)" :bordered="false">
            <span>共同特徵:</span>
            <p>
              尊重權威和規章制度,喜歡按計劃辦事,細心、有條理,習慣接受他人的指揮和領導,自己不謀求領導職務。
            </p>
          </a-card>
        </a-col>
      </a-row>
    </div>
  </div>
</template>
<style scoped>
.gutter-example :deep(.ant-row > div) {
  border: 0;
}
.gutter-box {
  padding: 5px 0;
}
.title {
  text-align: center;
  font-size: 24px;
  font-weight: bold;
}
.ant-card-body span {
  font-weight: bold;
}
.testBtn {
  margin: 5px 0;
  display: block;
}
.vGap {
  margin-top: 20px;
}
</style>

這裡強調兩點:

1.你不管怎麼套UI,你一定要寫成6個card的重複

<a-col :span="8" class="vGap">
    <a-card title="Card title" :bordered="false">
        <p>card content</p>
    </a-card>
</a-col>
……重複六次

別寫成3個一組中間加間距,那樣後臺一套資料就亂了,容易跟你打起來。我這裡是寫死的就不從資料裡面取了。

2.我加了一個vGap類,不是說你用UI庫,就不自己搞事情了。別被UI庫限制住了結果自己不會寫改樣式了。

到這裡大家看到我,整了一個跳轉 ,我們按照架構圖來:

<router-link to="/holland-test">
<a-button type="primary" class="testBtn" block size="large">進入測試系統</a-button>

然後我們建立一個HollandTest.vue的元件,裡用到了HollandLib元件views>HollandTest.vue檔案如下

<script setup lang="ts">
import { Modal } from "ant-design-vue";
import { defineComponent, ref } from "vue";
import { onMounted } from "vue";
import { useRouter } from "vue-router";
import HollandLib from "../components/HollandLib.vue";
const router = useRouter();
onMounted(() => {
  Modal.confirm({
    title: () => "溫馨提示",
    okText: () => "開始吧>>",
    cancelText: "我再想想……",
    content:
      () => `測評選項沒有對錯之分,如果您想對自己有一個真實的認知,請根據自己的實際情況選擇是或否√
         本測試題共60題,測試時間為20分鐘。
         現在,請找到一個安靜的場所...`,
    onCancel() {
      router.push({ path: "/Career-Test" });
    },
  });
});
</script>
<template>
  <HollandLib />
</template>

這裡我用了一個模態確認框,https://2x.antdv.com/componen... 用的是自定義按鈕文字的模態框

重點是這句,

const router = useRouter();//這是新寫法 相當於原來的$router
router.push({ path: "/Career-Test" });

點選取消按鈕跳轉。另外,定義元件用setup語法糖 非常的嗨皮,你不用return,你就放心大膽的定義各種變數和使用各種元件,剩下的交給setup.

敲黑板劃重點要寫核心結構了。

七、核心測試功能實現

<template>
  <div>
    <a-row type="flex" justify="center" align="middle" class="rowContainer">
      <a-col :span="4" class="previous">
        <div>
          <a-button>上一題</a-button>
        </div>
      </a-col>
      <a-col :span="8" class="process">
        <div>
          <a-progress type="line" :percent="75" :format="() => `12/60`" />
        </div>
      </a-col>
      <a-col :span="4"><div class="timeC">04:33</div></a-col>
    </a-row>
    <a-row
      :gutter="[16, 16]"
      type="flex"
      justify="center"
      align="middle"
      class="rowContainer"
    >
      <a-col class="gutter-row" :span="16">
        <div class="gutter-box">
          <a-card title="1.我喜歡把一件事情做完後再做另一件事。">
            <a-button
              size="large"
              block
              class="yesBtn"
              @click="nextQuestion('是')"
              >是</a-button
            >
            <a-button size="large" block @click="nextQuestion('否')"
              >否</a-button
            >
          </a-card>
        </div>
      </a-col>
    </a-row>
  </div>
</template>
<script setup>
</script>
<style scoped>
.gutter-box {
  margin-top: 10px;
}
.ant-card {
  padding: 30px;
}
.previous {
  text-align: left;
}
.process {
  min-height: 35px;
}
.timeC {
  text-align: right;
}
.yesBtn {
  margin: 10px 0;
}
</style>

關於怎麼套頁面我就不多墨跡,你看就明白了,我們中心在功能上。

1.測評頁套資料

將資料處理完然後套到card上,data>QuestionsData.ts

現在QuestionsData.ts是這樣的:

export const quesStr = `
1、我喜歡把一件事情做完後再做另一件事。                           
2、在工作中我喜歡獨自籌劃,不願受別人干涉。                        
……
`;

這裡注意市場給你的是word文件,你需要記事本透一下格式,第二千萬別自己一個個寫陣列,容易把自己寫死。也別要求需求方按照你的格式給你資料,那是你的事情跟人家沒有半毛錢關係,過分要求別人做不該人家乾的事兒,容易被懟死或者打死。

還有就是能不用資料庫就別搞太複雜,一是為了響應速度,第二是為了開發速度夠用就好。

當下我們只要處理成

['1、我喜歡把一件事情做完後再做另一件事。',
 '2、在工作中我喜歡獨自籌劃,不願受別人干涉'。
]

的形式,注意每一個問題後面有不定數量空格需要處理

程式碼也很簡單一句話:

let questArrr = quesStr.split('\n').map(s => s.trim()).filter(s => s);
// 定義一個響應式陣列questions 來提供卡片內容
let  questions = reactive(questArrr);

然後在模板裡面套questions[0]就可以了,程式碼如下:

<template>
  <div>
    <a-row type="flex" justify="center" align="middle" class="rowContainer">
      <a-col :span="4" class="previous">
        <div>
          <a-button>上一題</a-button>
        </div>
      </a-col>
      <a-col :span="8" class="process">
        <div>
          <a-progress type="line" :percent="75" :format="() => `12/60`" />
        </div>
      </a-col>
      <a-col :span="4"><div class="timeC">04:33</div></a-col>
    </a-row>
    <a-row
      :gutter="[16, 16]"
      type="flex"
      justify="center"
      align="middle"
      class="rowContainer"
    >
      <a-col class="gutter-row" :span="16">
        <div class="gutter-box">
            <a-card :title="questions[0]">
              <a-button
                size="large"
                block
                class="yesBtn"
                @click="nextQuestion('是')"
                >是</a-button
              >
              <a-button size="large" block @click="nextQuestion('否')"
                >否</a-button
              >
            </a-card>
        </div>
      </a-col>
    </a-row>
  </div>
</template>
<script setup>
import { quesStr } from "../data/QuestionsData";
import { ref, reactive } from "vue";
let questArrr = quesStr
  .split("\n")
  .map((s) => s.trim())
  .filter((s) => s);
// 定義一個響應式陣列questions 來提供卡片內容
let questions = reactive(questArrr);
</script>
<style scoped>
.gutter-box {
  margin-top: 10px;
}
.ant-card {
  padding: 30px;
}
.previous {
  text-align: left;
}
.process {
  min-height: 35px;
}
.timeC {
  text-align: right;
}
.yesBtn {
  margin: 10px 0;
}
</style>

接下來要實現上一題下一題,還有把你選擇的結果用一個resArr陣列接收,為計算最終結果給雷達圖做準備。程式碼如下:

<template>
  <div>
    <a-row type="flex" justify="center" align="middle" class="rowContainer">
      <a-col :span="4" class="previous">
        <div>
          <a-button @click="previousQuestion">上一題</a-button>
        </div>
      </a-col>
      <a-col :span="8" class="process">
        <div>
          <a-progress type="line" :percent="75" :format="() => `12/60`" />
        </div>
      </a-col>
      <a-col :span="4"><div class="timeC">04:33</div></a-col>
    </a-row>
    <a-row
      :gutter="[16, 16]"
      type="flex"
      justify="center"
      align="middle"
      class="rowContainer"
    >
      <a-col class="gutter-row" :span="16">
        <div class="gutter-box">
          {{ resArr }}
          <a-card :title="questions[curIndex]">
            <a-button
              size="large"
              block
              class="yesBtn"
              @click="nextQuestion('是')"
              >是</a-button
            >
            <a-button size="large" block @click="nextQuestion('否')"
              >否</a-button
            >
          </a-card>
        </div>
      </a-col>
    </a-row>
  </div>
</template>
<script setup lang="ts">
import { quesStr } from "../data/QuestionsData";
import { ref, reactive } from "vue";
let questArrr = quesStr
  .split("\n")
  .map((s) => s.trim())
  .filter((s) => s);
// 定義一個響應式陣列questions 來提供卡片內容
let questions = reactive(questArrr);
// 點選任意一個選項就是下一題
// 定義一個題號index
let curIndex = ref(0);
// 定義一個選擇結果的陣列
const resArr = ref([] as any[]);
function nextQuestion(answer: any) {
  resArr.value.splice(curIndex.value, 1, answer);
  curIndex.value++;
  if (curIndex.value == questions.length) {
    curIndex.value = questions.length - 1;
  }
}
function previousQuestion() {
  curIndex.value--;
  if (curIndex.value == -1) {
    alert("第一題");
    curIndex.value = 0;
  }
}
</script>
<style scoped>
.gutter-box {
  margin-top: 10px;
}
.ant-card {
  padding: 30px;
}
.previous {
  text-align: left;
}
.process {
  min-height: 35px;
}
.timeC {
  text-align: right;
}
.yesBtn {
  margin: 10px 0;
}
</style>

效果如下:

6選擇資料處理完成.png

處理一下上一題,第一題就沒必要顯示上一題了,

<a-button v-if="curIndex > 0" @click="previousQuestion">上一題</a-button>

最後一題,提示是否提交的模態框

import { Modal } from "ant-design-vue";
function showCompop() {
  Modal.confirm({
    title: () => "溫馨提示",
    okText: () => "提交",
    cancelText: "取消",
    content: () => `恭喜你所有問題已經完成,確認提交檢視結果嗎?`,
    onOk() {
      router.push({
        path: "/result",
      });
    },
    onCancel() {
      router.push({ path: "/holland-test" });
    },
  });
}

路由跳轉還是老方法,就不贅述。另存一個Result.vue,在routes.ts裡面加配置具體如下:

import Home from '../views/Home.vue';
import CareerTest from '../views/CareerTest.vue';
import About from '../views/About.vue';
import HollandTest from '../views/HollandTest.vue';
// 有多少路由都可以在這裡面配置
const routes = [
    {
        path: '/',
        name: 'Home',
        component: Home
    },
    {
        path: '/Career-Test',
        name: 'CareerTest',
        component: CareerTest
    },
    {
        path: '/About',
        name: 'About',
        component: About
    },
    {
        path: '/holland-test',
        name: '霍蘭德測試',
        component: HollandTest
    },
    {
        path: '/result',
        name: '測試結果',
        component: Result
    },
];
export default routes;

1.結果頁套資料

我需要整一個雷達圖,然後一段文字說一下測評結果。

npm i vue-chartjs chart.js

然後我們套一個介面,依然用antdv


<template>
  <div style="background: #fff; padding: 14px 24px; min-height: 380px">
    <a-descriptions
      title="職業興趣報告:"
      bordered
      size="middle"
      layout="vertical"
    >
      <a-descriptions-item
        label="您的職業興趣程式碼是"
        :labelStyle="{
          textAlign: 'center',
          display: 'block',
          fontWeight: 'bold',
        }"
        :span="1"
        :contentStyle="{ textAlign: 'center', display: 'block' }"
      >
        <div class="codeBox">
          <div class="code1">S</div>
          <div class="code2">E</div>
          <div class="code3">C</div>
          <p class="code">SEC</p>
        </div>
      </a-descriptions-item>
      <a-descriptions-item
        label="您的各型別佔比"
        :labelStyle="{
          textAlign: 'center',
          display: 'block',
          fontWeight: 'bold',
        }"
        :contentStyle="{ textAlign: 'center', display: 'block' }"
        :span="2"
      >
        <div style="max-width: 350px; margin: 0 auto">
          <Radar id="my-chart-id" :data="chartData" />
        </div>
      </a-descriptions-item>
      <a-descriptions-item label="CAS型適合的職業" :span="3">
        <a-badge
          text="廚師、林務員、跳水員、潛水員、染色員、電器修理、眼鏡製作、電工、紡織機器裝配工、服務員、裝玻璃工人"
        />
      </a-descriptions-item>

      <a-descriptions-item label="形態" :span="1">現實型R</a-descriptions-item>
      <a-descriptions-item label="人格傾向" :span="1"
        >喜歡與人交往、不斷結交新的朋友、善言談、願意教導別人。關心社會問題、渴望發揮自己的社會作用。尋求廣泛的人際關係,比較看重社會義務和社會道德</a-descriptions-item
      >
      <a-descriptions-item label="典型職業" :span="3"
        ><div class="codeBox">工人 農民 土木工程師</div></a-descriptions-item
      >
      <a-descriptions-item label="形態" :span="1">現實型R</a-descriptions-item>
      <a-descriptions-item label="人格傾向" :span="1"
        >具有順從、坦率、謙虛、自然、堅毅、實際、有禮、害羞、穩健、節儉的特徵,表現為
        1、喜愛實用性的職業或情境,以從事所喜好的活動,避免社會性的職業或情境
        2、用具體實際的能力解決工作及其他方面的問題,較缺乏人際關係方面的能力。
        3、重視具體的事物,如金錢,權力、地位等。</a-descriptions-item
      >
      <a-descriptions-item label="典型職業" :span="3"
        ><div class="codeBox">喜歡要求與人打交道的工作,能夠不斷結交新的朋友,從事提供資訊、啟迪、幫助、培訓、開發或治療等事務,並具備相應能力。如: 教育工作者(教師、教育行政人員),社會工作者(諮詢人員、公關人員)。</div></a-descriptions-item
      >
      <a-descriptions-item label="形態" :span="1">現實型R</a-descriptions-item>
      <a-descriptions-item label="人格傾向" :span="1"
        >具有順從、坦率、謙虛、自然、堅毅、實際、有禮、害羞、穩健、節儉的特徵,表現為
        1、喜愛實用性的職業或情境,以從事所喜好的活動,避免社會性的職業或情境
        2、用具體實際的能力解決工作及其他方面的問題,較缺乏人際關係方面的能力。
        3、重視具體的事物,如金錢,權力、地位等。</a-descriptions-item
      >
      <a-descriptions-item label="典型職業" :span="3"
        ><div class="codeBox">工人 農民 土木工程師</div></a-descriptions-item
      >
      <a-descriptions-item
        label="溫馨提示"
        :labelStyle="{
          textAlign: 'left',
          display: 'block',
          fontWeight: 'bold',
        }"
        :contentStyle="{ textAlign: 'left' }"
        :span="3"
      >
        <p>
          除了關注得分最高的前三項CAS,找到適合自己發展的職業領域外,還希望您也特別關注一下自己最不適合發展的職業領域,即得分最低的那個型別所指向的領域,避免長時間地在不適合自己發展的職業領域探索。
        </p>
      </a-descriptions-item>
    </a-descriptions>
  </div>
</template>
<script setup lang="ts">
import { Radar } from "vue-chartjs";
import { ref, reactive } from "vue";
import {
  Chart as ChartJS,
  RadialLinearScale,
  PointElement,
  LineElement,
  Filler,
  Tooltip,
  Legend,
} from "chart.js";
ChartJS.register(
  RadialLinearScale,
  PointElement,
  LineElement,
  Filler,
  Tooltip,
  Legend
);

let chartData = reactive({
  labels: [
    "研究型(I)",
    "藝術型(A)",
    "社會型(S)",
    "企業型(E)",
    "傳統型(C)",
    "現實型(R)",
  ],
  datasets: [
    {
      label: "您的各型別佔比",
      backgroundColor: "rgba(255,99,132,0.2)",
      borderColor: "rgba(255,99,132,1)",
      pointBackgroundColor: "rgba(255,99,132,1)",
      pointBorderColor: "#fff",
      pointHoverBackgroundColor: "#fff",
      pointHoverBorderColor: "rgba(255,99,132,1)",
      data: [0, 0, 0, 0, 0, 0],
    },
  ],
});
</script>  
<style scoped>
.codeBox {
  position: relative;
  width: 300px;
}
.code1,
.code2,
.code3 {
  width: 100px;
  height: 100px;
  position: absolute;
  border-radius: 50px;
  line-height: 100px;
  font-size: 40px;
  color: #fff;
}
.code {
  position: absolute;
  color: black;
  z-index: 100;
  left: 125px;
  top: 80px;
  font-size: 30px;
}
.code1 {
  background: green;
  left: 100px;
  top: -110px;
}
.code2 {
  background: orange;
  left: 50px;
  top: -25px;
}
.code3 {
  background: blue;
  left: 150px;
  top: -25px;
}
</style>

報告部分用了描述列表https://2x.antdv.com/componen...

7效果圖.png

八、資料對接

現在我們測試選項頁能把測試題結果拿到了,然後結果報告頁靜態頁面也出來了,現在最關鍵的點就來了,

如何將測試結果陣列處理成 報告頁的資料展示出來。

這裡分三步:

1.把資料傳過來

2.把資料處理成用來展示的

3.套資料展示

九、狀態管理與pinia

處理第一步資料的時候,我們需要把資料components>從HollandLib.vue 的resArr傳到views>Result.vue裡面。

我們當然可以用透過向父元件傳遞資料然後傳遞給兄弟元件,但是大量資料的時候就很亂了,所以我們使用的Vue 狀態管理庫pinia。

別墨跡 先裝上再說,官網https://pinia.vuejs.org/zh/ge...

npm install pinia

開啟main.ts跟使用router和ant-design-vue一樣。

import { createApp } from 'vue'
import App from './App.vue'
import router from './router';
import Antd from 'ant-design-vue';
import 'ant-design-vue/dist/antd.css'
import { createPinia } from 'pinia'
const pinia = createPinia()
createApp(App).use(router).use(Antd).use(pinia).mount('#app')//注意這裡我用了多個個use,沒用.use(Antd,router),還是那句話坑我給你遮蔽了你不需要知道用就好了

裝上了就開整,你不要一看到狀態管理就覺得複雜和高大上。其實簡單的令人髮指。我做個類比你就秒懂。

你家水果可以放廚房櫃子裡,也可以放客廳冰箱裡,你家裡好幾個人都吃水果,洗衣部分隨手放在水池子邊上或者其它兩個位置,下一個人吃,就得很麻煩的找來找去。另外你一會拿個香蕉一會拿個蘋果忒麻煩了吧。怎麼辦呢?

你家裡就規定了,水果都放在冰箱的保鮮區,用水果籃子洗和放水果吃完都要放回去。

我們在src>stores>userCheckStore.ts,內容如下:

import { defineStore } from 'pinia'
import { reactive } from 'vue'
//defineStore以冰箱 userCheckStore
export const userCheckStore = defineStore('QueuserChecktionRes', {
    // sate就是保鮮區,resArr就是蘋果、香蕉各種你要拿走的水果(資料),你不用管為啥我用reactive,你包一層不錯,有時候你不包可能就錯,所以不用記照著搞就行了
    state: () => {
        return {
            resArr: reactive([])
        }
    },
})

然後我們在各個元件用resArr用它,怎麼用HollandLib.vue下

import { userCheckStore } from "../stores/userCheckStore";
import { storeToRefs } from "pinia";
const store = userCheckStore();
const {resArr} = storeToRefs(store);

userCheckStore 就是我們冰箱,store就是保鮮區,resArr是蘋果,是不是很簡單?storeToRefs是為了響應式資料的,你也不用管是啥,你就包上就完事兒了。反正作為新手,我講storeToRefs包不包的區別意義也不大。上面那段話你想在哪個元件用就在那個元件這麼寫就行。然後我們說下怎麼把香蕉放回冰箱,也就是修改資料。

store.resArr.splice(curIndex.value, 1, answer);

就跟修改物件沒區別注意前面帶上store.resArr(改的是保鮮區裡的香蕉,你不能改錯了,這樣所有元件都能接收到你的修改。

store.name = 'xxxx'這樣的形式,因為我玩的是陣列,所以splice了一下,道理一樣。這樣做目的是我把每道題的選項上一題的時候能修改成點選的那個值,最後是[][]['是','否','是'],這個陣列views>Result.vue能拿到,就可以計算和巢狀資料了,計算資料這個跟ts和vue3無關,是原生js基礎的東西。這裡去強調一點要熟練使用陣列、物件和正則處理資料,而巢狀資料就跟我們前面七、核心測試功能實現巢狀問題卡沒區別了。

最後是打包上線,

npm run build

把dist檔案家裡的內容扔到伺服器根目錄下就可以了。

十、關於開發效率

最後我說一下如何提高開發效率,用框架肯定是快,但是前提是原生js的語法和演算法要很瞭解,還有邏輯清晰。

比如給大家舉個例子:resultData.ts這個資料是市場部們給的,

export let sixTypeStr = `
1、社會型:(S)

共同特徵:喜歡與人交往、不斷結交新的朋友、善言談、願意教導別人。關心社會問題、渴望發揮自己的社會作用。尋求廣泛的人際關係,比較看重社會義務和社會道德

典型職業:喜歡要求與人打交道的工作,能夠不斷結交新的朋友,從事提供資訊、啟迪、幫助、培訓、開發或治療等事務,並具備相應能力。如: 教育工作者(教師、教育行政人員),社會工作者(諮詢人員、公關人員)。

2、企業型:(E)

共同特徵:追求權力、權威和物質財富,具有領導才能。喜歡競爭、敢冒風險、有野心、抱負。為人務實,習慣以利益得失,權利、地位、金錢等來衡量做事的價值,做事有較強的目的性。

典型職業:喜歡要求具備經營、管理、勸服、監督和領導才能,以實現機構、政治、社會及經濟目標的工作,並具備相應的能力。如專案經理、銷售人員,營銷管理人員、政府官員、企業領導、法官、律師。

3、常規型:(C)

共同特點:尊重權威和規章制度,喜歡按計劃辦事,細心、有條理,習慣接受他人的指揮和領導,自己不謀求領導職務。喜歡關注實際和細節情況,通常較為謹慎和保守,缺乏創造性,不喜歡冒險和競爭,富有自我犧牲精神。

典型職業:喜歡要求注意細節、精確度、有系統有條理,具有記錄、歸檔、據特定要求或程式組織資料和文字資訊的職業,並具備相應能力。如:秘書、辦公室人員、記事員、會計、行政助理、圖書館管理員、出納員、打字員、投資分析員。

4、實際型:(R)

共同特點:願意使用工具從事操作性工作,動手能力強,做事手腳靈活,動作協調。偏好於具體任務,不善言辭,做事保守,較為謙虛。缺乏社交能力,通常喜歡獨立做事。

典型職業:喜歡使用工具、機器,需要基本操作技能的工作。對要求具備機械方面才能、體力或從事與物件、機器、工具、運動器材、植物、動物相關的職業有興趣,並具備相應能力。如:技術性職業(計算機硬體人員、攝影師、製圖員、機械裝配工),技能性職業(木匠、廚師、技工、修理工、農民、一般勞動)。

5、調研型:(I)

共同特點:思想家而非實幹家,抽象思維能力強,求知慾強,肯動腦,善思考,不願動手。喜歡獨立的和富有創造性的工作。知識淵博,有學識才能,不善於領導他人。考慮問題理性,做事喜歡精確,喜歡邏輯分析和推理,不斷探討未知的領域。

典型職業:喜歡智力的、抽象的、分析的、獨立的定向任務,要求具備智力或分析才能,並將其用於觀察、估測、衡量、形成理論、最終解決問題的工作,並具備相應的能力。 如科學研究人員、教師、工程師、電腦程式設計人員、醫生、系統分析員。

6、藝術型:(A)

共同特點:有創造力,樂於創造新穎、與眾不同的成果,渴望表現自己的個性,實現自身的價值。做事理想化,追求完美,不重實際。具有一定的藝術才能和個性。善於表達、懷舊、心態較為複雜。

典型職業:喜歡的工作要求具備藝術修養、創造力、表達能力和直覺,並將其用於語言、行為、聲音、顏色和形式的審美、思索和感受,具備相應的能力。不善於事務性工作。如藝術方面(演員、導演、藝術設計師、雕刻家、建築師、攝影家、廣告製作人),音樂方面(歌唱家、作曲家、樂隊指揮),文學方面(小說家、詩人、劇作家)。`;

拿到以後多餘空格不用管,你用編輯器格式化就全沒了,但是空格你肯定不能手動刪除吧?很多人想都不想直接split

let resultArr = resultStr.split("\n");

也確實該這麼做,但是問題就來了,

8問題.png

這就要求你熟練的使用陣列方法,正則了和字串操作方法。

還有再處理sixTypeStr

export let sixTypeStr = `
1、社會型:(S)

共同特徵:喜歡與人交往、不斷結交新的朋友、善言談、願意教導別人。關心社會問題、渴望發揮自己的社會作用。尋求廣泛的人際關係,比較看重社會義務和社會道德

典型職業:喜歡要求與人打交道的工作,能夠不斷結交新的朋友,從事提供資訊、啟迪、幫助、培訓、開發或治療等事務,並具備相應能力。如: 教育工作者(教師、教育行政人員),社會工作者(諮詢人員、公關人員)。

2、企業型:(E)

共同特徵:追求權力、權威和物質財富,具有領導才能。喜歡競爭、敢冒風險、有野心、抱負。為人務實,習慣以利益得失,權利、地位、金錢等來衡量做事的價值,做事有較強的目的性。

典型職業:喜歡要求具備經營、管理、勸服、監督和領導才能,以實現機構、政治、社會及經濟目標的工作,並具備相應的能力。如專案經理、銷售人員,營銷管理人員、政府官員、企業領導、法官、律師。

3、常規型:(C)

時候,你split完會是這樣,

9陣列處理.png

你其實要的是 三個一組,包含社會型,共同特徵,還有職業。一般人又會去迴圈處理陣列再扔到一個物件裡,這樣做當然更好更靈活,但是你處理的時候又會涉及到又要隔3個迴圈,還有考慮陣列中物件型別如何對應,比如S要對應前三項,E要對應456專案,這樣又要做一個陣列放六種型別……

其實到這裡已經可以用了,你只要找到包含字母S的,然後下標+1 +2你要的資料就可以巢狀了,一句話搞定。

const index = sixTypeArr.findIndex((item) => item.includes(searchChar[i]));

使用了陣列的findIndex和includes方法,所以大家可以看到,熟練的使用陣列操作能夠極大的提升開發效率與降低程式碼量。

十一,與需求方和產品溝通與扯皮

很多程式設計師要跟產品、測試和需求方關係非常緊張,吵架。很大部分原因是沒有搞明白程式設計師是幹什麼的。

程式設計師是把需求方的需求準確無誤的告訴電腦高效的執行,這是最低需求。

比如我測試結果是ECA,但是並沒有ECA型別的測試結果與職業匹配對照結果,這個問題第一做好提醒需求方,第二你處理好這種情況的提示即可。至於你透過威逼利誘砍掉你不想開發的功能那是進階了,至少你得做到前面這點,你才是一個合格的程式設計師。

十二,寫在最後

1.程式設計師不要自嗨,夠用就好。

因為這個工具我自己和公司用,另外想透過這個專案讓大家迅速的能夠用vue3開發專案,而不是卡住大家,所以我省略了很多的細節,比如路由我實際開發的時候使用v-for迴圈的,但是講的時候,我就直接寫死了,因為不想增加大家理解複雜度。

2.不要手裡有錘子,眼裡都是釘子

程式是為了實現功能和業務服務,而程式永遠不是唯一的實現方式(但是往往是高效的方式),能不用程式就能高效解決,那就不要寫程式。

最後奉上效果圖:

10gameOver.png

最後網站展示效果:https://leolau2012.github.io/
關於這個教程Follow的過程中,有人任何問題和卡頓,歡迎留言或私信。

相關文章