系列前幾個組件都是用vue2編寫的,此次用最新的vue3編寫, vue3也出了一段時間,公司也不會牟然換版本,因此不多實踐的機會,那就只可以本身寫一個組件實踐下,看了一下vue3的文檔,最大變化,就是setup函數和Composition Api這塊,此次我主要也是說說這部分的使用過程。javascript
另外組件也是經常使用的組件,通常用在電商類網站產品詳情頁,鼠標移到圖片位置放大圖片,具體怎實現就不詳說 如圖:css
vue2中,咱們會在methods,computed,watch,data中等等定義屬性和方法,共同處理頁面邏輯,咱們稱這種方式爲Options API。相信用過的都知道,方即是挺方便,不過缺點也很明顯,當項目愈來愈大,極可能一個methods下就有二三十個方法, 還得確切地知道方法中能夠訪問哪些屬性以及this關鍵字的行爲,維護起來就十分麻煩了。Composition API(組合API)就是解決這個問題而生的。另外vue3是向下兼容的,也就是說容許咱們用vue2的寫法在vue3寫,但既然是個新東西,咱們就要嘗試體驗,看看有什麼改變給本身帶來什麼便利。vue
Composition API它相似 react hooks寫法。此次我直接用 setup 的語法糖編寫這個組件。java
什麼是setup 語法糖?想要使用 setup
模式只要在 script
標籤上面加個 setup
屬性就能夠了。這個模式下不須要 return
和 export
就能夠在模板中使用。react
<script setup>
</script>
複製代碼
先上組件完整代碼編程
<script setup>
<template> <div class="imgBox" ref="imgbox"> <slot></slot> <div class="mask" v-show="state.isShow" :style="{ left:state.maskX + 'px', top :state.maskY +'px'}"> </div> </div> <transition name="fade"> <div class="zoomBox" v-show="state.isShow" :style="{left :state.boxX +'px',top: state.boxY +'px',}"> <img :src="state.imgSrc" :style="{ width:state.zoomImgWidth + 'px', height: state.zoomImgHeight + 'px', marginLeft :-state.bImgX + 'px', marginTop : -state.bImgY + 'px' }"> </div> </transition> </template> <script setup> import {defineProps, onMounted, onUnmounted, reactive, ref} from 'vue' const maskWidth = 50, maskHeight = 50 const imgbox = ref(null) const props = defineProps({mode: String}) const state = reactive({ zoomImgWidth: 0, zoomImgHeight: 0, isShow: false, boxX: 0, boxY: 0, maskX: 0, maskY: 0, bImgX: 0, bImgY: 0, imgSrc: '' }) const zommIn = (ev) => { const img = ev.currentTarget.getElementsByTagName('img')[0] const {offsetWidth, offsetTop, offsetHeight} = imgbox.value state.zoomImgWidth = offsetWidth * 3 state.zoomImgHeight = offsetHeight * 3 state.imgSrc = img.src state.boxX = offsetWidth state.boxY = offsetTop state.isShow = true } const zoomMove = (ev) => { const {clientX, clientY} = ev const {offsetTop, offsetLeft} = ev.currentTarget const {offsetWidth, offsetHeight} = imgbox.value let mx = clientX - offsetLeft - (maskWidth / 2), my = clientY - offsetTop - (maskHeight / 2) mx = mx < 0 ? 0 : mx my = my < 0 ? 0 : my if (mx > offsetWidth - maskWidth / 2) { mx = offsetWidth - maskWidth / 2 } if (my > offsetHeight - maskHeight / 2) { my = offsetHeight - maskHeight / 2 } state.maskX = mx state.maskY = my state.bImgX = mx * (state.zoomImgWidth - offsetWidth) / (offsetWidth - maskWidth) state.bImgY = my * (state.zoomImgWidth - offsetWidth) / (offsetWidth - maskWidth) } const zommOut = () => { state.isShow = false } //綁定方法 onMounted(() => { imgbox.value.addEventListener('mouseover', zommIn) imgbox.value.addEventListener('mousemove', zoomMove) imgbox.value.addEventListener('mouseout', zommOut) }) onUnmounted(() => { imgbox.value.removeEventListener('mouseover', ()=>{}) imgbox.value.removeEventListener('mousemove', ()=>{}) imgbox.value.removeEventListener('mouseout', ()=>{}) }) </script> <style scoped> .mask { width: 50px; height: 50px; background-color: #fff; opacity: .6; cursor: crosshair; position: absolute; } .imgBox { position: relative; overflow: hidden; width: 200px; height: 200px; } .zoomBox { width: 200px; height: 200px; position: absolute; border: 1px solid #eee; background: #fff; overflow: hidden; } .fade-enter-active, .fade-leave-active { transition: opacity .5s } .fade-enter, .fade-leave-active { opacity: 0 } </style> </script>
複製代碼
看到這種模式編程,不就是函數式編程嗎!!接下來我就說說我是怎樣使用這些APIapi
1.依賴注入defineProps
, onMounted
, onUnmounted
, reactive
, ref
這些函數都是在這個組件用到的,看到函數的命名,是否是有點似曾相識的感受呢,沒錯,除了reactive
比較陌生 其餘就是你想的!markdown
import {defineProps, onMounted, onUnmounted, reactive, ref} from 'vue'
複製代碼
2.defineProps
這個至關於props,組件傳入的參數,而後經過保存props變量讀取dom
const props = defineProps({mode: String})
複製代碼
reactive
這個方式相似於咱們設置的data選項, 但綁定到模板上就須要帶上state
這個函數目的是爲了觀察引用數據類型。想直接綁定變量到模板上能夠經過toRefs
解構模板變量。const state = reactive({
zoomImgWidth: 0,
zoomImgHeight: 0,
isShow: false,
boxX: 0,
boxY: 0,
maskX: 0,
maskY: 0,
bImgX: 0,
bImgY: 0,
imgSrc: ''
})
複製代碼
4.ref
這個也是相似設置data的選項, 但它通常是觀察原始數據類型,另外還能夠相似vue2經過綁定ref獲取dom信息,此次的ref我也是用在獲取dom信息,固然你也能夠用來設置可觀察數據ssh
// 綁定ref
<div class="imgBox" ref="imgbox"></div>
//獲取dom信息
const imgbox = ref(null)
複製代碼
5.onMounted
和 onUnmounted
這兩個方法相似 mounted 的鉤子函數, 相信熟悉vue的對鉤子應該也不會陌生,這裏我直接作事件監聽
onMounted(() => {
imgbox.value.addEventListener('mouseover', zommIn)
imgbox.value.addEventListener('mousemove', zoomMove)
imgbox.value.addEventListener('mouseout', zommOut)
})
onUnmounted(() => {
imgbox.value.removeEventListener('mouseover', ()=>{})
imgbox.value.removeEventListener('mousemove', ()=>{})
imgbox.value.removeEventListener('mouseout', ()=>{})
})
複製代碼
組件調用也簡化了,直接import
進來,不用在components
註冊組件。
import zoom from './components/zoom.vue'
<zoom>
<img alt="Vue logo" src="./assets/logo.png"/>
</zoom>
複製代碼
vue3還提供不少api 在這個組件沒用到 ,如emit、watch、computed、provide、inject、還有各生命週期鉤子函數,這些都是在vue2 熟悉的東西 ,但在vue3容許你用其餘形式來編寫,喜歡這種編寫方式,就會感受寫得很爽。 對於用react的同窗也是能夠無縫接入,很快就能夠上手,反之在vue3用過Composition Api的同窗去學習react hooks 也是很容易上手。