写在前面

最近想把之前项目中的Pixiv插画展示页给分离出来,于是也就用到了一些以前封装的Vue2组件,顺带着熟悉一下Vue3

其中用到了 createVNode 函数,和Vue2中的组件封装大同小异,但是没有Vue2那么繁琐了

Code

目录结构

index.ts

import {App, render, createVNode} from 'vue';
import ShowImage from "./ShowImage.vue"

const Main = function (urlV: string | string[]) {
    const container = document.createElement('div')
    container.setAttribute("class", "image-show")
    // 创建虚拟 DOM
    const VNode = createVNode(ShowImage, {urlV})
    // 通过 render 函数挂载到页面中
    render(VNode, container)
    document.body.appendChild(container)
};

Main.install = (app: App<Element>) => {
    app.config.globalProperties.$Image = Main;
};

export default Main;

ShowImage.vue

<script setup lang="ts">
import {onMounted, ref} from 'vue'

let props = defineProps<{ urlV: { type: string | string[], default: '' } }>()

let url = ref<string>('')
let urls = ref<string[]>([])
let index = ref<number>(0)
let show = ref<boolean>(false)

const last = () => {
  if (index.value > 0) {
    index.value--;
  }
}

const next = () => {
  if (index.value < urls.value.length - 1) {
    index.value++;
  }
}

const close = () => {
  show.value = false
  let pDom = document.querySelector('.image-show')
  setTimeout(() => {
    if (pDom) pDom.remove()
  }, 300)
}

onMounted(() => {
  let type = typeof props.urlV
  // @ts-ignore
  if (type === 'string') url.value = props.urlV
  // @ts-ignore
  else urls.value = props.urlV
  show.value = true
})

</script>

<template>
  <div name="image-dialog">
    <transition name="ani">
      <div class="border" v-if="show" @click="close()">
        <div class="content">
          <i class="el-icon-arrow-left" v-if="urls.length > 0" @click.stop="last()"></i>
          <img @click.stop :src="urls.length > 0 ? urls[index] : url" alt=""/>
          <i class="el-icon-arrow-right" v-if="urls.length > 0" @click.stop="next()"></i>
        </div>
      </div>
    </transition>
  </div>
</template>

<style scoped lang="scss">
.ani-enter-active,
.ani-leave-active {
  opacity: 1;
  transition: all 0.3s;
}

.ani-enter,
.ani-leave-to {
  opacity: 0;
}

.border {
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  z-index: 9999;
  display: flex;
  align-items: center;
  justify-content: center;
  background-color: rgba(0, 0, 0, .3);

  .content {
    display: flex;
    justify-content: center;
    align-items: center;

    i {
      font-weight: 700;
      color: white;
      background: #409eff;
      border-radius: 100%;
      padding: 5px;
      font-size: 23px;
    }

    img {
      margin: 0 15px;
      max-width: 1000px;
      max-height: 800px;
    }
  }
}
</style>

main.ts中引入

import ShowImage from "./components/ShowImage/index"

let app = createApp(App)
app.use(ShowImage)
app.mount('#app')

调用

const { proxy } = getCurrentInstance() as any;
proxy.$Image("https://alioss.xiamoqwq.com/anime_pic/202206710261970840.png")

这里其实用 $Image() 就可以直接调用了,不过这么写是为了避免编译时ts的报错,也算是规范?


Ex - ploooosion!