【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 文件进行修改,并且导出模版中需要使用的属性,然后在模版中使用。

相关推荐
树上有只程序猿32 分钟前
年底了公司要裁员,大家还好吗?
前端·后端
问道飞鱼1 小时前
【前端知识】Javascript进阶-类和继承
开发语言·前端·javascript·继承·
Grocery store owner1 小时前
el-time-picker选择时分秒并且根据总秒数禁用不可选
前端·javascript·vue.js
川石教育1 小时前
Vue前端开发-axios默认配置和响应结构
前端·javascript·vue.js
半吊子全栈工匠1 小时前
WEB语义化的新探索:浅析LLMs.txt
前端·搜索引擎
JackieDYH2 小时前
Vue3中页面滑到最下面,然后跳转新页面后新页面的位置还是在之前浏览的位置
前端·javascript·html
正小安2 小时前
vue3实现ai聊天对话框
前端·javascript·vue.js·elementui
长风清留扬2 小时前
小程序开发中的插件生态与应用-上
前端·javascript·css·微信小程序·小程序·apache
JSCON简时空2 小时前
还没下雪嘛?等不及了,自己整个 3D 雪地写写字!
前端·react.js·three.js