Selaa lähdekoodia

fix: 抽离弹出框 hoo,解决bug

MTrun 3 vuotta sitten
vanhempi
sitoutus
3ee85b7c7b

+ 1 - 1
src/components/AppleControlBtn/index.vue

@@ -4,7 +4,7 @@
       <div
         class="btn"
         :class="[item.key, disabled && 'disabled']"
-        @click="handleClick(item.key)"
+        @click.stop="handleClick(item.key)"
       >
         <n-icon size="10" class="icon-base" :class="{ hover: !disabled }">
           <component :is="item.icon" />

+ 3 - 1
src/styles/common/_dark.scss

@@ -18,5 +18,7 @@ $dark: (
     filter-color: $--filter-color-login-dark,
   // 物料市场背景
     items-top-bg:
-    linear-gradient(180deg, $--color-dark-bg-1, rgba(23, 23, 26, 0))
+    linear-gradient(180deg, $--color-dark-bg-1, rgba(23, 23, 26, 0)),
+  // hover 边框颜色
+    hover-border-color: #55606e,
 );

+ 3 - 1
src/styles/common/_light.scss

@@ -17,5 +17,7 @@ $light: (
       linear-gradient(90deg, transparent 14px, $--color-dark-bg-5 0)
     ),
   //毛玻璃
-    filter-color: $--filter-color-login-light
+    filter-color: $--filter-color-login-light,
+  // hover 边框颜色
+    hover-border-color: $--color-light-fill-1
 );

+ 7 - 0
src/styles/common/mixins/mixins.scss

@@ -65,3 +65,10 @@
     border-color: themed($target);
   }
 }
+
+//获取边框颜色
+@mixin hover-border-color($target) {
+  @include themeify {
+    border: 1px solid themed($target);
+  }
+}

+ 30 - 6
src/styles/common/style.scss

@@ -44,27 +44,51 @@
 // todo 使用 scss 循环写一套完整的
 // margin
 .go-mt-0 {
-  margin-top: 0;
+  margin-top: 0!important;
 }
 
 .go-mb-0 {
-  margin-bottom: 0;
+  margin-bottom: 0!important;
+}
+.go-ml-0 {
+  margin-left: 0!important;
 }
 
-.go-mx-0 {
+.go-mr-0 {
+  margin-right: 0!important;
+}
+
+.go-my-0 {
   @extend .go-mt-0;
   @extend .go-mb-0;
 }
 
+.go-mx-0 {
+  @extend .go-ml-0;
+  @extend .go-mr-0;
+}
+
 .go-pt-0 {
-  padding-top: 0;
+  padding-top: 0!important;
 }
 
 .go-pb-0 {
-  padding-bottom: 0;
+  padding-bottom: 0!important;
+}
+.go-pl-0 {
+  padding-left: 0!important;
 }
 
-.go-px-0 {
+.go-pr-0 {
+  padding-right: 0!important;
+}
+
+.go-py-0 {
   @extend .go-pt-0;
   @extend .go-pb-0;
 }
+
+.go-px-0 {
+  @extend .go-pl-0;
+  @extend .go-pr-0;
+}

+ 39 - 1
src/utils/utils.ts

@@ -1,6 +1,7 @@
 import { h } from 'vue'
 import { NIcon } from 'naive-ui'
 import screenfull from 'screenfull'
+import debounce from 'lodash/debounce'
 
 /**
  * * 生成一个用不重复的ID
@@ -28,6 +29,7 @@ export const renderIcon = (icon: any, set = {}) => {
 export const requireUrl = (path: string, name: string) => {
   return new URL(`${path}/${name}`, import.meta.url).href
 }
+
 /**
  * * 获取错误处理图片,默认 404 图
  * @param path
@@ -36,7 +38,10 @@ export const requireUrl = (path: string, name: string) => {
  */
 export const requireFallbackImg = (path?: string, name?: string) => {
   const url = path && name
-  return new URL(url?`${path}/${name}`: '../assets/images/exception/image-404.png', import.meta.url).href
+  return new URL(
+    url ? `${path}/${name}` : '../assets/images/exception/image-404.png',
+    import.meta.url
+  ).href
 }
 
 export const screenfullFn = (isFullscreen?: boolean, isEnabled?: boolean) => {
@@ -53,3 +58,36 @@ export const screenfullFn = (isFullscreen?: boolean, isEnabled?: boolean) => {
   // TODO lang
   window['$message'].warning('您的浏览器不支持全屏功能!')
 }
+
+/**
+ * * 挂载监听
+ * @returns url
+ */
+export const goAddEventListener = <K extends keyof WindowEventMap>(
+  target: EventTarget,
+  type: K,
+  listener: EventListenerOrEventListenerObject,
+  options?: boolean | AddEventListenerOptions | undefined
+) => {
+  if(!target) return
+  target.addEventListener(
+    type,
+    debounce(listener, 300, {
+      leading: true,
+      trailing: false
+    }),
+    options
+  )
+}
+/**
+ * * 卸载监听
+ * @returns url
+ */
+export const goRemoveEventListener = <K extends keyof WindowEventMap>(
+  target: EventTarget,
+  type: K,
+  listener: EventListenerOrEventListenerObject
+) => {
+  if(!target) return
+  target.removeEventListener(type, listener)
+}

+ 8 - 1
src/views/project/items/components/Card/index.vue

@@ -12,7 +12,7 @@
           />
         </div>
         <!-- 中间 -->
-        <div class="list-content-img">
+        <div class="list-content-img"  @click="resizeHandle">
           <n-image
             object-fit="contain"
             height="200"
@@ -184,9 +184,16 @@ const resizeHandle = () => {
 $contentHeight: 200px;
 @include go('items-list-card') {
   position: relative;
+  border-radius: $--border-radius-base;
+  border: 1px solid rgba(0, 0, 0, 0);
+  @extend .go-transition;
+  &:hover {
+    @include hover-border-color('hover-border-color');
+  }
   .list-content {
     margin-top: 20px;
     margin-bottom: 5px;
+    cursor: pointer;
     border-radius: $--border-radius-base;
     @include background-point('background-point');
     @extend .go-point-bg;

+ 53 - 0
src/views/project/items/components/List/hooks/useData.hook.ts

@@ -0,0 +1,53 @@
+import { ref, Ref } from 'vue'
+import { goDialog } from '@/utils'
+import { DialogEnum } from '@/enums/pluginEnum'
+
+// 数据初始化
+export const useDataListInit = () => {
+  const list = ref<object[]>([
+    {
+      id: 1,
+      title: '物料1',
+      release: true
+    },
+    {
+      id: 2,
+      title: '物料2',
+      release: false
+    },
+    {
+      id: 3,
+      title: '物料3',
+      release: false
+    },
+    {
+      id: 4,
+      title: '物料4',
+      release: false
+    },
+    {
+      id: 5,
+      title: '物料5',
+      release: false
+    }
+  ])
+
+  // 删除
+  const deleteHandle = (cardData: object, index: number) => {
+    goDialog({
+      type: DialogEnum.delete,
+      promise: true,
+      onPositiveCallback: () =>
+        new Promise(res => setTimeout(() => res(1), 1000)),
+      promiseResCallback: (e: any) => {
+        window.$message.success('删除成功')
+        list.value.splice(index, 1)
+      }
+    })
+  }
+
+  return {
+    list,
+    deleteHandle
+  }
+}

+ 27 - 0
src/views/project/items/components/List/hooks/useModal.hook.ts

@@ -0,0 +1,27 @@
+import { ref, Ref } from 'vue'
+
+export const useModalDataInit = () => {
+  const modalShow = ref<boolean>(false)
+  const modalData = ref<object | unknown>(null)
+
+  // 关闭 modal
+  const closeModal = () => {
+    modalShow.value = false
+    modalData.value = null
+    console.log('close')
+  }
+
+  // 打开 modal
+  const resizeHandle = (cardData: Ref<object | unknown>) => {
+    console.log(cardData)
+    modalShow.value = true
+    modalData.value = cardData
+  }
+
+  return {
+    modalData,
+    modalShow,
+    closeModal,
+    resizeHandle
+  }
+}

+ 6 - 58
src/views/project/items/components/List/index.vue

@@ -15,74 +15,22 @@
       </n-grid-item>
     </n-grid>
   </div>
-  <ModalCard :show="modalShow" :cardData="modalData" @close="closeModal" />
+  <ModalCard v-model:show="modalShow" :cardData="modalData" @close="closeModal" />
 </template>
 
 <script setup lang="ts">
-import { reactive, ref } from 'vue'
+import { ref } from 'vue'
 import { Card } from '../Card/index'
 import { ModalCard } from '../ModalCard/index'
-import { goDialog } from '@/utils'
-import { DialogEnum } from '@/enums/pluginEnum'
 import { icon } from '@/plugins'
+import { useModalDataInit } from './hooks/useModal.hook'
+import { useDataListInit } from './hooks/useData.hook'
 
 const { CopyIcon, EllipsisHorizontalCircleSharpIcon } = icon.ionicons5
 
-const list = ref([
-  {
-    id: 1,
-    title: '物料1',
-    release: true
-  },
-  {
-    id: 2,
-    title: '物料2',
-    release: false
-  },
-  {
-    id: 3,
-    title: '物料3',
-    release: false
-  },
-  {
-    id: 4,
-    title: '物料4',
-    release: false
-  },
-  {
-    id: 5,
-    title: '物料5',
-    release: false
-  }
-])
-
-const modalData = ref({})
-const modalShow = ref(false)
-
-// 删除
-const deleteHandle = (cardData: object, index: number) => {
-  goDialog({
-    type: DialogEnum.delete,
-    promise: true,
-    onPositiveCallback: () =>
-      new Promise(res => setTimeout(() => res(1), 1000)),
-    promiseResCallback: (e: any) => {
-      window.$message.success('删除成功')
-      list.value.splice(index, 1)
-    }
-  })
-}
+const { modalData, modalShow, closeModal, resizeHandle } = useModalDataInit()
 
-// 关闭 modal
-const closeModal = () => {
-  modalShow.value = false
-}
-
-// 打开 modal
-const resizeHandle = (cardData: object) => {
-  modalShow.value = true
-  modalData.value = cardData
-}
+const { list, deleteHandle } = useDataListInit()
 </script>
 
 <style lang="scss" scoped>

+ 84 - 76
src/views/project/items/components/ModalCard/index.vue

@@ -1,76 +1,77 @@
 <template>
-  <n-modal class="go-modal-card" v-model:show="showModal">
-    <slot name="default">
-      <n-card hoverable size="small">
-        <div class="list-content">
-          <!-- 顶部按钮 -->
-          <n-space class="list-content-top">
-            <AppleControlBtn
-              :narrow="true"
-              :hidden="['close']"
-              @remove="closeHandle"
-            />
+  <!-- mask-closable 暂时是失效的,不知道为啥 -->
+  <n-modal
+    class="go-modal-box"
+    v-model:show="show"
+    @on-after-leave="closeHandle"
+  >
+    <n-card hoverable size="small">
+      <div class="list-content">
+        <!-- 标题 -->
+        <n-space class="list-content-top go-px-0" justify="center">
+          <n-space>
+            <n-text>
+              {{ cardData?.title || '' }}
+            </n-text>
           </n-space>
-          <!-- 中间 -->
-          <div class="list-content-img">
-            <img
-              :src="
-                requireUrl(
-                  '../assets/images/project',
-                  'moke-20211219181327.png'
-                )
-              "
-              :alt="cardData?.title"
-            />
-          </div>
+        </n-space>
+        <!-- 顶部按钮 -->
+        <n-space class="list-content-top">
+          <AppleControlBtn
+            :narrow="true"
+            :hidden="['close']"
+            @remove="closeHandle"
+          />
+        </n-space>
+        <!-- 中间 -->
+        <div class="list-content-img">
+          <img
+            :src="
+              requireUrl('../assets/images/project', 'moke-20211219181327.png')
+            "
+            :alt="cardData?.title"
+          />
         </div>
-        <template #action>
-          <n-space class="list-footer" justify="space-between">
-            <n-space>
-              <n-text>
-                {{ cardData?.title || '' }}
-              </n-text>
-              <n-text depth="3">
-                最后编辑于:
-                <n-time
-                  :time="new Date()"
-                  format="yyyy-MM-dd hh:mm"
-                />
-              </n-text>
-            </n-space>
-            <!-- 工具 -->
-            <n-space>
-              <n-text>
-                <n-badge
-                  class="animation-twinkle"
-                  dot
-                  :color="cardData?.release ? '#34c749' : '#fcbc40'"
-                />
-                {{ cardData?.release ? '已发布' : '未发布' }}
-              </n-text>
+      </div>
+      <template #action>
+        <n-space class="list-footer" justify="space-between">
+          <n-text depth="3">
+            最后编辑于:
+            <n-time :time="new Date()" format="yyyy-MM-dd hh:mm" />
+          </n-text>
+          <!-- 工具 -->
+          <n-space>
+            <n-text>
+              <n-badge
+                class="animation-twinkle"
+                dot
+                :color="cardData?.release ? '#34c749' : '#fcbc40'"
+              />
+              {{ cardData?.release ? '已发布' : '未发布' }}
+            </n-text>
 
-              <template v-for="item in fnBtnList" :key="item.key">
-                <n-tooltip placement="bottom" trigger="hover">
-                  <template #trigger>
-                    <n-button size="small">
-                      <template #icon>
-                        <component :is="item.icon" />
-                      </template>
-                    </n-button>
-                  </template>
-                  <span> {{ item.label }}</span>
-                </n-tooltip>
-              </template>
-            </n-space>
-            <!-- end -->
+            <template v-for="item in fnBtnList" :key="item.key">
+              <n-tooltip placement="bottom" trigger="hover">
+                <template #trigger>
+                  <n-button size="small">
+                    <template #icon>
+                      <component :is="item.icon" />
+                    </template>
+                  </n-button>
+                </template>
+                <span> {{ item.label }}</span>
+              </n-tooltip>
+            </template>
           </n-space>
-        </template>
-      </n-card>
-    </slot>
+          <!-- end -->
+        </n-space>
+      </template>
+    </n-card>
   </n-modal>
 </template>
 
 <script setup lang="ts">
+import { watchEffect } from 'vue'
 import { renderIcon, requireUrl, requireFallbackImg } from '@/utils'
 import { icon } from '@/plugins'
 import { AppleControlBtn } from '@/components/AppleControlBtn'
@@ -79,13 +80,17 @@ const { HammerIcon } = icon.ionicons5
 const emit = defineEmits(['close'])
 
 const props = defineProps({
-  modalShow: Boolean,
+  show: Boolean,
   cardData: Object
 })
 
-const handleSelect = (key: string) => {
-  console.log(key)
-}
+// 解决点击模态层不会触发 @on-after-leave 的问题
+watchEffect(() => {
+  if (!props.show && props.cardData) {
+    closeHandle()
+  }
+})
+
 const fnBtnList = [
   {
     label: '编辑',
@@ -93,8 +98,6 @@ const fnBtnList = [
     icon: renderIcon(HammerIcon)
   }
 ]
-// 放大处理
-const resizeHandle = () => {}
 
 // 关闭对话框
 const closeHandle = () => {
@@ -105,9 +108,10 @@ const closeHandle = () => {
 <style lang="scss" scoped>
 $padding: 30px;
 $contentHeight: calc(80vh);
-@include go('modal-card') {
-  position: relative;
-  width: 82vw;
+$contentWidth: calc(82vw);
+
+@include go('modal-box') {
+  width: $contentWidth;
   .list-content {
     margin-top: 20px;
     border-radius: $--border-radius-base;
@@ -116,14 +120,18 @@ $contentHeight: calc(80vh);
     @extend .go-point-bg;
     &-top {
       position: absolute;
-      top: 10px;
-      left: 10px;
+      top: 7px;
+      left: 0px;
+      padding-left: 10px;
       height: 22px;
+      width: $contentWidth;
     }
     &-img {
       @extend .go-flex-center;
       img {
-        height: $contentHeight;
+        max-height: $contentHeight;
+        min-height: 200px;
+        max-width: 100%;
         @extend .go-border-radius;
       }
     }

+ 4 - 3
src/views/project/mtTemplate/index.vue

@@ -3,21 +3,22 @@
     <n-space vertical>
       <n-image
         object-fit="contain"
-        height="400"
+        height="300"
         preview-disabled
         :src="requireFallbackImg()"
       />
-      <n-h1>没有东西呢</n-h1>
+      <n-h3>暂时还没有东西呢</n-h3>
     </n-space>
   </div>
 </template>
 
 <script setup lang="ts">
-import { requireUrl, requireFallbackImg } from '@/utils'
+import { requireFallbackImg } from '@/utils'
 </script>
 
 <style lang="scss" scoped>
 @include go('project-my-template') {
+  margin-top: 100px;
   @extend .go-flex-center;
 }
 </style>