放映功能的代码都在 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,
绘制过程分为三个阶段,鼠标落下、鼠标移动、鼠标抬起
- // 处理鼠标(触摸)事件
- // 准备开始绘制/擦除墨迹(落笔)
- 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
- }
- }
复制代码
- // 开始绘制/擦除墨迹(移动)
- 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()
- }
复制代码
- // 结束绘制/擦除墨迹(停笔)
- 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企服之家,中国第一个企服评测及商务社交产业平台。 |