系列前几个组件都是用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 也是很容易上手。