owned this note
owned this note
Published
Linked with GitHub
# Vue-Composition-API 的學習 (一)
###### tags: `w3HexSchool` . `js`
為何我們需要 Composition 呢 ?
其實我也不是特別清楚 , 不過接下來有一些旅途可以跟在下一起走 , 讓我們發現一些利用 Composition-API 可能會更棒的例子
1. window.innerHeight / window.innerWidth
不知道各位有沒有為測量螢幕長寬而困擾過呢 ?
以下是在下為了要測量螢幕的長寬 , 結果需要作出一個元件才能完成
```javascript=
// measurer.vue
<template>
<div class="root">
<slot name="body"
:width="width"
:height="height" />
</div>
</template>
<script>
export default {
name: "measurer",
mounted() {
window.addEventListener('resize', this.reportWindowSize);
},
beforeDestroy(){
window.removeEventListener('resize', this.reportWindowSize);
},
methods: {
reportWindowSize() {
this.height = window.innerHeight;
this.width = window.innerWidth;
},
},
data() {
return {
width: window.innerWidth, // document.body.clientWidth,
height: window.innerHeight, // document.body.clientHeight,
}
}
}
</script>
<style scoped>
.root {
width: 400px;
height: 200px;
font-weight: 900;
font-size: 50px;
display: flex;
flex-direction: column;
background-color: #898585;
margin: 20px;
padding: 20px;
}
</style>
```
外加上在使用測量時 , 都需要用 `slot` 將目標元件包成子元件 ,
並有可能受到多一層 div 的 side effect , 讓 css 調整困難
```htmlmixed=
<measurer>
<template v-slot:body="{height,width}">
<span>寬度:{{width}}px</span>
<span>高度:{{height}}px</span>
</template>
</measurer>
```
這時我們可以引入 @vue/composition-api 套件 ,
讓我們在 vue 2 的環境中使用 setup 的功能 ,
如果觀察 measurer.vue 我們可以整理出一個 useMeasurer.js
```javascript=
import {onMounted, onBeforeUnmount, reactive} from '@vue/composition-api'
const useMeasurer = () => {
const state = reactive({
height: window.innerHeight,
width: window.innerWidth,
})
const reportWindowSize = () => {
state.height = window.innerHeight;
state.width = window.innerWidth;
}
onMounted(() => {
window.addEventListener('resize', reportWindowSize);
})
// beforeDestroy 需要替換成 onBeforeUnmount
onBeforeUnmount(() => {
window.removeEventListener('resize', reportWindowSize);
})
return state;
};
export default useMeasurer
```
之後如果要使用測量工具 , 直接引入 useMeasurer 並放在 setup 區塊中就可以舒服的測量尺寸了 :smiley:
```javascript=
<template>
<div>
<span>寬度:{{state.width}}px</span>
<span>高度:{{state.height}}px</span>
</div>
</template>
<script>
import useMeasurer from './useMeasurer.js'
export default {
name: "CompositeMeasurer",
setup() {
return {state: useMeasurer()}
},
}
</script>
```
:::warning
做到這裡本樹產生了一些疑惑 🤔 ,
如果有 2 個 useXXX 函數都用到了 onMounted 最後會如何呢 ?
- 前一個功能被後一個功能覆蓋掉 ?
- 2 個功能都按照預期的執行呢 ?
:::
這時我們來試試看監聽滑鼠移動的事件
```javascript=
import {onMounted, onBeforeUnmount, reactive} from '@vue/composition-api'
const useMouseMove = () => {
const state = reactive({
x: 0,
y: 0,
})
const getMousePosition = e => {
state.x = e.pageX;
state.y = e.pageY;
}
onMounted(() => {
window.addEventListener('mousemove', getMousePosition);
})
onBeforeUnmount(() => {
window.removeEventListener('mousemove', getMousePosition);
})
return state;
};
export default useMouseMove
```
### 成果
<iframe src="https://codesandbox.io/embed/vue-composition-api-1g0uc?fontsize=14&hidenavigation=1&theme=dark"
style="width:100%; height:500px; border:0; border-radius: 4px; overflow:hidden;"
title="vue-composition-api"
allow="accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking"
sandbox="allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts"
></iframe>
:::info
==結論==
如果有兩個 useXXX 都註冊 onMounted 事件 ,
二者不會有衝突 , 都可以正常執行相關的程式 ,
以後我們可以將相關的邏輯拉出來放在 useXXX 統一處理 ,
不用東一塊 . 西一塊了 !
:::
## 參考資料
- [【🚨万字警告】了不起的Vue3(下)](https://juejin.cn/post/6898121032171945992)
- [VueMastery - Vue 3 Composition API](https://www.vuemastery.com/courses/vue-3-essentials/why-the-composition-api)