美文网首页
物料库之popup

物料库之popup

作者: 羊驼驼驼驼 | 来源:发表于2024-02-29 17:56 被阅读0次

    一、分析一波🌝🌝🌝

    • popup 是独立的组件,放到body下面
    • popup 含两部分内容,一部分为背景蒙版,一部分为内容的包裹容器
    • popup 通过双向绑定的值进行控制展示和隐藏
    • popup 展示时,页面滚动应该被锁定
    • 内容区域应该接收所有的 attrs,并且应该通过插槽让调用方指定其内容

    二、构建🌪️🌪️🌪️

    1. 新建 src/libs/popup/index.vue 文件

    小知识点:v-model双向数据绑定,底层机制defineModel 是一个便利宏。 编译器将其展开为以下内容:

    • 一个名为 modelValue 的 prop,本地 ref 的值与其同步;
    • 一个名为 update:modelValue 的事件,当本地 ref 的值发生变更时触发
    <template>
      <div>
        <!-- teleport -->
        <teleport to="body">
          <!-- 蒙版 -->
          <transition name="fade">
            <div
              v-if="modelValue"
              class="w-screen h-screen bg-zinc-900/80 z-40 fixed top-0 left-0"
              @click="emits('update:modelValue', false)"
            ></div>
          </transition>
          <!-- 内容 -->
          <transition name="popup-down-up">
            <div
              v-if="modelValue"
              v-bind="$attrs"
              class="w-screen bg-white z-50 fixed bottom-0"
            >
              <slot />
            </div>
          </transition>
        </teleport>
      </div>
    </template>
    
    <script setup>
    import { useScrollLock } from '@vueuse/core'
    import { watch } from 'vue'
    const props = defineProps({
      modelValue: {
        required: true,
        type: Boolean
      }
    })
    
    const emits = defineEmits(['update:modelValue'])
    
    // ------ 滚动锁定 ------
    const isLocked = useScrollLock(document.body)
    watch(
      () => props.modelValue,
      (val) => {
        isLocked.value = val
      },
      {
        immediate: true
      }
    )
    </script>
    
    <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>
    

    优化一下:v-model双向数据绑定,由于不可以在子组件直接修改响应式数据,所以有一些不太方便,那应该怎么优化呢?可以使用vueuse 提供的 useVModel,通过 useVModel 获取到响应式数据,当响应式数据的状态变化时,自动触发 update:modelValue

    <template>
    <!-- 无需主动触发 事件 -->
    <div
      v-if="isOpen"
      class="w-screen h-screen bg-zinc-900/80 z-40 fixed top-0 left-0"
      @click="isOpen = false"
    ></div>
    <div
      v-if="isOpen"
      v-bind="$attrs"
      class="w-screen bg-white z-50 fixed bottom-0"
    >
      <slot />
    </div>
    ...
    </template>
    
    <script setup>
    import { useVModel } from '@vueuse/core'
    ...
    // 不需要主动触发了
    // const emits = defineEmits(['update:modelValue'])
    
    // 通过 useVModel 获取到响应式数据 isOpen
    const isOpen = useVModel(props)
    
    ...
    // 监听 isOpen 的变化即可
    watch(
      isOpen,
      ...
    )
    </script>
    
    2. 小试牛刀 demo.vue
    <template>
    <m-popup v-model="isOpenPopup">
      <div>测试m-popup</div>
    </m-popup>
    </template>
    
    <script setup>
    // 控制popup显示/隐藏
    const isOpenPopup = ref(true);
    </script>
    

    相关文章

      网友评论

          本文标题:物料库之popup

          本文链接:https://www.haomeiwen.com/subject/gjuqzdtx.html