文章目录
- 一、前言
- 二、自动注册全局组件
- 2.1、自动注册`components`目录下所有`vue`组件并以组件的文件名为组件的名称
- 2.2、使用这个插件
- 2.3、为全局组件添加类型提示
- 三、函数式图片预览
- 四、手动封装 `svgIcon` 组件
- 五、封装拖拽钩子函数
- 六、`vscode` 中 `vue3` 代码片段
- 七、最后
一、前言
本文主要分享一下在使用vue3
开发项目时的一些常用功能
二、自动注册全局组件
2.1、自动注册components
目录下所有vue
组件并以组件的文件名为组件的名称
// components/index.tsimport { type App, defineAsyncComponent } from 'vue'
const components = Object.entries(import.meta.glob('./**/*.vue'))
const preFix = 'Es'
export default {// use 的时候install: (app: App) => {components.forEach(([key, comp]) => {// 得到组件的名称const name = getCompName(comp.name || key)app.component(preFix + name, defineAsyncComponent(comp as any))})}
}function getCompName(key: string) {const nameReg = //(\w+).vue/return nameReg.test(key) ? key.match(nameReg)![1] : key
}
- 使用
import.meta.glob
动态导入所有以.vue
结尾的文件,并将它们作为键值对的形式存储在components
变量中。 - 在
install
方法中,通过遍历components
数组,对每个组件进行注册 - 通过
comp.name
获取组件的名称,如果名称不存在,则使用组件的路径 key。然后,使用defineAsyncComponent
将组件定义为异步组件 getCompName
函数用于从组件路径中提取组件的名称。使用正则对组件路径进行匹配,提取出路径中最后一个斜杠后的单词作为组件名称
2.2、使用这个插件
import { createApp } from 'vue'
import App from './App.vue'import MyComponents from './components'createApp(App).use(MyComponents).mount('#app')
自动注册全局组件虽然很方便,但在使用时缺少了ts
类型提示,下面介绍一下为全局组件添加类型提示
2.3、为全局组件添加类型提示
这需要我们自己编写.d.ts
声明文件
// src/typings/component.d.ts
export {}declare module 'vue' {export interface GlobalComponents {EsDialog: typeof import('../components/Dialog.vue')['default']}
}
三、函数式图片预览
图片预览是一个比较常用的功能,封装成函数调用可以简化我们使用的方式
基于 element-plus
的 ElImageViewer
组件
对于有类似的功能都可以使用这种方式,例如我们想使用函数调用的方式弹窗
// utils/preview.ts
import { createVNode, render } from 'vue'
import { ElImageViewer, ImageViewerProps } from 'element-plus'type PreviewOption = Partial<ImageViewerProps>export function preview(option: PreviewOption) {const container = document.createElement('div')let vm = createVNode(ElImageViewer, {...option,onClose() {render(null, container)}})// 将组件渲染成真实节点render(vm, container)document.body.appendChild(container.firstElementChild!)
}
preview
函数接受一个option
参数,它是PreviewOption
(ImageViewerProps
类型的部分可选类型) 类型的对象,用于配置图片预览的选项。- 函数内部,首先创建了一个
div
元素作为容器,用于渲染预览组件。 - 使用
createVNode
创建了一个ElImageViewer
组件实例vm
- 使用
render
方法将vm
渲染为真实的节点,并将其挂载到之前创建的容器中,最后添加到body
页面上 - 传入的
props
中 监听close
事件移除节点
调用
preview({urlList: ['https://fuss10.elemecdn.com/0/6f/e35ff375812e6b0020b6b4e8f9583jpeg.jpeg'],initialIndex: 0
})
四、手动封装 svgIcon
组件
这节主要是vangle
组件库的icon
组件封装方式的介绍,为想自己手动封装svgIcon
组件的朋友可以作个参考
以下是代码实现
Icon.vue
<template><i class="es-icon" :style="style" v-html="icon"></i>
</template><script lang="ts" setup>
import { computed, CSSProperties } from 'vue'
import { IconProps, getIcon } from './icon'const props = defineProps(IconProps)const icon = computed(() => getIcon(props.name))
const style = computed<CSSProperties>(() => {if (!props.size && !props.color) return {}return {fontSize: typeof props.size === 'string' ? props.size : `${props.size}px`,'--color': props.color,}
})
</script><style scoped lang="scss">
.es-icon {--color: inherit;height: 1em;width: 1em;line-height: 1em;display: inline-flex;justify-content: center;align-items: center;position: relative;fill: currentColor;color: var(--color);font-size: inherit;font-style: normal;svg {height: 1em;width: 1em;}
}
</style>
- 以下是
getIcon
的实现icon.ts
export const svgs = import.meta.glob('./svg/*.svg', { eager: true, as: 'raw' })
export const IconProps = {name: String,color: String,size: [String, Number]
}export const getIcon = (name?: string) => {if (!name) return ''return svgs[`./svg/${name}.svg`]
}
使用 import.meta.glob
动态导入svg
目录下所有以 .svg
结尾的文件,as: 'raw'
表示导入的文件内容以原始字符串形式保存
getIcon
根据name
获取svg
的内容
- 直接使用
<es-icon name="add-location" />
<es-icon name="add-location" color="pink" />
<es-icon name="add-location" color="pink" :size="30" />
五、封装拖拽钩子函数
import { onBeforeUnmount, onMounted, watchEffect, Ref } from 'vue'export const useDraggable = (targetRef: Ref<HTMLElement | undefined>,dragRef: Ref<HTMLElement | undefined>,draggable: Ref<boolean>
) => {// 保存偏移量let transform = {offsetX: 0,offsetY: 0,}const onMousedown = (e: MouseEvent) => {const downX = e.clientXconst downY = e.clientYconst { offsetX, offsetY } = transform// 获取拖拽目标的位置和尺寸信息const targetRect = targetRef.value!.getBoundingClientRect()const targetTop = targetRect.topconst targetWidth = targetRect.widthconst targetHeight = targetRect.height// 计算拖拽目标在页面中的可移动范围const clientWidth = document.documentElement.clientWidthconst clientHeight = document.documentElement.clientHeightconst minLeft = -targetRect.left + offsetXconst minTop = -targetTop + offsetYconst maxLeft = clientWidth - targetRect.left - targetWidth + offsetXconst maxTop = clientHeight - targetTop - targetHeight + offsetYconst onMousemove = (e: MouseEvent) => {// 计算移动后的位置/*** offsetX + e.clientX - downX: 初始偏移量 offsetX 加上 e.clientX - downX 移动的距离得到拖拽元素在水平方向上的新位置。* Math.max(offsetX + e.clientX - downX, minLeft) 确保新位置大于等于最小可移动位置 minLeft,即不超出左边界* Math.min(..., maxLeft) 确保新位置小于等于最大可移动位置 maxLeft,即不超出右边界。这样做的目的是防止拖拽元素移出指定的范围。*/const moveX = Math.min(Math.max(offsetX + e.clientX - downX, minLeft),maxLeft)// 和上面同理const moveY = Math.min(Math.max(offsetY + e.clientY - downY, minTop),maxTop)// 更新偏移量和元素位置transform = {offsetX: moveX,offsetY: moveY,}targetRef.value!.style.transform = `translate(${moveX}px, ${moveY}px)`}const onMouseup = () => {// 移除事件监听document.removeEventListener('mousemove', onMousemove)document.removeEventListener('mouseup', onMouseup)}// 监听鼠标移动和鼠标抬起事件document.addEventListener('mousemove', onMousemove)document.addEventListener('mouseup', onMouseup)}const onDraggable = () => {if (dragRef.value && targetRef.value) {dragRef.value.addEventListener('mousedown', onMousedown)}}const offDraggable = () => {if (dragRef.value && targetRef.value) {dragRef.value.removeEventListener('mousedown', onMousedown)}}onMounted(() => {watchEffect(() => {if (draggable.value) {onDraggable()} else {offDraggable()}})})onBeforeUnmount(() => {offDraggable()})
}
useDraggable
的函数,接受三个参数:
targetRef
:拖拽目标Ref
dragRef
:拖拽触发区域Ref
draggable
: 开启/关闭拖拽
在函数内部定义了一个变量 transform
,用于保存拖拽过程中的偏移量。
- 在
onMousedown
函数中,首先记录下鼠标按下时的坐标downX
和downY
,以及当前的偏移量offsetX
和offsetY
- 获取拖拽目标元素的位置和尺寸信息,计算出拖拽目标在页面中可移动的范围。
- 移动时
onMousemove
中,根据鼠标移动的位置计算出新的偏移量moveX
和moveY
,并更新transform
对象和拖拽目标元素的位置 - 最后,定义了一个
onMouseup
函数,当鼠标抬起时执行的事件处理函数。在函数内部,移除鼠标移动和鼠标抬起事件的监听。
六、vscode
中 vue3
代码片段
针对 Vue 3.2+
的代码片段模板,用于在 VSCode
中快速生成 Vue
组件的模板代码
在项目的 .vscode
目录下创建一个名为 vue3.2.code-snippets
的文件,它是一个 JSON
格式的代码片段文件
{"Vue3.2+快速生成模板": {"prefix": "Vue3.2+","body": ["<template>","\t<div>\n","\t</div>","</template>\n","<script setup lang='ts'>","</script>\n","<style lang='scss' scoped>\n","</style>","$2"],"description": "Vue3.2+"}
}
prefix
:定义了在代码编辑器中触发该代码片段的前缀,这里设定为Vue3.2+
body
:定义了代码片段的主体部分,它是一个数组,包含多行模板代码
description
:对该代码片段的描述
在vue
文件中输入Vue3.2+
(会有自动提示) 按下 Tab
键,就会自动插入这段模板代码。你可以根据需要自行修改和完善这个模板。
七、最后
本人每篇文章都是一字一句码出来,希望对大家有所帮助,多提提意见。顺手来个三连击,点赞👍收藏💖关注✨,一起加油☕