目录
一、组件代码
(1)在src/libs/popup/index.vue中写如下代码
javascript
<script setup>
import { useScrollLock, useVModel } from '@vueuse/core'
import { watch } from 'vue'
const props = defineProps({
modelValue: {
required: true,
type: Boolean
}
})
// const emits = defineEmits(['update:modelValue']) // 不用这个的原因是,下面的useVModel直接监听到props的变化,然后自动触发update:modelValue
const isOpen = useVModel(props)
// ----- 滚动锁定 -----
const isLocked = useScrollLock(document.body)
watch(
isOpen,
() => props.modelValue,
(val) => {
isLocked.value = val
},
{
immediate: true
}
)
</script>
<template>
<div class="">
<!-- teleport -->
<teleport to="body">
<!-- 蒙版 -->
<transition name="fade">
<div
v-if="isOpen"
class="w-screen h-screen bg-zinc-900/80 z-40 fixed top-0 left-0"
@click="isOpen = false"
></div>
</transition>
<!-- 内容 -->
<transition name="popup-down-up">
<div
v-if="isOpen"
v-bind="$attrs"
class="w-screen bg-white z-50 fixed bottom-0 dark:bg-zinc-800"
>
<slot />
</div>
</transition>
</teleport>
</div>
</template>
<style lang="scss" scoped>
// fade 展示动画
.fade-enter-active {
transition: all 0.3s;
}
.fade-leave-active {
transition: all 0.3s;
}
.fade-enter-from,
.fade-leave-to {
opacity: 0;
}
// popup-down-up 展示动画
.popup-down-up-enter-active {
transition: all 0.3s;
}
.popup-down-up-leave-active {
transition: all 0.3s;
}
.popup-down-up-enter-from,
.popup-down-up-leave-to {
transform: translateY(100%);
}
</style>
(2)src/libs/index.js中注册该组件
javascript
import { defineAsyncComponent } from 'vue'
export default {
install(app) {
const components = import.meta.glob('./*/index.vue')
for (const [key, value] of Object.entries(components)) {
const componentName = 'm-' + key.replace('./', '').split('/')[0]
app.component(componentName, defineAsyncComponent(value))
}
}
}
二、使用组件
在src/views/main/components/navigation/mobile/index.vue中使用组件
javascript
<!-- 汉堡按钮 -->
<li
...
@click="isOpenPopup = !isOpenPopup"
>
...
</li>
<m-popup v-model="isOpenPopup">
<div>测试内容</div>
</m-popup>
然后就可以在这个组件的插槽里面放入相应的数据了
至此,这个弹窗组件完成!
三、在插槽中放入业务组件
这里就是展示一个弹出的菜单
(1)组件代码
src/views/main/components/menu/index.vue
javascript
<script setup>
defineEmits(['onItemClick'])
//这里的数据是从vuex获取的,也可以从使用组件的地方传过来
</script>
<template>
<div class="py-2 h-[80vh] flex flex-col">
<h2 class="text-xl text-zinc-900 font-bold mb-2 px-1 dark:text-zinc-200">所有分类</h2>
<ul class="overflow-y-scroll">
<li
v-for="(item, index) in $store.getters.categorys"
:key="item.id"
class="text-lg text-zinc-900 px-1 py-1.5 duration-100 active:bg-zinc-100 dark:text-zinc-300 dark:active:bg-zinc-900"
@click="$emit('onItemClick', index)"
>
{{ item.name }}
</li>
</ul>
</div>
</template>
<style lang="scss" scoped></style>
(2)在popup中绑定业务组件中触发的点击事件
javascript
<m-popup v-model="isOpenPopup">
<menu-vue @onItemClick="onItemClick"></menu-vue>
</m-popup>
const onItemClick = (index) => {
currentCategoryIndex.value = index
isOpenPopup.value = false
}
至此,整个弹窗封装完成!