【PPTist】网格线、对齐线、标尺

前言:本篇文章介绍辅助我们摆放元素位置的几个功能

一、网格线功能

网格线主要是用来辅助我们对齐元素的,右键可以选择使用哪种网格线,以及关闭和打开

显示效果就是图中的这种效果。但是强迫症有点难受,它底部没对齐啊啊啊

不行,我要把它改成对齐的!

猜测目前的网格线设置的是固定值。

然后咱们先全局搜索一下"网格线",发现了这里的定义
src/store/main.ts

ts 复制代码
gridLineSize: number  // 网格线尺寸(0表示不显示网格线)

网格线这个组件是 src/views/Editor/Canvas/GridLines.vue ,其中就两个方法,一个计算网格线颜色的,避免网格线颜色和底色太接近看不清;另一个是计算网格路径的。网格线使用过 path 标签渲染出来的,我们来看一下网格路径的计算方法

ts 复制代码
const { canvasScale, gridLineSize } = storeToRefs(useMainStore())
// 网格路径
const path = computed(() => {
  const maxX = VIEWPORT_SIZE
  const maxY = VIEWPORT_SIZE * viewportRatio.value

  let p = ''
  for (let i = 0; i <= Math.floor(maxY / gridLineSize.value); i++) {
    p += `M0 ${i * gridLineSize.value} L${maxX} ${i * gridLineSize.value} `
  }
  for (let i = 0; i <= Math.floor(maxX / gridLineSize.value); i++) {
    p += `M${i * gridLineSize.value} 0 L${i * gridLineSize.value} ${maxY} `
  }
  return p
})

以及页面中的这个网格线组件:

可以看到里面的线条数据,只有一个不是整数,所以 562.5 应该就是最后一行的纵坐标,不过最后一行应该也是50的倍数,所以应该是下边框上还有一条线

话说好像不能让底部对齐,因为网格得是正方形,好吧,那我还是忍忍吧。

然后还有一个相关的组件 src/views/Editor/Canvas/index.vue ,里面有右键菜单。可以看到,设置网格线尺寸的方法是 mainStore.setGridLineSize(50)

这个方法在 src/store/main.ts

ts 复制代码
setGridLineSize(size: number) {
  this.gridLineSize = size
},

二、对齐线

对齐线就是这个

对齐线的定义在这里 src/views/Editor/Canvas/AlignmentLine.vue

控制对齐线的显示的属性有四个:
type: 'vertical' | 'horizontal' 控制方向
lefttop 控制位置
sizeStyle ,如果是竖向就有 height 值,如果是横向就有 width 值表示长度。

然后我们来看一下这个组件的父组件在哪里,以及是怎么从父组件获取 props

是在 src/views/Editor/Canvas/index.vue 文件中

其中的 .viewport-wrapper 是覆盖整个编辑区域的框框

其中的对齐线是通过 v-for 渲染的数组

html 复制代码
<AlignmentLine 
  v-for="(line, index) in alignmentLines" 
  :key="index" 
  :type="line.type" 
  :axis="line.axis" 
  :length="line.length"
  :canvasScale="canvasScale"
/>

数据 alignmentLines 的修改依赖于两个方法

typescript 复制代码
const { dragElement } = useDragElement(elementList, alignmentLines, canvasScale)
const { scaleElement, scaleMultiElement } = useScaleElement(elementList, alignmentLines, canvasScale)

看方法名就是拖拽和缩放元素的时候会更新

这个写法比较少见,没有通过一个方法返回 alignmentLines 更新后的值,而是在方法里面直接修改了 alignmentLines

然后我们会发现代码的组织性真的很好,这些钩子函数在另外的文件中维护,并且方法名很明确。

总而言之言而总之,这个方法好复杂,各种计算的。

简单看一下数据。

还有多条的情况

三、标尺

标尺就是这个

主要跟缩放行为有关,中间顶部 500 的位置和左侧 300 的位置是固定的。

还有如果选中一个元素的话,标尺的对应坐标会高亮

它的父组件跟上面的对齐线的父组件是同一个
src/views/Editor/Canvas/index.vue

html 复制代码
<Ruler :viewportStyles="viewportStyles" :elementList="elementList" v-if="showRuler" />

showRuler 通过右键菜单控制标尺的开关。

typescript 复制代码
const { dragViewport, viewportStyles } = useViewportSize(canvasRef)
const elementList = ref<PPTElement[]>([])
const setLocalElementList = () => {
  elementList.value = currentSlide.value ? JSON.parse(JSON.stringify(currentSlide.value.elements)) : []
}
watchEffect(setLocalElementList)
// 开关标尺
const toggleRuler = () => {
  mainStore.setRulerState(!showRuler.value)
}

标尺组件在这里 src/views/Editor/Canvas/Ruler.vue

根元素下有两个元素,一个是 .h,表示顶部的标尺; 一个是 .v,表示左侧的标尺

先看下动态添加的类名是啥意思:class="{ 'hide': markerSize < 36, 'omit': markerSize < 72 }"

typescript 复制代码
const markerSize = computed(() => {
  return props.viewportStyles.width * canvasScale.value / 10
})

就是缩放值小于72的时候,中间的这个小齿齿会隐藏

缩放值小于 36 的时候,数字会隐藏

其中的高亮是这个元素

html 复制代码
<div class="range" 
  v-if="elementListRange"
  :style="{
    left: elementListRange.minX * canvasScale + 'px',
    width: (elementListRange.maxX - elementListRange.minX) * canvasScale + 'px',
  }"
></div>
typescript 复制代码
const { canvasScale, activeElementIdList } = storeToRefs(useMainStore())
watchEffect(() => {
  const els = props.elementList.filter(el => activeElementIdList.value.includes(el.id))
  if (!els.length) return elementListRange.value = null
  elementListRange.value = getElementListRange(els)
})

activeElementIdList 是公用的数据,通过 src/store/main.ts 中的下面的方法修改

typescript 复制代码
// 设置选中元素列表
setActiveElementIdList(activeElementIdList: string[]) {
  if (activeElementIdList.length === 1) this.handleElementId = activeElementIdList[0]
  else this.handleElementId = ''
  this.activeElementIdList = activeElementIdList
},

然后各种地方都可能会用到,包括组合元素、鼠标选中、切换页面(清空)等等。

计算元素的范围 getElementListRange 也是一个公用的方法,在这个文件中 src/utils/element.ts,大致就是找选中的元素的所有的位置,取最边缘的位置,作为包含所有的选中元素的范围。

相关推荐
华玥作者10 小时前
[特殊字符] VitePress 对接 Algolia AI 问答(DocSearch + AI Search)完整实战(下)
前端·人工智能·ai
Mr Xu_11 小时前
告别冗长 switch-case:Vue 项目中基于映射表的优雅路由数据匹配方案
前端·javascript·vue.js
前端摸鱼匠11 小时前
Vue 3 的toRefs保持响应性:讲解toRefs在解构响应式对象时的作用
前端·javascript·vue.js·前端框架·ecmascript
lang2015092811 小时前
JSR-340 :高性能Web开发新标准
java·前端·servlet
好家伙VCC12 小时前
### WebRTC技术:实时通信的革新与实现####webRTC(Web Real-TimeComm
java·前端·python·webrtc
未来之窗软件服务12 小时前
未来之窗昭和仙君(六十五)Vue与跨地区多部门开发—东方仙盟练气
前端·javascript·vue.js·仙盟创梦ide·东方仙盟·昭和仙君
嘿起屁儿整13 小时前
面试点(网络层面)
前端·网络
VT.馒头13 小时前
【力扣】2721. 并行执行异步函数
前端·javascript·算法·leetcode·typescript
phltxy14 小时前
Vue 核心特性实战指南:指令、样式绑定、计算属性与侦听器
前端·javascript·vue.js
Byron070715 小时前
Vue 中使用 Tiptap 富文本编辑器的完整指南
前端·javascript·vue.js