基于 Vue3打造前台+中台通用提效解决方案(中)

news2024/11/25 3:04:42

33、实现全屏展示功能

我们知道在原生dom上,提供了一些方法来供我们开启或关闭全屏:

  • Element.requestFullscreen()
  • Document.exitFullscreen()
  • Document.fullscreen
  • Document.fullscreenElement
一般浏览器

使用requestFullscreen()exitFullscreen()来实现

早期版本Chrome浏览器

基于WebKit内核的浏览器需要添加webkit前缀,使用webkitRequestFullScreen()webkitCancelFullScreen()来实现。

早期版本IE浏览器

基于Trident内核的浏览器需要添加ms前缀,使用msRequestFullscreen()msExitFullscreen()来实现,注意方法里的screen的s为小写形式。

早期版本火狐浏览器

基于Gecko内核的浏览器需要添加moz前缀,使用mozRequestFullScreen()mozCancelFullScreen()来实现。

早期版本Opera浏览器

Opera浏览器需要添加o前缀,使用oRequestFullScreen()oCancelFullScreen()来实现。

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>萌狼蓝天 伴姬一生</title>
</head>

<body>
    <div>
        <img src="./source/img/dog.jpg" height="300" alt="">
        <button id="full">全屏显示</button>
        <button id="cancelFull">取消全屏</button>
        <button id="isFull">是否全屏</button>
        <p id="tip" style="color:blue"></p>
    </div>
    <script>
        //全屏显示
        var div = document.querySelector('div');
        document.querySelector('#full').onclick = function () {
     
            if (div.requestFullscreen) {
     
                div.requestFullscreen(); // 正常浏览器 
            } else if (div.webkitRequestFullScreen) {
     
                div.webkitRequestFullScreen(); // webkit 
            } else if (div.mozRequestFullScreen) {
     
                div.mozRequestFullScreen(); //早期火狐浏览器
            } else if (div.oRequestFullScreen) {
     
                div.oRequestFullScreen(); //早期Opera浏览器
            } else if (div.msRequestFullscreen) {
     
                div.msRequestFullscreen(); //早期IE浏览器
            } else {
     
                alert('暂不支持在您的浏览器中全屏');
            }
        };
        //取消全屏显示
        document.querySelector('#cancelFull').onclick = function () {
     
            if (document.exitFullscreen) {
     
                document.exitFullscreen(); // 正常浏览器 
            } else if (document.webkitCancelFullScreen) {
     
                document.webkitCancelFullScreen(); // webkit 
            } else if (document.mozCancelFullScreen) {
     
                document.mozCancelFullScreen(); //早期火狐浏览器
            } else if (document.oCancelFullScreen) {
     
                document.oCancelFullScreen(); //早期Opera浏览器
            } else if (document.msCancelFullscreen) {
     
                document.msCancelFullscreen(); //早期IE浏览器
            } else {
     
                alert('暂不支持在您的浏览器中全屏');
            }
            //可以用document,也可以用上方设置的变量 div
        };
        //检测当前是否处于全屏状态
        document.querySelector('#isFull').onclick = function () {
     
            // alert(document.webkitIsFullScreen); // webkit
            // 使用上面的弹窗方式。如果是处于全屏状态,会自动退出
            document.getElementById('tip').innerHTML=document.webkitIsFullScreen;
        };
    
    </script>
</body>

</html>

但是这些方法:在一些低版本浏览器中存在兼容性的问题,需要我们手动封装;如果不想封装的话也可以使用第三方封装好的库来处理:

常见的第三方全屏库:

  • 1、vueUse
import {
    useFullscreen } from '@vueuse/core'

const imgEle = ref(null)
const {
    isFullscreen, enter, exit, toggle } = useFullscreen(imgEle)
const handleFullScreen = () => {
   
  imgEle.value.style.backgroundColor = 'transparent'
  enter()
}

34、从首页跳转到详情页解决方案

34.1、需求分析

首先我们看一下首页的图片

image-20220902162832479

分析:

  • 当点击某一个图片时、跳转到对应图片的详情页
  • 并且在跳转的过程中有从小到放大的动画的效果(类似于全屏效果的动画)
34.2、分析现阶段路由跳转动画

在vue-router页面跳转如果要实现跳转到动画,需要借助于transition组件来进行实现动画

<router-view v-slot="{ Component, route }">
  <transition name="fade">
    <component :is="Component" />
  </transition>
</router-view>

image-20220902164012102

这是在vue官网截的图,从图中我们可以得知transition组件一般适用于 组件 或 元素的显示和隐藏、并不适合我们的需求、

34.3、提出解决方案

那么根据咱们上一小节的分析,我们知道通过 vue-router 的过渡动效是无法实现咱们期望的路由切换效果的。

那么我们应该如何去做呢?

想要搞明白咱们的可行性方案,那么首先我们得先来搞清楚什么是路由的跳转?

所谓路由的跳转无非指的是两个部分:

  • 1.浏览器的url 发生了变化

  • 2.浏览器中展示的页面组件发生了变化

那么只要满足这两点,我们就认为路径进行了跳转

所以说,我们是不是可以换个思路,我们不去进行真实的路由跳转,而是先修改浏览器的URL,再切换展示的页面(以组件的形式覆盖整个浏览器可视区域)。这样对于用户而言,是不是就完成了整个的路由跳转工作。

所以说我们的具体问题就变成了:

  • 1.如何让浏览器的url发生变化,但是不跳转页面
  • 2.如何让一个新的组件以包含动画的形式进行展示
    • 那么想要完成第一个功能我们可以使用:History.pushState()方法
    • 而第二个功能我们可以使用 GSAP这个动画库来进行实现。
34.4、关于GSAP介绍

GSAP, 它是一个非常强大的js动画库, 他支持Flip、滚动动画等;在其内部给我们提供了非常多的方法供我们来使用;

本次我们使用到的api,只有setto两个:

  • set: 给元素设置初始化(动画执行之前)的属性

  • to: 给元素设置结束时(动画之后结束)的属性

    • to方法的返回值为tween对象、我们通过调用对应的api来控制元素动画的开启、暂停、翻转、重新开始…

      tween.play()
      tween.pause()
      tween.resume()
      tween.reverse()
      tween.restart()
      

测试1 - 自动执行动画

<template>
    <div  class="w-screen h-[400px] flex items-center justify-center">
      <div ref="testGsap" class="border border-zinc-300 rounded-sm p-4">test GSAP</div>
    </div>
</template>

<script setup>
import gsap from "gsap"
import { onMounted, ref } from 'vue'
const testGsap = ref(null)
onMounted(() => {
  gsap.set(testGsap.value, { transform: 'translateX(-100px)', color: 'blue' })
  gsap.to(testGsap.value, { transform: 'translateX(100px)', color: 'pink', duration: 1, delay: 0 })
})
</script>

20220902_180847

测试2 - 手动控制执行动画

<template>
    <div  class="w-screen h-[400px] flex items-center justify-center">
      <div ref="testGsap" class="border border-zinc-300 rounded-sm p-4">test GSAP</div>
    </div>
    <Button @click="handleStart">执行动画</Button>
    <Button @click="handleReverse">翻转动画</Button>
</template>

<script setup>
import gsap from "gsap"
import { onMounted, ref } from 'vue'
const testGsap = ref(null)
let tween
onMounted(() => {
  gsap.set(testGsap.value, { transform: 'translateX(-100px)', color: 'blue' })
  tween = gsap.to(testGsap.value, { transform: 'translateX(100px)', color: 'pink', duration: 1, delay: 0 })
  tween.pause();
})
const handleStart = () => {
   tween.play()
}
const handleReverse = () => {
   tween.reverse()
}
</script>

也就是当我们不主动暂停的话, gsap.to函数调用之后就会开始执行动画

34.5、实现从首页调到详情页
  • 1、创建pins/components/pins.vue组件

    image-20220903100744179

  • 2、在首页中使用Pins组件,并使用translation包裹、并设置执行动画

    <transition
        :css="false"
        @before-enter="onBeforeEnter"
        @enter="onEnter"
        @after-enter="onAfterEnter"
        @leave="onLeave"
        @after-leave="onAfterLeave"
      >
        <Pins :id="currentItem.id" v-if="pinsVisible"/>
      </transition>
    
    
  • 3、点击每一项时,计算当前项距离屏幕左边和边的距离、并利用h5的pushState改变地址栏路径

  • 4、展示Pins组件, 在展示过程中在过渡钩子函数中设置对应的动画样式

  • 5、当需要关闭Pins组件时; 我们需要监听页面的回退事件popState,当时间被调用时关闭Pins组件

先看下我们要实现的效果

20220903_102106

开始实现

list/index.js

<template>
  <div class="w-full">
    ...
  <!-- 图片详情 -->
  <transition
    :css="false"
    @before-enter="onBeforeEnter"
    @enter="onEnter"
    @after-enter="onAfterEnter"
    @leave="onLeave"
    @after-leave="onAfterLeave"
  >
    <Pins :id="currentItem.id" v-if="pinsVisible"/>
  </transition>
</template>

<script setup>
import ListItem from './item/index.vue'
import { getPexels } from '@/api/pexels'
import { isMoboleTerminal } from '@/utils/flexible'
import { ref, watch, computed } from 'vue'
import { useStore } from 'vuex'
import Pins from '@/views/pins/components/pins.vue'
import gsap from 'gsap'
import { useEventListener } from '@vueuse/core'

const store = useStore()

// 选中item
const selectItem = (item) => {
  currentItem.value = item
  // 修改页面地址
  window.history.pushState(null, '', '/pins/' + item.id)
}
// 监听页面回退
useEventListener('popstate', () => {
  delete currentItem.value.id
})
const pinsVisible = computed(() => currentItem.value.id !== void 0)
// pins动画钩子 -- 动画执行之前
const onBeforeEnter = (el) => {
  gsap.set(el, {
    scaleX: 0.2,
    scaleY: 0.2,
    transformOrigin: '0 0',
    translateX: currentItem.value.translateX,
    translateY: currentItem.value.translateY,
    opacity: 0
  })
}

// pins动画钩子 -- 动画执行过程
const onEnter = (el, done) => {
  el.__gsap__ = gsap.to(el, {
    duration: 0.4,
    scaleX: 1,
    scaleY: 1,
    transformOrigin: '0 0',
    translateX: 0,
    translateY: 0,
    opacity: 1,
    onComplete: done
  })
}

// pins动画钩子 -- 动画离开过程
const onLeave = (el, done) => {
  el.__gsap__.reverse()
  setTimeout(() => {
    done()
  }, el.__gsap__._dur * 1500)
}

const onAfterLeave = (el) => {
  currentItem.value = {}
}
</script>

item.vue

const handleSelectItem = () => {
   
  // 获取图片中间路基浏览器左边和顶部的距离
  const {
    left, top, width, height }  = imgEle.value?.getBoundingClientRect()
  const translateX = left + width / 2
  const translateY = top + height / 2
  emits('selectItem', {
   
    ...props.pexel,
    translateX,
    translateY
  })
}
34.5、解决刷新丢失的问题 - 路由props传参

所谓的刷新丢失,就是刷新之后、会直接访问我们设置的路径、而路径没有没有匹配到对应的路由组件、所以就会显示空白页面;

所以,我们的思路是:

方案1:

  • 1、在路由表中配置对应连接的路由对象
  • 2、路由对象中的组件中使用到我们上面定义的pins.vue组件
  • 3、这样刷新时就会通过路由匹配到对应的路由组件,在路由初始化时获取id参数传递给组件

方案2:路由props传参

vue-router 中 props传参给组件、

在你的组件中使用 $route 会与路由紧密耦合,这限制了组件的灵活性,因为它只能用于特定的 URL。虽然这不一定是件坏事,但我们可以通过 props 配置来解除这种行为:

我们可以将下面的代码

const User = {
   
  template: '<div>User {
   { $route.params.id }}</div>'
}
const routes = [{
    path: '/user/:id', component: User }]

替换成

const User = {
   
  // 请确保添加一个与路由参数完全相同的 prop 名
  props: ['id'],
  template: '<div>User {
   { id }}</div>'
}
const routes = [{
    path: '/user/:id', component: User, props: true }]

这允许你在任何地方使用该组件,使得该组件更容易重用和测试。

本案例中我们使用路由props传参

export default [
  {
   

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1531483.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于python的4s店客户管理系统

技术&#xff1a;pythonmysqlvue 一、背景 进入21世纪网络和计算机得到了飞速发展&#xff0c;并和生活进行了紧密的结合。目前&#xff0c;网络的运行速度以达到了千兆&#xff0c;覆盖范围更是深入到生活中的角角落落。这就促使管理系统的发展。网上办公可以实现远程处理事务…

NetSuite Saved Search-当前库存快照查询报表

最近&#xff0c;在项目上我们遇到了一个需求是&#xff0c;用户想要在一张报表上&#xff0c;看到某一个仓库中批次物料和非批次物料的库存On Hand信息。 其实&#xff0c;系统也有一张原生的库存当前快照报表&#xff0c;但是由于批次物料会涉及太多的批次信息&#xff0c;因…

力扣---打家劫舍---动态规划

思路 1&#xff1a; 我将res[i]定义为&#xff1a;一定要取第 i 个房子的前提下&#xff0c;能获取的最大金额。那么直接用cnt从头记录到尾&#xff0c;每个房子的res最大值即是答案。那么递推公式是什么&#xff1f;res[i]max(res[i-2],res[i-1],...,res[0])nums[i]。数组初始…

设计模式深度解析:适配器模式与桥接模式-灵活应对变化的两种设计策略大比拼

​&#x1f308; 个人主页&#xff1a;danci_ &#x1f525; 系列专栏&#xff1a;《设计模式》 &#x1f4aa;&#x1f3fb; 制定明确可量化的目标&#xff0c;坚持默默的做事。 适配器模式与桥接模式-灵活应对变化的两种设计策略大比拼 探索设计模式的魅力&#xff1a;深入了…

如何实现在固定位置的鼠标连点

鼠大侠的鼠标连点功能是免费的 浏览器搜索下载鼠大侠&#xff0c;指定连点间隔和启动快捷键 点击设置&#xff0c;指定点击位置

【区间、栈】算法例题

目录 六、区间 48. 汇总区间 ① 49. 合并区间 ② 50. 插入区间 ② 51. 用最少数量的箭引爆气球 ② 七、栈 52. 有效的括号 ① 53. 简化路径 ② 54. 最小栈 ② 55. 逆波兰表达式求值 ② √- 56. 基本计算器 ③ 六、区间 48. 汇总区间 ① 给定一个 无重复元素 的 …

安防监控视频汇聚方案EasyCVR平台调用设备录像不返回视频流的原因排查

国标GB28181协议EasyCVR安防平台可以提供实时远程视频监控、视频录像、录像回放与存储、告警、语音对讲、云台控制、平台级联、磁盘阵列存储、视频集中存储、云存储等丰富的视频能力&#xff0c;平台支持7*24小时实时高清视频监控&#xff0c;能同时播放多路监控视频流&#xf…

使用Pygame做一个乒乓球游戏

项目介绍 使用Pygame做一个乒乓球游戏。左侧为电脑&#xff0c;右侧为玩家。 视频地址-YT 视频搬运-B站 视频教程约90分钟。 代码地址 环境&#xff1a;需要pygame库&#xff0c;可用pip安装&#xff1a;pip install pygame 1. 基础版本 首先进行一些初始化&#xff0c;初始…

MySQL 多表查询与事务的操作

一,多表联查 有些数据我们已经拆分成多个表,他们之间通过外键进行连接.当我们要查询两个表的数据,各取其中的一列或者多列. 这时候就需要使用多表联查. 数据准备: # 创建部门表 create table dept(id int primary key auto_increment,name varchar(20) ) insert into dept (n…

MySQL 多表关系(介绍) 一对多/多对多

一对多 举例介绍 例子: 部门与员工 在常理上来说: 一个部门有多个员工&#xff0c;一个员工只对应一个部门实现方式: 在多的一方建立外键&#xff0c;指向一的一方的主键 多对多 举例介绍 例子: 学生与课程 在常理上来说: 一个学生可以有多个课程,一门课程可以有多个学生实…

热插拔技术(番外)

5、总线热插拔及系统解决方案 在实际运用中&#xff0c;总线上插入板卡时&#xff0c;由于新插入板卡电容的充电以及上电过程中一些低阻抗通道的存在&#xff0c;会产生极大的浪涌电流&#xff0c;拉低总线电平&#xff0c;对总线上其他设备产生干扰&#xff0c;影响总线上其他…

【机器学习】TinyML的介绍以及在运动健康领域的应用

&#x1f9d1; 作者简介&#xff1a;阿里巴巴嵌入式技术专家&#xff0c;深耕嵌入式人工智能领域&#xff0c;具备多年的嵌入式硬件产品研发管理经验。 &#x1f4d2; 博客介绍&#xff1a;分享嵌入式开发领域的相关知识、经验、思考和感悟,欢迎关注。提供嵌入式方向的学习指导…

前端基础篇-深入了解 Ajax 、Axios

&#x1f525;博客主页&#xff1a; 【小扳_-CSDN博客】 ❤感谢大家点赞&#x1f44d;收藏⭐评论✍ 文章目录 1.0 Ajax 概述 2.0 Axios 概述 3.0 综合案例 1.0 Ajax 概述 通过 Ajax 可以给服务器发送请求&#xff0c;并获取服务器响应的数据。异步交互是指&#xff0c;可以在不…

高效编写产品规格书的秘诀与注意事项

高效编写产品规格书的秘诀&#xff1a;学会利用简单的工具&#xff0c;写出效果最佳的产品规格书。比如&#xff0c;你可以使用HelpLook、Markdown编辑器、LaTeX、notion等。 在快节奏的商业环境中&#xff0c;产品规格书是企业向市场展示产品特性和优势的重要工具。一份清晰、…

Linux——进程通信(三)命名管道

前言 我们在之前学习了匿名管道与匿名管道的应用——进程池&#xff0c;但是匿名管道的通信&#xff0c;需要有血缘关系的进程&#xff08;通过fork创建的进程们&#xff09;&#xff0c;如果我想让两个毫不相干的进程进行通信&#xff0c;可以采样命名管道的方式&#xff08;…

如何在Windows系统使用VS Code制作游戏网页并实现无公网IP远程访问

文章目录 前言1. 编写MENJA小游戏2. 安装cpolar内网穿透3. 配置MENJA小游戏公网访问地址4. 实现公网访问MENJA小游戏5. 固定MENJA小游戏公网地址 前言 本篇教程&#xff0c;我们将通过VS Code实现远程开发MENJA小游戏&#xff0c;并通过cpolar内网穿透发布到公网&#xff0c;分…

提升Java编程安全性-代码加密混淆工具的重要性和应用

在Java编程领域中&#xff0c;保护代码安全性和知识产权至关重要。本文旨在探讨代码加密混淆工具在提升代码安全性和保护知识产权方面的重要性。我们将介绍几款流行的Java代码加密混淆工具&#xff0c;如ProGuard、DexGuard、Jscrambler、DashO和ipaguard&#xff0c;并分析它们…

【RabbitMQ】【Docker】基于docker-compose构建rabbitmq容器

本文通过docker-compose构建一个单体的rabbtimq容器。 1&#xff0c;docker、docker-compose环境 首先需要有docker和docker-compose环境&#xff0c;docker安装[1]&#xff0c;docker-compose安装[2]。 通过下列命令确定docker、docker-compose是否安装成功。 [root192 ge…

单片机LED灯闪烁

延时函数计算&#xff08;相关代码生成&#xff09;&#xff1a; #include "reg52.h" #include <INTRINS.H> void Delay500ms() //11.0592MHz {unsigned char i, j, k;_nop_();_nop_();i 22;j 3;k 227;do{do{while (--k);} while (--j);} while (--i); }vo…

利用Xinstall,实现安装页面快速拉起App,推广效果倍增!

在移动互联网时代&#xff0c;App推广已成为广告主和开发者的重要任务。然而&#xff0c;面对激烈的市场竞争&#xff0c;如何提升推广效率、洞悉推广效果并衡量广告ROI&#xff0c;成为摆在他们面前的难题。今天&#xff0c;我们将聚焦一个关键环节——安装页面拉起App&#x…