【PPTist】画布状态管理

一、简介

在 PPTist 项目中,画布是指幻灯片编辑区域的主要工作区,具体包括:

  • 基础尺寸
  • 主要功能:显示和编辑幻灯片、元素拖拽和缩放等、网格线和标尺对齐、元素的选择和多选
  • 相关状态:缩放比例、画布能否被拖拽、网格线尺寸等
  • 主要操作:缩放、平移、显示网格线标尺等
  • 组成部分:背景层、内容层、工具层
  • 画布的特点:
    响应式:自适应窗口大小、保持宽高比例、支持缩放适配
    交互性:支持拖拽移动、支持元素选择、支持快捷键操作
    辅助功能:网格对齐、标尺显示、智能参考线

二、基础属性

画布的定义在src/store/main.ts文件,看一下接口定义,包含各个部分的编辑状态、选中状态等等

ts 复制代码
// 主状态接口定义
export interface MainState {
  activeElementIdList: string[]      // 被选中的元素ID集合
  handleElementId: string            // 正在操作的元素ID(如调整大小、旋转等)
  activeGroupElementId: string       // 组合元素中被选中的子元素ID
  hiddenElementIdList: string[]      // 被隐藏的元素ID集合

  canvasPercentage: number          // 画布可视区域百分比
  canvasScale: number               // 画布缩放比例(基于宽度1000px)
  canvasDragged: boolean            // 画布是否被拖拽移动

  thumbnailsFocus: boolean          // 左侧导航缩略图区域是否聚焦
  editorAreaFocus: boolean          // 编辑区域是否聚焦
  disableHotkeys: boolean           // 是否禁用快捷键

  gridLineSize: number              // 网格线尺寸(0表示不显示网格线)
  showRuler: boolean                // 是否显示标尺

  creatingElement: CreatingElement | null   // 正在创建的元素信息
  creatingCustomShape: boolean              // 是否正在绘制自定义形状

  availableFonts: typeof SYS_FONTS         // 当前环境可用的字体列表
  toolbarState: ToolbarStates              // 右侧工具栏状态

  clipingImageElementId: string            // 当前正在裁剪的图片ID
  isScaling: boolean                       // 是否正在进行元素缩放

  richTextAttrs: TextAttrs                 // 富文本编辑器属性
  selectedTableCells: string[]             // 选中的表格单元格

  selectedSlidesIndex: number[]            // 当前选中的页面索引集合
  dialogForExport: DialogForExportTypes    // 导出对话框类型

  databaseId: string                       // 当前应用的indexedDB数据库ID 随机数

  textFormatPainter: TextFormatPainter | null    // 文字格式刷
  shapeFormatPainter: ShapeFormatPainter | null  // 形状格式刷

  showSelectPanel: boolean                 // 是否显示选择面板
  showSearchPanel: boolean                 // 是否显示查找替换面板
  showNotesPanel: boolean                  // 是否显示批注面板
}

三、计算属性

typescript 复制代码
// 计算属性
getters: {
  // 获取当前选中的元素列表
  activeElementList(state) {
    const slidesStore = useSlidesStore()
    const currentSlide = slidesStore.currentSlide
    if (!currentSlide || !currentSlide.elements) return []
    return currentSlide.elements.filter(element => state.activeElementIdList.includes(element.id))
  },

  // 获取当前操作的元素
  handleElement(state) {
    const slidesStore = useSlidesStore()
    const currentSlide = slidesStore.currentSlide
    if (!currentSlide || !currentSlide.elements) return null
    return currentSlide.elements.find(element => state.handleElementId === element.id) || null
  },
},

四、方法

action 的定义还挺多的,但是里面的实现都比较简单,都是设置状态的值。大家肯定看一眼就明白啦

五、使用

画布状态都在哪里使用,这是一个关键的问题,以后我们在开发新功能的时候,需要知道什么时候要调用这里面的方法。

我们以 setCanvasPercentage 方法为例,这个方法是用来改变画布的缩放的百分比的,在 src/hooks/useScaleCanvas.ts 中使用

typescript 复制代码
/**
 * 缩放画布百分比
 * @param command 缩放命令:放大、缩小
 */
const scaleCanvas = (command: '+' | '-') => {
  let percentage = canvasPercentage.value
  const step = 5
  const max = 200
  const min = 30
  if (command === '+' && percentage <= max) percentage += step
  if (command === '-' && percentage >= min) percentage -= step

  mainStore.setCanvasPercentage(percentage)
}

/**
 * 设置画布缩放比例
 * 但不是直接设置该值,而是通过设置画布可视区域百分比来动态计算
 * @param value 目标画布缩放比例
 */
const setCanvasScalePercentage = (value: number) => {
  const percentage = Math.round(value / canvasScale.value * canvasPercentage.value) / 100
  mainStore.setCanvasPercentage(percentage)
}

/**
 * 重置画布尺寸和位置
 */
const resetCanvas = () => {
  mainStore.setCanvasPercentage(90)
  if (canvasDragged) mainStore.setCanvasDragged(false)
}

设置完了之后呢,canvasPercentage这个属性在哪里使用呢?

是在 src/views/Editor/Canvas/hooks/useViewportSize.ts 这个文件中

typescript 复制代码
  // 可视区域缩放或比例变化时,重置/更新可视区域的位置
  watch(canvasPercentage, setViewportPosition)

监听到这个属性变化之后,会计算出画布的位置,然后执行

typescript 复制代码
  // 画布可视区域位置和大小的样式
const viewportStyles = computed(() => ({
  width: VIEWPORT_SIZE,
  height: VIEWPORT_SIZE * viewportRatio.value,
  left: viewportLeft.value,
  top: viewportTop.value,
}))

viewportStyles 这个属性又在 src/views/Editor/Canvas/index.vue 文件中使用

html 复制代码
<div 
  class="viewport-wrapper"
  :style="{
    width: viewportStyles.width * canvasScale + 'px',
    height: viewportStyles.height * canvasScale + 'px',
    left: viewportStyles.left + 'px',
    top: viewportStyles.top + 'px',
  }"
>

viewport-wrapper 这个元素我们看一下是谁,就是这个编辑区域

可以看出,项目的源码分工还是很细的

如果我们要在编辑区域增加一个新的属性,就需要把属性定义到src/store/main.ts 文件中,然后通过 src/hooks/useXXX.ts 文件进行修改,并且导出模版中需要使用的属性,然后在模版中使用。

相关推荐
G_G#8 小时前
纯前端js插件实现同一浏览器控制只允许打开一个标签,处理session变更问题
前端·javascript·浏览器标签页通信·只允许一个标签页
@大迁世界8 小时前
TypeScript 的本质并非类型,而是信任
开发语言·前端·javascript·typescript·ecmascript
GIS之路8 小时前
GDAL 实现矢量裁剪
前端·python·信息可视化
是一个Bug8 小时前
后端开发者视角的前端开发面试题清单(50道)
前端
Amumu121388 小时前
React面向组件编程
开发语言·前端·javascript
持续升级打怪中9 小时前
Vue3 中虚拟滚动与分页加载的实现原理与实践
前端·性能优化
GIS之路9 小时前
GDAL 实现矢量合并
前端
hxjhnct9 小时前
React useContext的缺陷
前端·react.js·前端框架
前端 贾公子9 小时前
从入门到实践:前端 Monorepo 工程化实战(4)
前端
菩提小狗9 小时前
Sqlmap双击运行脚本,双击直接打开。
前端·笔记·安全·web安全