ToB企服应用市场:ToB评测及商务社交产业平台
标题:
【PPTist】幻灯片放映
[打印本页]
作者:
钜形不锈钢水箱
时间:
2025-1-17 18:46
标题:
【PPTist】幻灯片放映
放映功能的代码都在
src/hooks/useScreening.ts
,我们看一下
从当前页开始
放映的功能。
// 进入放映状态(从当前页开始)
const enterScreening = () => {
enterFullscreen()
screenStore.setScreening(true)
}
复制代码
起首是 enterFullscreen(),进入全屏放映
src/utils/fullscreen.ts
// 进入全屏
export const enterFullscreen = () => {
const docElm = document.documentElement
if (docElm.requestFullscreen) docElm.requestFullscreen()
else if (docElm.mozRequestFullScreen) docElm.mozRequestFullScreen()
else if (docElm.webkitRequestFullScreen) docElm.webkitRequestFullScreen()
else if (docElm.msRequestFullscreen) docElm.msRequestFullscreen()
}
复制代码
进入全屏指的是整个编辑器 document.documentElement 进入全屏
就先找一下当前的浏览器能用的全屏的方法,然后调用。
然后执行 screenStore.setScreening(true)
src/store/screen.ts
setScreening(screening: boolean) {
this.screening = screening
},
复制代码
然后通过这个属性控制的App..vue中的组件的显示
src/App.vue
<template>
<Screen v-if="screening" />
<Editor v-else-if="_isPC" />
<Mobile v-else />
</template>
复制代码
进入放映模式
src/views/Screen/index.vue
<template>
<div class="pptist-screen">
<BaseView :changeViewMode="changeViewMode" v-if="viewMode === 'base'" />
<PresenterView :changeViewMode="changeViewMode" v-else-if="viewMode === 'presenter'" />
</div>
</template>
复制代码
通过幻灯片放映的下拉框进入的是
普通视图
,就是 BaseView。然后右键有一个
演讲者视图
,就是 PresenterView
1、普通视图
src/views/Screen/BaseView.vue
右键点击
工具栏
的时候右下角会浮现工具栏
这内里的内容其实跟右键菜单项差不多
① 画笔工具
右键点击
画笔工具
时会出现画笔工具
src/views/Screen/WritingBoardTool.vue
利用画笔工具的时候,
sizePopoverType
这个属性用来表现当前利用的是哪个工具。
绘制过程的组件
src/components/WritingBoard.vue
,
绘制过程分为三个阶段,鼠标落下、鼠标移动、鼠标抬起
mousedown
// 处理鼠标(触摸)事件
// 准备开始绘制/擦除墨迹(落笔)
const handleMousedown = (e: MouseEvent | TouchEvent) => {
// 获取鼠标在canvas中的相对位置
const [mouseX, mouseY] = getMouseOffsetPosition(e)
// 计算鼠标在canvas中的绝对位置
const x = mouseX / widthScale.value
const y = mouseY / heightScale.value
// 设置鼠标状态
isMouseDown = true
lastPos = { x, y }
lastTime = new Date().getTime()
// 设置鼠标状态
if (!(e instanceof MouseEvent)) {
mouse.value = { x: mouseX, y: mouseY }
mouseInCanvas.value = true
}
}
复制代码
mousemove
// 开始绘制/擦除墨迹(移动)
const handleMousemove = (e: MouseEvent | TouchEvent) => {
// 获取鼠标在canvas中的相对位置
const [mouseX, mouseY] = getMouseOffsetPosition(e)
// 计算鼠标在canvas中的绝对位置
const x = mouseX / widthScale.value
const y = mouseY / heightScale.value
// 设置鼠标位置
mouse.value = { x: mouseX, y: mouseY }
// 开始绘制/擦除墨迹
if (isMouseDown) handleMove(x, y)
}
复制代码
// 路径操作
const handleMove = (x: number, y: number) => {
const time = new Date().getTime()
if (props.model === 'pen') {
const s = getDistance(x, y)
const t = time - lastTime
const lineWidth = getLineWidth(s, t)
draw(x, y, lineWidth)
lastLineWidth = lineWidth
}
else if (props.model === 'mark') draw(x, y, props.markSize)
else erase(x, y)
lastPos = { x, y }
lastTime = new Date().getTime()
}
复制代码
此中画画、橡皮擦是通过 canvas 实现的
// 绘制画笔墨迹方法
const draw = (posX: number, posY: number, lineWidth: number) => {
if (!ctx) return
const lastPosX = lastPos.x
const lastPosY = lastPos.y
ctx.lineWidth = lineWidth
ctx.strokeStyle = props.color
ctx.beginPath()
ctx.moveTo(lastPosX, lastPosY)
ctx.lineTo(posX, posY)
ctx.stroke()
ctx.closePath()
}
复制代码
mouseup
// 结束绘制/擦除墨迹(停笔)
const handleMouseup = () => {
if (!isMouseDown) return
isMouseDown = false
emit('end')
}
复制代码
竣事绘制会被父组件监听
src/views/Screen/WritingBoardTool.vue
// 每次绘制完成后将绘制完的图片更新到数据库
const hanldeWritingEnd = () => {
const dataURL = writingBoardRef.value!.getImageDataURL()
if (!dataURL) return
db.writingBoardImgs.where('id').equals(currentSlide.value.id).toArray().then(ret => {
const currentImg = ret[0]
if (currentImg) db.writingBoardImgs.update(currentImg, { dataURL })
else db.writingBoardImgs.add({ id: currentSlide.value.id, dataURL })
})
}
复制代码
将绘制的内容存储到数据库中,切换幻灯片的时候,会查察当前幻灯片有没有对应的绘制字迹
// 打开画笔工具或切换页面时,将数据库中存储的墨迹绘制到画布上
watch(currentSlide, () => {
db.writingBoardImgs.where('id').equals(currentSlide.value.id).toArray().then(ret => {
const currentImg = ret[0]
writingBoardRef.value!.setImageDataURL(currentImg?.dataURL || '')
})
}, { immediate: true })
复制代码
② 自动放映
自动放映的方法在这里:
src/views/Screen/hooks/useExecPlay.ts
// 自动播放
const autoPlayInterval = ref(2500)
const autoPlay = () => {
closeAutoPlay()
message.success('开始自动放映')
autoPlayTimer.value = setInterval(execNext, autoPlayInterval.value)
}
复制代码
execNext()
方法咱们以前见过,就是下一张的方法。可以看到自动放映就是每隔固定时间执行下一张的方法
③ 循环放映
// 循环放映
const loopPlay = ref(false)
const setLoopPlay = (loop: boolean) => {
loopPlay.value = loop
}
复制代码
循环播放通过 loopPlay 控制。
在执行 execNext() 方法的时候,如果执行到末了一张幻灯片,就会需要判定是否是循环放映模式,如果是,就将幻灯片从头开始,
const execNext = () => {
if (formatedAnimations.value.length && animationIndex.value < formatedAnimations.value.length) {
runAnimation()
}
else if (slideIndex.value < slides.value.length - 1) {
slidesStore.updateSlideIndex(slideIndex.value + 1)
animationIndex.value = 0
inAnimation.value = false
}
else {
// 如果循环播放,则切换到第一页
if (loopPlay.value) turnSlideToIndex(0)
else {
throttleMassage('已经是最后一页了')
closeAutoPlay()
}
inAnimation.value = false
}
}
复制代码
④ 查察所有幻灯片
点击“查察所有幻灯片”时,会显示
src/views/Screen/SlideThumbnails.vue
组件,页面就变成如许了
不过这页面可以看出来挺简朴的,点击某一张幻灯片的时候,会进入目标幻灯片的放映模式
const turnSlide = (index: number) => {
props.turnSlideToIndex(index)
emit('close')
}
复制代码
src/views/Screen/hooks/useExecPlay.ts
// 切换幻灯片到指定的页面
const turnSlideToIndex = (index: number) => {
slidesStore.updateSlideIndex(index)
animationIndex.value = 0
}
复制代码
触发 close 方法,就是潜伏这个
SlideThumbnails
组件
@close="slideThumbnailModelVisible = false"
复制代码
2、演讲者视图
① 画笔
画笔跟上面的画笔工具是一个组件,由此可知组件化的告急性,功能复用多么方便!
② 激光笔
设置成激光笔模式的时候,内容地域会增长一个类名
<div
class="slide-list-wrap"
:class="{ 'laser-pen': laserPen }"
ref="slideListWrapRef"
>
复制代码
是用来设置 cursor 属性的,显示成一个小圆点,是通过base64设置的,代码太长了我就不粘贴了
然后激光笔似乎没有别的作用了,就是让鼠标更明显一些。
③ 计时器
计时器会显示这么一个小组件
src/views/Screen/CountdownTimer.vue
表现分和秒的两个小框框是由不可编辑的 input 框组成
<input
type="text"
:value="fillDigit(minute, 2)"
:maxlength="3" :disabled="inputEditable"
@mousedown.stop
@blur="$event => changeTime($event, 'minute')"
@keydown.stop
@keydown.enter.stop="$event => changeTime($event, 'minute')"
>
复制代码
开始计时的时候,会设置计时器
const start = () => {
clearTimer()
if (isCountdown.value) {
// 倒计时
timer.value = setInterval(() => {
time.value = time.value - 1
// 倒计时结束 重置计时器
if (time.value <= 0) reset()
}, 1000)
}
else {
// 计时
timer.value = setInterval(() => {
time.value = time.value + 1
// 计时超过36000秒 暂停计时器
if (time.value > 36000) pause()
}, 1000)
}
inTiming.value = true
}
复制代码
至于分钟和秒数的盘算,都是根据 time 盘算出来的。
const time = ref(0)
const minute = computed(() => Math.floor(time.value / 60))
const second = computed(() => time.value % 60)
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/)
Powered by Discuz! X3.4