vue3-components-plus

vue3-components-plus 是一个功能丰富的 Vue 3 企业级组件库,提供办公文档预览、动态表单、视频播放、权限控制等完整解决方案。
4,986
Install
npm install vue3-components-plus
Latest Version:3.0.52
Vue:3
Last Updated:Oct 2, 2026
Links: npm
Maintainer: mr.zy

vue3-components-plus 组件库

简介

vue3-components-plus 是一个功能丰富的 Vue 3 企业级组件库,提供办公文档预览、动态表单、视频播放、权限控制等完整解决方案。

GitHub 源代码: https://github.com/75535596/vue3-components-plus

组件使用示例参考 dist/ComponentDemo

📸 部分组件预览

NsDialog

emh1eWluZw==

NsForm

emh1eWluZw==

NsTableContainer

emh1eWluZw==

NsOffice

emh1eWluZw==

emh1eWluZw==

emh1eWluZw==

NsMD

emh1eWluZw==

自定义指令集

emh1eWluZw==

浸润线

emh1eWluZw==

📊 功能特性总结

组件功能

  • ✅ NsOffice: 办公文档统一预览(Excel/PDF/Word)
  • ✅ NsForm: 动态表单生成和管理
  • ✅ NsDialog: 灵活弹窗对话框
  • ✅ NsPdf: PDF文档预览和搜索
  • ✅ NsExcel: Excel预览和编辑
  • ✅ NsWord: Word文档预览
  • ✅ NsImage: 图片预览
  • ✅ NsMD: Markdown编辑器
  • ✅ NsSaturationline: 浸润线
  • ✅ NsAutoScreen: 自适应屏幕工具

指令功能

  • ✅ v-permission: 按钮权限控制
  • ✅ v-length: 输入长度和格式限制
  • ✅ v-sline: 单行文本省略
  • ✅ v-event-unuse/use: 事件穿透控制

工具函数

  • ✅ HTTP请求: 完整的RESTful API封装
  • ✅ 资源加载: 动态JS/CSS资源管理
  • ✅ 表格排序: 表格排序功能
  • ✅ SM2加密: 国密算法加密
  • ✅ CSS变量: 主题样式管理
  • ✅ 通用工具: 常用工具函数

创建公共组件库步骤

  • npm create vue@latest
  • 主目录:创建packages(任意文件夹), 创建全局导出文件index.ts
// 主index.ts
import NsXX from './packages/NsXX/index.ts'
const components = { NsXX, 其他公共组件 }
const NsComponents = {
  install: (app: App)=> {
    Object.Keys(components).forEach((compName)=>{
      app.component(compName, components[compName])
    })
  }
}
// 按需导出
export {
  NsXX,
  其他公共组件
}
// 全局导入
export default NsComponents
  • 子目录:NsXX目录,创建独立导出index.ts
// 子index.ts:
import NsXX from './comps/index.ts'
// 按需导出
NsXX.install = (app)=>{
  app.component(NsXX.name, NsXX)
}
// 导出子组件
export default NsXX
  • 配置package.json
{
  "name": "vue3-components-plus",
  "version": "2.0.100",
  "private": false,
  "type": "module",
  "files": [
    "dist"
  ],
  "main": "./dist/vue3-components-plus.umd.cjs",
  "module": "./dist/vue3-components-plus.js",
  "exports": {
    "./dist/vue3-components-plus.css": "./dist/vue3-components-plus.css",
    "./css": "./dist/vue3-components-plus.css",
    ".": {
      "import": "./dist/vue3-components-plus.js",
      "require": "./dist/vue3-components-plus.umd.cjs"
    }
  },
  "publishConfig": {
    "registry": "http://199.10.9.178:8081/repository/npm-hosted/"
  }
}
  • 配置vite.config.ts
build: {
  outDir: "dist",
  lib: {
    // 指定入口主文件
    entry: fileURLToPath(new URL("./pacakges/index.ts"), import.meta.url),
    // 组件库导出后可以使用的全局变量
    name: 'MatrixComponents',
    // 不指定为package.json的name属性
    fileName: 'vue3-components-plus',
  },
  rollupOptions: {
    // 使用外部依赖(打包时删除的包,避免打入到组件库中)
    external: ["vue"],
    output: {
      // 主index.ts导出多个module时需要指定"named"否则报警告,默认为"default"
      exports: 'named',
      // 配合external: ["vue"], 使用外部项目的变量映射
      globals: {
         vue: 'Vue',
      },
    }
  },
  // 【可选】压缩方式,viet3+需安装pnpm i terser -D
  minify: 'terser',
  terserOptions: {
    compress: {
      drop_console: true,
      drop_debugger: true,
    },
    format: {
      comments: false,
    },
  },
}
  • 打包
npm run build
  • 当前项目main.ts使用
import NsComponents from '../dist/vue3-components-plus.js'
// 按需引入
// import {NsXX} from '../dist/vue3-components-plus,js'
...
app.use(NsComponents)
// 按需引入
// app.use(NsXX)
  • 当前项目Test.vue使用
<template>
  <NsXX />
</template>

使用公共组件库

# 1. 引入组件库
pnpm i vue3-components-plus element-plus

// 2. main.ts中引入
// 安装 Element-Plus
import 'element-plus/dist/index.css'
import ElementPlus from 'element-plus'
import zhCn from 'element-plus/es/locale/lang/zh-cn'
app.use(ElementPlus, {
  locale: zhCn,
})
// 安装组件库(ts需要//@ts-ignore)
//@ts-ignore
import NsComponents from 'vue3-components-plus'
import 'vue3-components-plus/dist/vue3-components-plus.css'
app.use(NsComponents)

📋 组件列表

NsOffice - 办公文档统一预览组件

支持格式:Excel(.xlsx/.xls)、PDF(.pdf)、Word(.docx/.doc)

<template>
  <!-- 基础使用 -->
  <NsOffice :url="fileUrl" />
  
  <!-- Excel编辑模式 -->
  <NsOffice :url="excelUrl" :isEdit="true" />
  
  <!-- 获取组件引用 -->
  <NsOffice ref="officeRef" :url="fileUrl" />
</template>

<script setup>
import { ref } from 'vue'
import { NsOffice } from 'vue3-components-plus'

const officeRef = ref()

// 获取文件类型
const fileType = officeRef.value?.getFileType() // 'excel' | 'pdf' | 'word' | 'unsupported'

// 获取当前激活的组件实例
const activeComponent = officeRef.value?.getActiveComponent()

// 刷新组件
officeRef.value?.refresh()
</script>

NsForm - 动态表单组件

<template>
  <NsForm :rows="formConfig" ref="formRef" />
</template>

<script setup>
import { ref } from 'vue'
import { NsForm } from 'vue3-components-plus'

const formRef = ref()
const formConfig = [
  {
    key: 'name',
    label: '姓名',
    component: 'el-input',
    props: { placeholder: '请输入姓名' }
  },
  {
    key: 'age',
    label: '年龄',
    component: 'el-input-number',
    props: { min: 0, max: 100 }
  }
]

// 获取表单数据
const formData = formRef.value?.getFormData()

// 重置表单
formRef.value?.resetForm()

// 验证表单
const isValid = formRef.value?.validate()
</script>

NsDialog - 弹出框组件

import { NsDialog, closeAllNsDialog } from 'vue3-components-plus'

// 打开对话框
NsDialog({
  title: '测试',
  // 任何组件添加 $emit('close') 时,会触发关闭弹出框事件
  dom: VideoDemo, // 也可以通过异步方式:import("@/views/VideoDemo.vue") 和 () => import("@/views/VideoDemo.vue")
  option: {
    // dom对应的自定义组件props属性
    ...data,
  },
  events: {
    // dom组件内部自定义事件emit('btnClick', xxx)
    btnClick: () => {
      console.log("点击中间区域内容");
    },
  },
  modalColor: 'rgb(0 21 115 / 20%)', // 遮罩层颜色
  width: '800px', // 宽度, 整个弹出框的高度,非内容高度
  height: '450px', // 高度, 不配置则默认为内容高度
  dialogPadding: [10, 20], // 弹窗内padding
  showFooter: true, // 默认显示底部按钮
  immediately: false, // true立即取消弹出框, false异步请求后取消弹出框,默认false
  draggable: true, // 是否可拖拽,默认false

  // 最小化配置(最小化后仅保留头部栏,恢复时还原尺寸、位置与内部状态)
  minimizable: true, // 是否显示最小化按钮,默认false;设为true显示
  minimizeWidth: '300px', // 最小化宽度,默认'300px';原始实际渲染宽度更小时保持原始宽度,不会被撑大
  minimizePosition: 'keep', // 最小化定位:'keep'保持最小化前位置(默认);{ x, y }为绝对定位坐标,支持数字(px)或字符串('24px'、'calc(...)'、'10%'),可只传x或只传y
  minimizeAnimation: true, // 最小化/恢复动画,默认开启
  minimizeAnimationDuration: '0.5s', // 最小化/恢复动画时长,默认'0.5s'

  confirm: async (closeFn, componentRef, footerLoading) => { // 底部确认按钮回调事件
    // componentRef可以调用内部函数,前提需要defineExpose
    try{
      const selectRows = componentRef?.value?.getSelectedRows();
      console.log("点击确认,选择数据:", selectRows);
    } catch(e) {
      console.log(e)
      await new Promise(resolve => setTimeout(resolve, 1000))
    }
    // footerLoading可以控制底部loading状态
    if(footerLoading) {
      footerLoading.value = false
    }
    // 请求数据,再关闭
    if(closeFn) {
      closeFn()
    }
  },
  close: () => { // 关闭弹出时立即出发
    console.log("点击关闭");
  },
  closed: () => { // 弹窗销毁时触发
    console.log("完成关闭");
  },
  // 头部+底部自定义配置
  headerDom: xxx,
  headerOption: {},
  headerEvents: {},
  footerDom: yyy,
  footerOption: {},
  footerEvents: {},
  // 底部按钮名称
  footerTitle: {
    close: "取消",
    confirm: "确定",
  },
}, true, '#app') // true为是否遮罩(非必填), '#app'为挂载点(非必填)

// 关闭所有对话框
closeAllNsDialog()

NsDialog 最小化行为说明:

  • 最小化后仅保留头部栏(高度收缩为标题栏高度),内容区与底部栏保留在 DOM 中仅做隐藏,内部组件状态(如表单输入)不丢失
  • 最小化宽度取「最小化时的实际渲染宽度」与 minimizeWidth 的较小值,窄弹窗不会被撑大;配置宽度无法解析时回退为 300px
  • minimizePosition: 'keep' 时最小化栏停在最小化前的位置;拖动最小化栏后位置会被记忆,恢复再最小化回到上次拖动后的位置
  • minimizePosition: { x, y } 时最小化栏使用绝对定位(position: fixed),不随恢复窗口的拖动而变化;拖动最小化栏会更新该记忆位置
  • 拖拽结束时位置会落位到 left/top,最小化、恢复、最大化、再拖动之间不会出现位置跳变或脱离鼠标
  • 最小化按钮默认隐藏,需要显式设置 minimizable: true 才会显示;设置为 false 时保持隐藏
  • 最小化与最大化互斥:最大化状态下点击最小化会先还原为普通窗口再最小化,两按钮图标始终不同;恢复时回到普通窗口
  • 禁用动画时(minimizeAnimation: false)直接切换到目标状态,无过渡

NsPdf - PDF预览组件

<template>
  <NsPdf ref="pdfRef" :url="pdfUrl"></NsPdf>
</template>

<script setup>
import { ref } from 'vue'
import { NsPdf } from 'vue3-components-plus'

const pdfRef = ref()

// 搜索关键词
function searchKeyword() {
  pdfRef.value?.search('关键词')
}
</script>

NsExcel - Excel预览/编辑组件

<template>
  <NsExcel :url="excelUrl" :isEdit="true" />
</template>

NsWord - Word预览组件

<template>
  <NsWord :url="wordUrl" />
</template>

NsImage - 图片预览组件

<template>
  <NsImage :src="imageUrl" :defaultImg="defaultImage" />
</template>

NsMD - Markdown编辑器组件

<template>
  <NsMD v-model="markdownContent" />
</template>

NsSaturationline - 饱和度线组件

<template>
  <NsSaturationline :data="saturationData" />
</template>

NsAutoScreen - 自适应屏幕工具

import { autoScaleInit, sacle_x, sacle_y } from 'vue3-components-plus'

// 初始化自适应
autoScaleInit(document.querySelector('body'), {
  designWidth: 1920,
  designHeight: 920,
  mode: 'stretch', // 可选 horizontal/vertical/stretch
});

// 获取缩放比例
const scaleX = sacle_x()
const scaleY = sacle_y()

🔧 自定义指令

1. v-permission - 按钮权限控制

<template>
  <!-- 使用class控制权限,无权限时隐藏 -->
  <el-button v-permission.class.display>查看</el-button>
  
  <!-- 使用id控制权限,无权限时隐藏 -->
  <el-button v-permission.id>编辑</el-button>
  
  <!-- 默认使用id控制权限 -->
  <el-button id="zuhu_list_add" v-permission>新增</el-button>
</template>

<script setup>
// 权限配置(需要在引入组件库之前设置)
import { createApp } from 'vue'

const app = createApp(App)

// 方式1:使用 provide/inject
const btnsPermission = ['zuhu_list_add', 'zuhu_list_edit', 'admin-btn']
app.provide('btnsPermission', btnsPermission)

// 方式2:使用全局属性
app.config.globalProperties.$btnsPermission = ['zuhu_list_add', 'zuhu_list_edit']

// 方式3:使用 sessionStorage(适用于动态权限)(推荐)
sessionStorage.setItem('btnsPermission', JSON.stringify(['zuhu_list_add', 'zuhu_list_edit']))

// 方式4:使用 localStorage(持久化权限)
localStorage.setItem('btnsPermission', JSON.stringify(['zuhu_list_add', 'zuhu_list_edit']))

app.use(NsComponents) // 引入组件库
</script>
权限控制优先级说明

权限控制按以下优先级进行判断(从高到低):

  1. sessionStorage → sessionStorage.getItem('btnsPermission')
  2. localStorage → localStorage.getItem('btnsPermission')
  3. 全局属性 → app.config.globalProperties.$btnsPermission
  4. provide/inject → app.provide('btnsPermission', btnsPermission)
指令修饰符说明
  • v-permission - 默认模式,使用 id 选择器,无权限时设置 visibility: hidden
  • v-permission.id - 显式指定使用 id 选择器
  • v-permission.class - 使用 class 选择器
  • v-permission.id.display - 使用 id 选择器,无权限时设置 display: none
  • v-permission.class.display - 使用 class 选择器,无权限时设置 display: none
动态权限切换示例
// 动态切换权限
function togglePermission() {
  // 获取当前权限列表
  let btnsPermission = JSON.parse(sessionStorage.getItem('btnsPermission')) || []
  
  // 添加新权限
  if (!btnsPermission.includes('delete_btn')) {
    btnsPermission.push('delete_btn')
  } else {
    // 移除权限
    btnsPermission = btnsPermission.filter(item => item !== 'delete_btn')
  }
  
  // 更新权限存储
  sessionStorage.setItem('btnsPermission', JSON.stringify(btnsPermission))
  
  // 刷新页面或重新渲染组件
  location.reload() // 或使用响应式更新
}
实际应用场景
<template>
  <!-- 按钮组权限控制 -->
  <div class="toolbar">
    <el-button id="add_btn" v-permission type="primary">添加</el-button>
    <el-button id="edit_btn" v-permission type="success">编辑</el-button>
    <el-button id="delete_btn" v-permission type="danger">删除</el-button>
    <el-button id="export_btn" v-permission.id.display type="warning">导出</el-button>
    <el-button class="admin-btn" v-permission.class type="info">管理员</el-button>
  </div>
  
  <!-- 菜单权限控制 -->
  <el-menu>
    <el-menu-item index="1" id="dashboard_menu" v-permission>
      <span>仪表盘</span>
    </el-menu-item>
    <el-menu-item index="2" class="user-menu" v-permission.class>
      <span>用户管理</span>
    </el-menu-item>
  </el-menu>
</template>

<script setup>
// 权限配置示例
const app = createApp(App)

// 实际项目中,权限数据通常从后端获取
const userPermissions = {
  // 普通用户权限
  normal: ['add_btn', 'edit_btn', 'dashboard_menu'],
  // 管理员权限
  admin: ['add_btn', 'edit_btn', 'delete_btn', 'export_btn', 'admin-btn', 'user-menu']
}

// 根据用户角色设置权限
const userRole = 'admin' // 从登录信息获取
app.provide('btnsPermission', userPermissions[userRole])

app.use(NsComponents)
</script>

2. v-length - 输入长度限制

<template>
  <!-- 限制最大长度50(默认) -->
  <el-input v-length placeholder="请输入用户名" />
  
  <!-- 自定义长度限制 -->
  <el-input v-length="100" placeholder="最多100字符" />
  
  <!-- 仅允许输入数字 -->
  <el-input v-length.number="11" placeholder="请输入手机号" />
  
  <!-- 自定义正则表达式 -->
  <el-input v-length.regex="{ maxLength: 10, pattern: /^[a-zA-Z]*$/ }" placeholder="仅允许字母" />
  
  <!-- 数字范围限制 -->
  <el-input v-length.range="{ min: 0, max: 100, int: true, maxLength: 10 }" placeholder="0-100整数" />
</template>

3. v-sline - 单行文本省略

<template>
  <span v-sline>这是一段很长的文本内容,超出部分会自动显示省略号...</span>
</template>

4. v-event-unuse / v-event-use - 事件穿透控制

<template>
  <!-- 阻止事件穿透 -->
  <div v-event-use>
    <button>这个按钮可以点击</button>
  </div>
  
  <!-- 允许事件穿透 -->
  <div v-event-unuse>
    <div>这个区域的事件会穿透到下层</div>
  </div>
</template>

🔧 工具函数

1. 通用工具函数

import { isNotNull } from 'vue3-components-plus'

// 检查值是否非空
const result = isNotNull(value) // 返回布尔值

2. 动态资源加载

import { loadAccess, removeDynamicAccess } from 'vue3-components-plus'

// 加载JS/CSS资源
await loadAccess('https://example.com/script.js', 'script-tag', false)

// 移除动态加载的资源
removeDynamicAccess('script-tag')

3. CSS变量管理

import { loadCssVars } from 'vue3-components-plus'

// 获取所有CSS变量
const cssVars = loadCssVars()
console.log(cssVars['--matrix-primary-color'])

4. 表格排序工具

import { handleSortChange, headerClick, handleHeaderCellClass } from 'vue3-components-plus'

// 在表格组件中使用
<el-table
  @sort-change="(sort) => handleSortChange(sort, searchForm, getList)"
  @header-click="headerClick"
  :header-cell-class-name="(params) => handleHeaderCellClass(params, searchForm)"
>
  <!-- 表格内容 -->
</el-table>

5. SM2加密工具

import { getEncryptSm2 } from 'vue3-components-plus'

// 使用SM2加密
const encrypted = getEncryptSm2(publicKey, ["xxx", "yyy"], isAdd04=false, cipherMode=1)

6. 动态表单工具函数

import { 
  useFileUpload, 
  getAllFormNodeByKey, 
  getAllFormKvData, 
  getAllFormNodeRefByKey 
} from 'vue3-components-plus'

// 表单文件上传hook
const { uploadFile, deleteFile } = useFileUpload()

// 根据key获取表单节点信息
const formNode = getAllFormNodeByKey(formRows, 'username')

// 获取表单所有键值对数据
const formData = getAllFormKvData(formRows)

// 根据key获取表单节点引用
const nodeRef = getAllFormNodeRefByKey(formRows, 'username')

7. 屏幕自适应函数

import { sacle_x, sacle_y, autoScaleInit } from 'vue3-components-plus'

// 初始化自适应
autoScaleInit(document.querySelector('body'), {
  designWidth: 1920,
  designHeight: 920,
  mode: 'stretch' // 可选 horizontal/vertical/stretch
})

// 获取当前缩放比例
const scaleX = sacle_x()
const scaleY = sacle_y()

🌐 HTTP请求函数

1. 基础HTTP请求方法

import { get, post, put, del, download, downLoadLocalFile, getTokenInfo } from 'vue3-components-plus'

// GET请求
const result = await get('/api/users', { page: 1, size: 10 })

// POST请求
const result = await post('/api/users', { name: '张三', age: 25 })

// PUT请求
const result = await put('/api/users/1', { name: '李四', age: 30 })

// DELETE请求
const result = await del('/api/users/1')

// 文件下载
await download('/api/export', 'report.xlsx', 'get', { type: 'excel' })

// 下载本地文件
downLoadLocalFile('/public/', 'template.xlsx', 'template.xlsx')

// 获取token信息
const tokenInfo = getTokenInfo()

2. 初始化配置

// main.ts中配置
import { createApp } from 'vue'
import NsComponents from 'vue3-components-plus'

const app = createApp(App)

// 请求地址的baseUrl,建议在app.use(NsComponents)之前设置
app.config.globalProperties.$BaseUrl = 'http://api.example.com/'

// 图片、文件请求地址的ImageBaseUrl,建议在app.use(NsComponents)之前设置
app.config.globalProperties.$ImageBaseUrl = 'http://api.example.com/'

// 【可选】401无权显示回调
app.config.globalProperties.$LogoutCallback = logoutHandler

// 【可选】请求添加的token头的key,默认为satoken
sessionStorage.setItem('tokenName', 'Authorization')
sessionStorage.setItem('tokenValue', 'Bearer your-token-here')

app.use(NsComponents)

3. 实际使用示例

// api/user.js
import { get, post } from 'vue3-components-plus'

export const getUserList = (params) => get('/api/users', params)

export const createUser = (data) => post('/api/users', data)

export const updateUser = (id, data) => put(`/api/users/${id}`, data)

export const deleteUser = (id) => del(`/api/users/${id}`)

export const exportUsers = () => download('/api/users/export', 'users.xlsx')

🚀 完整安装和使用

1. 安装依赖

# 安装Element Plus
pnpm i element-plus

# 安装组件库
pnpm i vue3-components-plus -S --registry=http://199.10.9.178:8081/repository/npm-group/

# 如果安装失败,使用备用地址
pnpm i vue3-components-plus --registry=http://199.10.9.178:8081/repository/npm-hosted/

2. 全局引入

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

// 安装 Element-Plus
import 'element-plus/dist/index.css'
import ElementPlus from 'element-plus'
import zhCn from 'element-plus/es/locale/lang/zh-cn'

// 安装组件库
// @ts-ignore
import NsComponents from 'vue3-components-plus'
import 'vue3-components-plus/dist/vue3-components-plus.css'

const app = createApp(App)

// 配置请求地址
app.config.globalProperties.$BaseUrl = 'http://your-api-server/'
app.config.globalProperties.$ImageBaseUrl = 'http://your-api-server/'

app.use(ElementPlus, {
  locale: zhCn,
})
app.use(NsComponents)

app.mount('#app')

3. 按需引入

// 按需引入组件和函数
import { NsForm, get, post, autoScaleInit } from 'vue3-components-plus'

// 在组件中使用
const app = createApp(App)
app.use(NsForm)

autoScaleInit(document.querySelector('body'), {
  designWidth: 1920,
  designHeight: 920,
  mode: 'stretch'
})

更新日志

version: 3.0.21
日期: 2026-03-17
更新内容:
1. NsTableContainer刷新后数据偶尔不更新的bug
version: 3.0.20
日期: 2026-03-17
更新内容:
1. NsTableContainer增加插槽#page-content,替换表格区域
2. NsTableContainer按钮禁用颜色修改
version: 3.0.16
日期: 2026-03-16
更新内容:
1. 修改NsTableContainer支持自定义分页字段:page-number-key/page-size-key/page-total-key
version: 3.0.15
日期: 2026-03-16
更新内容:
1. NsTableContainer支持多级表头,通过 children 属性配置嵌套列
version: 3.0.14
日期: 2026-03-16
更新内容:
1. 修复使用 v-length.range="{ min: 0, max: 10, maxLength: 10 }"指令时int:false,可输入负数的问题
version: 3.0.13
日期: 2026-03-13
更新内容:
1. 添加NsTableContainer带搜索条件的表格
version: 3.0.11
日期: 2026-03-09
更新内容:
1. 修复bug
version: 3.0.10
日期: 2026-01-23
更新内容:
1. 修改NsSaturationLine文字字体

Version History

Version Released Vue License
3.0.52 ^3.5.13
3.0.51 ^3.5.13
3.0.50 ^3.5.13
3.0.43 ^3.5.13
3.0.41 ^3.5.13