news 2026/5/14 3:14:42

别再手撸流程图了!用Vue-super-flow + Element UI 10分钟搞定审批流原型

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
别再手撸流程图了!用Vue-super-flow + Element UI 10分钟搞定审批流原型

用Vue-super-flow + Element UI快速构建企业级审批流原型

在企业内部管理系统中,审批流程是最常见的功能需求之一。传统的手工绘制流程图方式不仅效率低下,而且难以与业务系统无缝集成。现在,借助Vue-super-flow这一强大的Vue流程图组件,配合Element UI的表单控件,我们可以快速搭建出既美观又实用的审批流程原型。

1. 为什么选择Vue-super-flow构建审批流

审批流程是企业运营中不可或缺的环节,从请假申请到采购审批,几乎每个业务场景都需要流程化的管理。传统方式下,产品经理和前端开发者需要花费大量时间在Visio或Axure中绘制静态流程图,然后再由开发人员手动实现交互逻辑,这种工作模式存在几个明显痛点:

  • 效率低下:从设计到实现需要多次转换工具
  • 维护困难:业务变更时需同步修改设计和代码
  • 交互体验差:静态流程图无法真实反映系统行为

Vue-super-flow作为专为Vue生态设计的流程图组件,完美解决了这些问题。它提供了:

  1. 可视化拖拽:通过简单拖放即可创建流程节点
  2. 高度可定制:支持自定义节点样式和连线风格
  3. 数据驱动:流程状态完全由数据控制
  4. 无缝集成:与Element UI完美配合,构建完整表单
// 典型审批流节点配置示例 const approvalNodes = [ { id: "submit", type: "start", meta: { name: "提交申请", approver: "" } }, { id: "first_approve", type: "process", meta: { name: "部门审批", approver: "department_manager" } } // 更多节点... ]

2. 10分钟快速搭建审批流原型

2.1 环境准备与基础配置

首先确保项目中已安装Vue-super-flow及其依赖:

npm install vue-super-flow element-ui

然后在main.js中进行全局注册:

import Vue from 'vue' import ElementUI from 'element-ui' import SuperFlow from 'vue-super-flow' import 'vue-super-flow/lib/index.css' import 'element-ui/lib/theme-chalk/index.css' Vue.use(ElementUI) Vue.use(SuperFlow)

2.2 构建审批流画布

创建一个基本的审批流编辑器组件:

<template> <div class="approval-flow-editor"> <div class="node-palette"> <div v-for="item in nodeTypes" :key="item.type" class="node-item" draggable @dragstart="dragStart(item)" > {{ item.label }} </div> </div> <div class="flow-container" @drop="dropNode" @dragover.prevent> <super-flow ref="flow" :node-list="nodes" :link-list="links" @connection-created="onConnection" > <template v-slot:node="{ meta }"> <div :class="`flow-node ${meta.type}`"> <div class="node-header"> <span>{{ meta.name }}</span> <i class="el-icon-close" @click="removeNode(meta.id)"></i> </div> <div class="node-body"> <el-select v-if="meta.type === 'process'" v-model="meta.approver" placeholder="选择审批人"> <el-option v-for="user in approvers" :key="user.id" :label="user.name" :value="user.id"> </el-option> </el-select> </div> </div> </template> </super-flow> </div> </div> </template>

2.3 审批节点类型设计

典型的审批流程包含几种核心节点类型:

节点类型图标功能描述特有属性
start流程起点申请人信息
process审批环节审批人、审批规则
condition条件分支条件表达式
end流程终点处理结果
// 节点数据示例 data() { return { nodeTypes: [ { type: 'start', label: '开始节点' }, { type: 'process', label: '审批环节' }, { type: 'condition', label: '条件分支' }, { type: 'end', label: '结束节点' } ], approvers: [ { id: 'manager', name: '部门经理' }, { id: 'director', name: '总监' }, { id: 'finance', name: '财务审核' } ] } }

3. 实现审批流的业务逻辑

3.1 节点拖拽与连接

Vue-super-flow提供了完整的拖拽API和连接线事件:

methods: { dragStart(item) { event.dataTransfer.setData('nodeType', item.type) }, dropNode(event) { const type = event.dataTransfer.getData('nodeType') const coordinate = this.$refs.flow.getMouseCoordinate( event.clientX, event.clientY ) const newNode = { id: `node_${Date.now()}`, type, coordinate, meta: { name: `${type}节点`, approver: '' } } this.nodes.push(newNode) }, onConnection(connection) { this.links.push({ source: connection.sourceId, target: connection.targetId, meta: { label: '' } }) } }

3.2 审批规则配置

每个审批节点都可以配置详细的审批规则:

<el-dialog title="审批节点配置" :visible.sync="showConfig"> <el-form label-width="100px"> <el-form-item label="审批人类型"> <el-radio-group v-model="currentNode.meta.approverType"> <el-radio label="specific">指定人员</el-radio> <el-radio label="role">角色</el-radio> <el-radio label="variable">变量</el-radio> </el-radio-group> </el-form-item> <el-form-item v-if="currentNode.meta.approverType === 'specific'" label="选择审批人"> <el-select v-model="currentNode.meta.approver"> <el-option v-for="user in users" :key="user.id" :label="user.name" :value="user.id"> </el-option> </el-select> </el-form-item> <el-form-item label="审批方式"> <el-checkbox v-model="currentNode.meta.allowDelegate">允许转审</el-checkbox> <el-checkbox v-model="currentNode.meta.allowComment">必须填写意见</el-checkbox> </el-form-item> </el-form> </el-dialog>

3.3 条件节点逻辑处理

对于条件分支节点,需要配置判断条件:

// 条件节点配置示例 { id: "condition_1", type: "condition", meta: { name: "金额判断", conditions: [ { expression: "amount <= 5000", target: "approve_1" }, { expression: "amount > 5000", target: "approve_2" } ] } }

4. 高级功能与性能优化

4.1 审批流模板管理

将常用审批流程保存为模板:

methods: { saveAsTemplate() { const template = { name: this.templateName, nodes: this.nodes, links: this.links, createdAt: new Date() } // 保存到本地存储或后端 const templates = JSON.parse(localStorage.getItem('flowTemplates') || '[]') templates.push(template) localStorage.setItem('flowTemplates', JSON.stringify(templates)) this.$message.success('模板保存成功') }, loadTemplate(id) { const templates = JSON.parse(localStorage.getItem('flowTemplates') || '[]') const template = templates.find(t => t.id === id) if (template) { this.nodes = template.nodes this.links = template.links } } }

4.2 大型流程的性能优化

当审批流程非常复杂时,可以采取以下优化措施:

  1. 虚拟滚动:只渲染可视区域内的节点
  2. 分组折叠:将相关节点分组并可折叠
  3. 懒加载:动态加载流程的不同部分
  4. 简化渲染:在拖拽过程中使用简化版的节点渲染
// 虚拟滚动配置示例 <super-flow ref="flow" :node-list="visibleNodes" :viewport="viewport" @viewport-change="updateViewport" > <!-- 节点插槽 --> </super-flow> // 计算可见节点 computed: { visibleNodes() { return this.nodes.filter(node => node.coordinate[0] >= this.viewport.x && node.coordinate[0] <= this.viewport.x + this.viewport.width && node.coordinate[1] >= this.viewport.y && node.coordinate[1] <= this.viewport.y + this.viewport.height ) } }

4.3 与后端API集成

审批流程通常需要与后端服务深度集成:

// 保存流程到后端 async saveFlow() { try { const flowData = { name: this.flowName, nodes: this.nodes, links: this.links, version: '1.0' } const response = await axios.post('/api/workflow', flowData) this.$message.success('流程保存成功') return response.data.id } catch (error) { this.$message.error('保存失败: ' + error.message) console.error('保存错误:', error) } } // 从后端加载流程 async loadFlow(id) { try { const response = await axios.get(`/api/workflow/${id}`) this.nodes = response.data.nodes this.links = response.data.links this.flowName = response.data.name } catch (error) { this.$message.error('加载失败: ' + error.message) } }

5. 实际案例:请假审批流程实现

让我们通过一个完整的请假审批流程示例,展示Vue-super-flow的实际应用。

5.1 流程节点设计

典型的请假审批流程包含以下节点:

  1. 申请提交:员工填写请假信息
  2. 部门审批:直属领导审批
  3. HR备案:人力资源部记录
  4. 特殊审批:超过3天需要额外审批
  5. 结果通知:通知申请人结果
const leaveFlow = { nodes: [ { id: 'start', type: 'start', coordinate: [100, 50], meta: { name: '请假申请', form: 'leave_apply' } }, { id: 'dept_approve', type: 'process', coordinate: [100, 200], meta: { name: '部门审批', approver: 'direct_leader', form: 'approval_form' } }, { id: 'hr_record', type: 'process', coordinate: [100, 350], meta: { name: 'HR备案', approver: 'hr_staff', autoApprove: true } }, { id: 'condition', type: 'condition', coordinate: [300, 200], meta: { name: '天数判断', expression: 'days > 3' } }, { id: 'extra_approve', type: 'process', coordinate: [500, 200], meta: { name: '高管审批', approver: 'senior_manager', visible: false } }, { id: 'end', type: 'end', coordinate: [100, 500], meta: { name: '流程结束' } } ], links: [ { source: 'start', target: 'dept_approve' }, { source: 'dept_approve', target: 'condition' }, { source: 'condition', target: 'extra_approve', meta: { label: '是', expression: 'days > 3' } }, { source: 'condition', target: 'hr_record', meta: { label: '否', expression: 'days <= 3' } }, { source: 'extra_approve', target: 'hr_record' }, { source: 'hr_record', target: 'end' } ] }

5.2 动态表单集成

每个节点可以关联不同的表单:

<template> <div class="node-form"> <component v-if="currentForm" :is="currentForm.component" v-model="formData" :fields="currentForm.fields" /> </div> </template> <script> import LeaveApplyForm from './forms/LeaveApplyForm.vue' import ApprovalForm from './forms/ApprovalForm.vue' export default { components: { LeaveApplyForm, ApprovalForm }, data() { return { forms: { leave_apply: { component: 'LeaveApplyForm', fields: [ { name: 'type', label: '请假类型', type: 'select', options: [...] }, { name: 'days', label: '请假天数', type: 'number' }, { name: 'reason', label: '请假原因', type: 'textarea' } ] }, approval_form: { component: 'ApprovalForm', fields: [ { name: 'result', label: '审批结果', type: 'radio', options: [...] }, { name: 'comment', label: '审批意见', type: 'textarea' } ] } }, formData: {} } }, computed: { currentForm() { const node = this.selectedNode return node ? this.forms[node.meta.form] : null } } } </script>

5.3 流程状态跟踪

实时显示审批流程的当前状态:

<template> <div class="flow-status"> <div v-for="node in nodes" :key="node.id" :class="['status-node', getStatusClass(node)]" > <div class="node-icon"></div> <div class="node-info"> <h4>{{ node.meta.name }}</h4> <p v-if="node.meta.approver"> 审批人: {{ getApproverName(node.meta.approver) }} </p> <p v-if="getNodeStatus(node) === 'completed'"> 完成时间: {{ getCompletionTime(node) }} </p> </div> </div> </div> </template> <script> export default { methods: { getStatusClass(node) { const status = this.getNodeStatus(node) return `status-${status}` }, getNodeStatus(node) { // 根据实际业务逻辑返回节点状态 // pending, processing, completed, rejected return this.flowStatus[node.id] || 'pending' }, getApproverName(approverId) { return this.approvers.find(a => a.id === approverId)?.name || approverId } } } </script> <style> .status-node { border-left: 4px solid #ddd; padding: 10px; margin: 5px 0; transition: all 0.3s; } .status-pending { opacity: 0.6; } .status-processing { border-left-color: #409EFF; background: rgba(64, 158, 255, 0.1); } .status-completed { border-left-color: #67C23A; } .status-rejected { border-left-color: #F56C6C; } </style>

6. 最佳实践与常见问题

6.1 审批流设计原则

在设计企业审批流程时,应遵循以下原则:

  1. 简洁性:避免过度复杂的审批层级
  2. 灵活性:支持条件分支和动态审批人
  3. 可追溯性:完整记录审批过程和意见
  4. 用户体验:清晰的流程状态展示

6.2 常见问题解决方案

问题1:节点过多导致界面混乱

解决方案

  • 使用子流程概念,将相关节点分组
  • 实现缩放和平移功能
  • 添加搜索和筛选功能
// 子流程实现示例 { id: 'finance_approval', type: 'subflow', meta: { name: '财务审批流程', expanded: false, nodes: [...], links: [...] } }

问题2:审批人动态变化

解决方案

  • 支持变量表达式指定审批人
  • 提供审批人候选列表
  • 允许审批人转审
// 动态审批人配置 { meta: { approver: "${applicant.department.manager}", fallbackApprovers: ["hr_manager", "ceo"] } }

问题3:流程版本控制

解决方案

  • 每次修改保存为新版本
  • 维护版本变更历史
  • 提供流程比较功能
// 版本控制数据结构 { id: "flow_123", name: "采购审批流程", currentVersion: "v2.1", versions: [ { version: "v2.1", createdAt: "2023-05-20", author: "user123", changes: "增加财务审批节点" }, { version: "v2.0", createdAt: "2023-03-15", author: "user456", changes: "优化条件分支逻辑" } ] }

6.3 调试技巧

开发过程中可以使用以下方法调试审批流:

  1. 导出流程图数据
this.$refs.flow.toJSON()
  1. 验证流程完整性
function validateFlow(nodes, links) { // 检查是否有孤立节点 // 检查是否有无效连接 // 检查必填属性是否完整 }
  1. 使用模拟数据测试
const mockData = { applicant: { id: 'user001', department: { manager: 'manager123' } }, formData: { days: 5, reason: '家庭事务' } } function runFlowTest(flow, data) { // 模拟流程执行过程 // 验证每个节点的处理结果 }

7. 扩展思路:将审批流引擎化

对于更复杂的企业需求,可以考虑将审批流抽象为引擎:

7.1 流程定义语言

设计一种DSL来描述审批流程:

flow: name: 请假审批 version: 1.0 start: submit nodes: submit: type: start form: leave_apply next: dept_approve dept_approve: type: process approver: ${applicant.manager} actions: approve: next: check_days reject: next: end check_days: type: condition rules: - when: ${form.days > 3} next: extra_approve - default: next: hr_record

7.2 流程执行引擎

实现一个可以解析和执行流程定义的引擎:

class WorkflowEngine { constructor(flowDefinition) { this.flow = flowDefinition this.currentState = { node: this.flow.start, data: {}, history: [] } } async execute(action, payload) { const currentNode = this.flow.nodes[this.currentState.node] const transition = currentNode.actions[action] if (!transition) { throw new Error(`Invalid action ${action} for node ${this.currentState.node}`) } // 执行节点逻辑 const result = await this.executeNode(currentNode, payload) // 记录历史 this.currentState.history.push({ node: this.currentState.node, action, timestamp: new Date(), data: result }) // 转移到下一个节点 this.currentState.node = transition.next return this.currentState } async executeNode(node, payload) { switch(node.type) { case 'process': return this.executeProcessNode(node, payload) case 'condition': return this.executeConditionNode(node, payload) // 其他节点类型... } } }

7.3 可视化流程监控

为管理员提供流程执行的可视化监控:

<template> <div class="flow-monitor"> <super-flow :node-list="enhancedNodes" :link-list="links" :readonly="true" > <template v-slot:node="{ meta }"> <div :class="['monitor-node', meta.status]"> <div class="node-title">{{ meta.name }}</div> <div class="node-status">{{ meta.status }}</div> <div v-if="meta.status === 'completed'" class="node-time"> {{ meta.completedAt }} </div> </div> </template> </super-flow> </div> </template> <script> export default { props: ['instance'], computed: { enhancedNodes() { return this.instance.nodes.map(node => { const status = this.getInstanceStatus(node.id) return { ...node, meta: { ...node.meta, status, completedAt: this.getCompletionTime(node.id) } } }) } } } </script>

8. 从原型到生产环境

将审批流原型转化为生产环境可用的系统需要考虑以下方面:

8.1 性能与稳定性优化

  1. 前端优化

    • 虚拟滚动大型流程
    • 使用Web Worker处理复杂计算
    • 实现增量保存机制
  2. 后端集成

    • 设计高效的流程存储结构
    • 实现流程版本控制
    • 提供流程实例监控接口

8.2 权限与安全控制

审批流程通常涉及敏感数据,需要严格的安全控制:

// 权限检查中间件 function checkFlowPermission(flowId, userId) { return db.flows.findOne({ _id: flowId, $or: [ { owner: userId }, { collaborators: userId }, { isPublic: true } ] }) } // 审计日志记录 function logFlowAction(action, userId, details) { db.auditLogs.insert({ action, userId, details, timestamp: new Date(), ip: getClientIp() }) }

8.3 移动端适配

现代办公越来越依赖移动设备,审批流需要良好的移动端体验:

  1. 响应式布局
.flow-container { width: 100%; height: 100vh; } @media (max-width: 768px) { .node-palette { position: fixed; bottom: 0; left: 0; right: 0; height: 60px; overflow-x: auto; } .flow-container { height: calc(100vh - 60px); } }
  1. 手势操作支持
// 触摸事件处理 function setupTouchEvents() { const flowEl = document.querySelector('.flow-container') flowEl.addEventListener('touchstart', handleTouchStart) flowEl.addEventListener('touchmove', handleTouchMove) flowEl.addEventListener('touchend', handleTouchEnd) // 实现拖拽、缩放等手势逻辑 }
  1. 离线功能
// 使用Service Worker缓存流程模板 self.addEventListener('install', event => { event.waitUntil( caches.open('flow-templates').then(cache => { return cache.addAll([ '/api/templates/basic', '/api/templates/leave', '/api/templates/expense' ]) }) ) })

9. 测试策略与质量保障

确保审批流程系统的可靠性需要全面的测试方案:

9.1 单元测试重点

  1. 流程验证逻辑
describe('流程验证', () => { it('应检测孤立节点', () => { const flow = { nodes: [{id: 'node1'}, {id: 'node2'}], links: [] } expect(validateFlow(flow)).toHaveProperty('errors') }) it('应通过有效流程', () => { const flow = { nodes: [{id: 'start'}, {id: 'approve'}], links: [{source: 'start', target: 'approve'}] } expect(validateFlow(flow).errors).toHaveLength(0) }) })
  1. 条件节点逻辑
describe('条件节点', () => { const conditionNode = { type: 'condition', meta: { rules: [ {when: 'amount > 10000', next: 'manager_approve'}, {default: 'normal_approve'} ] } } it('应匹配金额条件', () => { const context = {amount: 15000} expect(evaluateCondition(conditionNode, context)) .toBe('manager_approve') }) it('应回退到默认分支', () => { const context = {amount: 5000} expect(evaluateCondition(conditionNode, context)) .toBe('normal_approve') }) })

9.2 端到端测试场景

使用Cypress或Playwright测试完整用户旅程:

describe('请假审批流程', () => { it('应完成简单审批流程', () => { cy.visit('/flow/leave') cy.dragNode('start', 100, 50) cy.dragNode('process', 100, 200) cy.connectNodes('start', 'process') cy.getNode('process').dblclick() cy.selectApprover('department_manager') cy.saveFlow('test_leave_flow') cy.submitTestInstance() cy.approveAs('department_manager') cy.assertFlowCompleted() }) })

9.3 性能测试指标

建立关键性能基准:

场景节点数量可接受响应时间
小型流程<10节点<500ms
中型流程10-50节点<1s
大型流程50+节点<2s
// 性能测试示例 describe('大型流程性能', () => { before(() => { cy.generateLargeFlow(100) // 生成100个节点的测试流程 }) it('应在2秒内渲染完成', () => { cy.visit('/flow/large') cy.get('.loading-indicator').should('not.exist') cy.get('.flow-container').should('be.visible') cy.window().then(win => { expect(win.performance.timing.loadEventEnd - win.performance.timing.navigationStart) .to.be.lessThan(2000) }) }) })

10. 持续演进与扩展

随着业务发展,审批流系统需要不断进化:

10.1 插件机制设计

允许通过插件扩展功能:

// 插件接口设计 class FlowPlugin { constructor(flowEditor) { this.editor = flowEditor } install() { // 注册自定义节点类型 // 添加工具栏按钮 // 扩展右键菜单 } } // 示例插件:会签功能 class ParallelApprovalPlugin extends FlowPlugin { install() { this.editor.registerNodeType('parallel', { template: ParallelApprovalNode, validator: (node) => { return node.meta.approvers?.length > 0 } }) this.editor.addToolbarButton({ icon: 'users', action: () => this.addParallelNode() }) } addParallelNode() { this.editor.addNode({ type: 'parallel', meta: { name: '会签审批', approvers: [], required: 1 // 需要几人同意 } }) } }

10.2 与现有系统集成

常见集成点及实现方式:

  1. 组织架构同步
async syncDepartments() { const depts = await HRSystem.getDepartments() this.departments = depts.map(dept => ({ id: dept.code, name: dept.name, manager: dept.managerId })) }
  1. 单点登录集成
// 认证中间件 function ssoMiddleware(req, res, next) { const token = req.headers['authorization'] if (!token) return res.status(401).send() SSO.validate(token).then(user => { req.user = user next() }).catch(() => res.status(403).send()) }
  1. 消息通知对接
class NotificationService { constructor() { this.providers = { email: new EmailProvider(), sms: new SmsProvider(), app: new MobileAppPush() } } send(recipient, message, channels = ['app']) { return Promise.all( channels.map(channel => this.providers[channel].send(recipient, message) ) ) } }

10.3 智能化方向探索

引入AI技术提升审批流智能化水平:

  1. 智能路由建议
function suggestApprovers(context) { return AI.predict('approver_suggestion', { applicant: context.applicant, request_type: context.type, historical_patterns: context.history }) }
  1. 自动审批规则
function evaluateAutoApproval(request) { return AI.predict('approval_likelihood', { request, applicant_history: request.applicant.approvalHistory, company_policy: currentPolicy }).then(score => score > 0.9) }
  1. 异常检测
function detectAnomalies(request) { return AI.detect('approval_anomalies', { current_request: request, historical_requests: similarRequests, applicant_behavior: request.applicant.requestPatterns }) }

11. 团队协作与版本管理

多人协作设计审批流程需要专门的版本管理方案:

11.1 基于Git的流程版本控制

将流程定义存储在Git仓库中:

/workflows /leave v1.yaml v2.yaml /expense v1.yaml v2.yaml
# 典型工作流程 git checkout -b feature/new-approval-flow # 编辑流程文件 git add . git commit -m "Add finance approval step" git push origin feature/new-approval-flow # 创建Pull Request进行代码审查

11.2 变更影响分析

在修改流程时分析潜在影响:

function analyzeImpact(flow, change) { // 识别受影响的节点 const affectedNodes = findDependentNodes(flow, change) // 检查正在运行的实例 const runningInstances = db.instances.find({ flowId: flow.id, status: 'running', currentNode: { $in: affectedNodes } }) return { affectedNodes, runningInstances: runningInstances.count(), completedInstances: db.instances.find({ flowId: flow.id, status: 'completed', path: { $elemMatch: { nodeId: { $in: affectedNodes } } } }).count() } }

11.3 审批流设计规范

建立团队设计规范确保一致性:

  1. 命名约定

    • 节点ID:类型_描述,如approve_dept
    • 变量名:camelCase
    • 条件表达式:field operator value,如amount > 10000
  2. 文档标准

    • 每个流程顶部添加注释说明用途
    • 复杂节点添加业务逻辑说明
    • 维护变更日志
# 采购审批流程 # 用途:所有采购申请的审批流程 # 创建人:张三 # 最后更新:2023-06-15 flow: version: 2.1 changelog: - version: 2.1 date: 2023-06-15 changes: 增加财务复核节点 - version: 2.0 date: 2023-03-10 changes: 拆分大额采购分支 start: submit nodes: submit: type: start description: 申请人填写采购申请单

12. 用户体验优化技巧

提升审批流系统的用户体验可以显著提高采用率:

12.1 直观的视觉反馈

  1. 节点状态可视化
/* 不同状态的节点样式 */ .node-status-pending { border: 1px dashed #ccc; background-color: #f9f9f9; } .node-status-processing { border: 2px solid #409EFF; animation: pulse 1.5s infinite; } @keyframes pulse { 0% { box-shadow: 0 0 0 0 rgba(64, 158, 255, 0.4); } 70% { box-shadow: 0 0 0 10px rgba(64, 158, 255, 0); } 100% { box-shadow: 0 0 0 0 rgba(64, 158, 255, 0); } }
  1. 连接线动画
// 动态连线效果 function animateConnection(link) { const path = link.getPathElement() const length = path.getTotalLength() path.style.strokeDasharray = length path.style.strokeDashoffset = length const animation = path.animate( [{ strokeDashoffset: length }, { strokeDashoffset: 0 }], { duration: 1000, fill: 'forwards' } ) return animation.finished }

12.2 快捷操作设计

提高频繁操作的效率:

  1. 键盘快捷键
// 快捷键设置 document.addEventListener('keydown', (e) => { if (e.ctrlKey && e.key === 's') { e.preventDefault() this.saveFlow() } if (e.key === 'Delete') { this.deleteSelected() } })
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/14 3:14:08

从一道408考研真题出发,拆解Cache映射的三种套路与避坑指南

从一道408考研真题出发&#xff0c;拆解Cache映射的三种套路与避坑指南 Cache映射是计算机组成原理中的核心考点&#xff0c;也是408考研真题中的高频难点。许多考生在面对Cache计算题时&#xff0c;往往陷入公式套用的误区&#xff0c;忽略了题目中隐藏的关键细节。本文将从一…

作者头像 李华
网站建设 2026/5/14 3:00:06

免费开源!3分钟掌握B站视频数据批量采集终极方案

免费开源&#xff01;3分钟掌握B站视频数据批量采集终极方案 【免费下载链接】Bilivideoinfo Bilibili视频数据爬虫 精确爬取完整的b站视频数据&#xff0c;包括标题、up主、up主id、精确播放数、历史累计弹幕数、点赞数、投硬币枚数、收藏人数、转发人数、发布时间、视频时长、…

作者头像 李华
网站建设 2026/5/14 2:58:04

苹果自研芯片M系列:从ARM架构到软硬件协同的垂直整合革命

1. 从传闻到现实&#xff1a;苹果芯片自研之路的必然性2012年11月&#xff0c;一则来自彭博社的报道在科技圈投下了一颗不大不小的石子&#xff1a;苹果正在探索用自家iPhone和iPad上的A系列芯片&#xff0c;取代Mac电脑中的英特尔处理器。当时&#xff0c;许多业内人士将其视为…

作者头像 李华
网站建设 2026/5/14 2:51:27

手把手教你配置i.MX RT1052的BOOT引脚:从HyperFlash到QSPI的启动选择实战

手把手教你配置i.MX RT1052的BOOT引脚&#xff1a;从HyperFlash到QSPI的启动选择实战 在嵌入式系统开发中&#xff0c;启动配置是硬件工程师和开发者面临的第一个关键挑战。i.MX RT1052作为一款高性能跨界处理器&#xff0c;其灵活的启动选项既带来了强大的适应性&#xff0c;也…

作者头像 李华