# 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)