Lala Code

Lala 的前端大補帖,歡迎一起鑽研前端技術😊

0%

Composition API 共用邏輯的封裝

Vue 處理共用邏輯的方式

以往用 Vue2 處理共用邏輯有幾種方式

🔸 Mixins
🔸 Higher-order Components ( HOC )
🔸 Renderless Components

但 Vue2 存在著一些問題,命名衝突、產生多餘的元件實體、資料難以追蹤來源,就會有一些狀況產生。
隨著 Vue3 的升級,Vue3 Composition API 解決了 Vue2 的問題

🔸 資料追蹤清晰
🔸 不會有命名衝突的問題
🔸 不需要產生多餘的元件

取得 Composition API 的值

從共用邏輯封裝的 Composition API 取值

範例: 顯示滑鼠座標

封裝邏輯的 JS

不同 components 可能會共用的 JS

composition-api/useMousePosition.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import { onMounted, onUnmounted, ref } from "vue";
export function mousePosition() {
const x = ref(0);
const y = ref(0);
const positionUpdate = (e) => {
x.value = e.pageX;
y.value = e.pageY;
};
onMounted(() => {
window.addEventListener("mousemove", positionUpdate);
});
onUnmounted(() => {
window.removeEventListener("mousemove", positionUpdate);
});
return { x, y };
}

整合封裝好的 JS

所有封裝的 JS 都在 index.js 做整合,component 只需引入這支就好

composition-api/index.js

1
2
import { mousePosition } from "./useMousePosition.js";
export const useMousePosition = mousePosition;

index.js 引入到 component

MousePosition.vue

1
2
3
4
5
6
7
import { useMousePosition } from "@/composition-api";
export default {
setup() {
const { x, y } = useMousePosition();
return { x, y };
},
};
1
2
3
4
<div class="box">
<h1>Mouse Position</h1>
<h2>x: {{x}} y: {{y}}</h2>
</div>

解構取出 reactive 的物件

組件透過解構要取出 reactive 的物件時,解構出來的變數會變成單純的變數(不具備綁定功能),要讓 reactive 的變數被綁定有兩種方法:

1️⃣ 不使用解構,直接 return reactive 物件

composition-api/useMousePosition.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import { onMounted, onUnmounted, reactive, ref } from "vue";
export function mousePosition() {
const position = reactive({
x: 0,
y: 0,
});
const positionUpdate = (e) => {
position.x = e.pageX;
position.y = e.pageY;
};
onMounted(() => {
window.addEventListener("mousemove", positionUpdate);
});
onUnmounted(() => {
window.removeEventListener("mousemove", positionUpdate);
});
return position;
}

MousePosition.vue

1
2
3
4
5
6
7
import { useMousePosition } from "@/composition-api";
export default {
setup() {
const position = useMousePosition();
return { position };
},
};
1
2
3
4
<div class="box">
<h1>Mouse Position</h1>
<h2>x: {{ position.x }} y: {{ position.y }}</h2>
</div>

2️⃣ 使用 toRefs

只要把 reactive 物件用 toRefs 包起來,就可以讓解構的值具備資料綁定的效果

composition-api/useMousePosition.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import { onMounted, onUnmounted, reactive, ref, toRefs } from "vue";
export function mousePosition() {
const position = reactive({
x: 0,
y: 0,
});
const positionUpdate = (e) => {
position.x = e.pageX;
position.y = e.pageY;
};
onMounted(() => {
window.addEventListener("mousemove", positionUpdate);
});
onUnmounted(() => {
window.removeEventListener("mousemove", positionUpdate);
});
return toRefs(position);
}

MousePosition.vue

1
2
3
4
5
6
7
import { useMousePosition } from "@/composition-api";
export default {
setup() {
const { x, y } = useMousePosition();
return { x, y };
},
};
1
2
3
4
<div class="box">
<h1>Mouse Position</h1>
<h2>x: {{x}} y: {{y}}</h2>
</div>

🔡 如要 return 更多的變數可使用展開運算子的方式

useMousePosition.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import { onMounted, onUnmounted, reactive, ref, toRefs } from "vue";
export function mousePosition() {
const name = ref("bobee");
const position = reactive({
x: 0,
y: 0,
});
const positionUpdate = (e) => {
position.x = e.pageX;
position.y = e.pageY;
};
onMounted(() => {
window.addEventListener("mousemove", positionUpdate);
});
onUnmounted(() => {
window.removeEventListener("mousemove", positionUpdate);
});
return { ...toRefs(position), name };
}

MousePosition.vue

1
2
3
4
5
6
7
import { useMousePosition } from "@/composition-api";
export default {
setup() {
const { x, y, name } = useMousePosition();
return { x, y, name };
},
};
1
2
3
4
<div class="box">
<h1>Mouse Position</h1>
<h2>x: {{x}} y: {{y}} {{ name }}</h2>
</div>

這麼一來就可以取出多個值了!


設定 Composition API 的值

範例: 點擊按鈕改變值

useState.js

1
2
3
4
5
6
7
8
9
import { ref } from "vue";

export function stateAdd() {
const idx = ref(0);
const addState = () => {
idx.value++;
};
return { idx, addState };
}

index.js

1
2
3
4
5
import { mousePosition } from "./useMousePosition.js";
import { stateAdd } from "./useState.js";

export const useMousePosition = mousePosition;
export const useState = stateAdd;
1
2
3
4
5
6
7
import { useState } from "@/composition-api";
export default {
setup() {
const { idx, addState } = useState();
return { idx, addState };
},
};
1
2
3
4
<div class="block">
<h1>number: {{idx}}</h1>
<button @click="addState">add</button>
</div>

封裝的內容都是 priviate 的,即使複製兩個 components 也不會影響到各別的值


封裝非同步處理的狀態

useFetch.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import { reactive, ref } from "vue";
import axios from "axios";

export function fetchs(API_url = "") {
const isLoad = ref(false);

const fetchData = reactive({ data: [] });

const errorMsg = ref("");

axios
.get(API_url)
.then((res) => {
isLoad.value = true;
fetchData.data = res.data;
})
.catch((error) => {
isLoad.value = true;
errorMsg.value = error.request.statusText;
});
return { isLoad, fetchData, errorMsg };
}

index.js

1
2
3
4
5
6
7
import { mousePosition } from "./useMousePosition.js";
import { stateAdd } from "./useState.js";
import { fetchs } from "./useFetch.js";

export const useMousePosition = mousePosition;
export const useState = stateAdd;
export const useFetch = fetchs;

FetchData.vue

1
2
3
4
5
6
7
8
9
import { useFetch } from "@/composition-api";
export default {
setup() {
const { isLoad, fetchData, errorMsg } = useFetch(
"https://vue-lessons-api.herokuapp.com/photo/list"
);
return { isLoad, fetchData, errorMsg };
},
};
1
2
3
4
5
6
7
8
9
10
11
12
13
<div>
<img v-if="!isLoad" class="loading" src="../assets/load.gif" alt="" />
<!--errorMsg不等於空時才會出現-->
<h1 v-if="errorMsg">ERROR: {{ errorMsg }}</h1>
<div v-if="isLoad" class="imgBlock">
<img
v-for="item in fetchData.data"
:key="item.url"
:src="item.url"
alt=""
/>
</div>
</div>

以上是我的學習筆記,希望也有幫助到你哦 😀



Hey!想學習更多前端知識嗎?

最近 Lala 開了前端課程 👉【實地掌握RWD - 12小時新手實戰班】👈
無論您是 0 基礎新手,又或是想學 RWD 的初學者,
我們將帶你從零開始,深入了解並掌握 RWD 響應式網頁設計的核心技術,快來一起看看吧 😊



🚀線上課程分享

線上課程可以加速學習的時間,省去了不少看文件的時間XD,以下是我推薦的一些課程
想學習更多關於前後端的線上課程,可以參考看看。

Hahow

Hahow 有各式各樣類型的課程,而且是無限次數觀看,對學生或上班族而言,不用擔心被時間綁住



六角學院

如果你是初學者,非常推薦六角學院哦!
剛開始轉職也是上了六角的課,非常的淺顯易懂,最重要的是,隨時還有線上的助教幫你解決問題!


Udemy

Udemy 裡的課程非常的多,品質普遍不錯,且價格都滿實惠的,CP值很高!
也是很多工程師推薦的線上課程網站。
❤️