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

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 [
  {
   

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

异常:程序出现的问题

目的&#xff1a;为了以后发现异常后怎么去处理 异常的作用

学点儿Java_Day7_在实体类当中IDEA无法进行单元测试(@Test没有启动按钮)

在敲代码体会继承和访问修饰符的时候忽然遇到了单元测试不管用的情况&#xff0c;表现为没有启动按钮   经过一番折腾&#xff0c;发现我的测试是在具有构造函数的实体类Person当中进行的&#xff0c;当我把所有的构造函数删除后&#xff0c;启动按钮又出来了&#xff0c;加…

鸿蒙开发实战:【文件管理】

介绍 本示例主要展示了文件管理相关的功能&#xff0c;使用[ohos.multimedia.medialibrary]、[ohos.filemanagement.userFileManager] 、[ohos.fileio] 、[ohos.file.fs]、[ohos.app.ability.contextConstant] 等接口&#xff0c;实现了增添文件、删除文件、查找指定类型文件…

Java基础夯实——八股文【2024面试题案例代码】

1、Java当中的基本数据类型 Java中常见的数据类型及其对应的字节长度和取值范围如下&#xff1a; byte&#xff1a;1字节&#xff0c;取值范围为-128到127。short&#xff1a;2字节&#xff0c;取值范围为-32,768到32,767。int&#xff1a;4字节&#xff0c;取值范围为-2,147…

【Linux】初识进程

目录 操作系统是什么 设计操作系统的目的 操作系统的定位 如何理解管理 管理的本质 管理的例子 计算机的管理概念图 操作系统管理逻辑的六字真言 系统调用和库函数的概念 进程 进程的概念 什么是PCB&#xff1f; PCB的主要内容 如何查看进程&#xff1f; 通过系统…

数据结构与算法----复习Part 17 (图(Graph)初步)

本系列是算法通关手册LeeCode的学习笔记 算法通关手册&#xff08;LeetCode&#xff09; | 算法通关手册&#xff08;LeetCode&#xff09; (itcharge.cn) 目录 一&#xff0c;图&#xff08;Graph&#xff09; 图的分类 顶点的度 环形图和无环图 连通图和非连通图 强连…

远程服务器安装portainer —— docker的可视化工具

可视化工具&#xff08;了解即可&#xff09; 最常用的工具是 portainer portainer 是一个开源的容器管理平台&#xff0c;它提供了一个简单易用的用户界面&#xff0c;用于管理和监控 docker 容器集群。通过 portainer&#xff0c;用户可以轻松地进行容器的部署、启动、停止…

C++_回文串

目录 回文子串 最长回文子串 分割回文串 IV 分割回文串 II 最长回文子序列 让字符串成为回文串的最少插入次数 回文子串 647. 回文子串 思路&#xff0c;i j表示改范围内是否为回文串&#xff0c; ②倒着遍历是为了取出dp[i 1][j - 1] ③i j 只有一对&#xff0c;不会重复…

算法沉淀——贪心算法五(leetcode真题剖析)

算法沉淀——贪心算法五 01.跳跃游戏 II02.跳跃游戏03.加油站04.单调递增的数字 01.跳跃游戏 II 题目链接&#xff1a;https://leetcode.cn/problems/jump-game-ii/ 给定一个长度为 n 的 0 索引整数数组 nums。初始位置为 nums[0]。 每个元素 nums[i] 表示从索引 i 向前跳转…

一共有哪 3 类线程安全问题

一共有哪 3 类线程安全问题 运行结果错误发布和初始化导致线程安全问题活跃性问题死锁活锁饥饿 要想弄清楚有哪 3 类线程安全问题&#xff0c;首先需要了解什么是线程安全&#xff0c;线程安全经常在工作中被提到&#xff0c;比如&#xff1a;你的对象不是线程安全的&#xff0…

2024新版计算器:腾讯云服务器价格计算器,报价不求人

腾讯云服务器价格计算器可以一键计算出云服务器的精准报价&#xff0c;包括CVM实例规格价格、CPU内存费用、公网带宽收费、存储系统盘和数据盘详细费用&#xff0c;腾讯云百科txybk.com分享腾讯云价格计算器链接入口、使用方法说明&#xff0c;在腾讯云百科 txy.wiki 查看当前最…

全球盲盒火热下,海外盲盒APP助力我国盲盒出海

盲盒具有不确定性&#xff0c;与各类热门影视动漫合作推出的专属盲盒商品&#xff0c;吸引了无数年轻人&#xff0c;成为了年轻人的娱乐消费首选方式。 在互联网电商的推动下&#xff0c;盲盒在全球内的市场规模迅速扩大。受到市场增长的影响&#xff0c;各类资本公司也纷纷进…

【Python】import无法导入某一目录下的文件

问题&#xff1a; 如图所示&#xff0c;我在mains文件夹下面有一个main_VAE.py的程序&#xff0c;在与mains同级目录的models文件夹下面有一个variational_autoencoder.py&#xff08;可能上图无法显示完全models文件夹&#xff09;&#xff0c;此时我想要在main_VAE.py程序中导…

数据结构从入门到精通——直接选择排序

直接选择排序 前言一、选择排序的基本思想&#xff1a;二、直接选择排序三、直接选择排序的特性总结&#xff1a;四、直接选择排序的动画展示五、直接选择排序的代码展示test.c 六、直接选择排序的优化test.c 前言 直接选择排序是一种简单的排序算法。它的工作原理是每一次从未…

Linux-docker安装数据库mysql

1、拉去mysql镜像&#xff1a; docker pull mysql2、创建容器挂载路径 mkdir -p /usr/local/jiuxiang/mysql/data # 数据存储位置 mkdir -p /usr/local/jiuxiang/mysql/logs # 日志存储位置 mkdir -p /usr/local/jiuxiang/mysql/conf # 配置文件3、启动容器 docker run -…

详细分析Python模块中的雪花算法(附模板)

目录 前言1. 基本知识2. 模板3. Demo 前言 分布式ID的生成推荐阅读&#xff1a;分布式ID生成方法的超详细分析&#xff08;全&#xff09; 1. 基本知识 Snowflake 算法是一种用于生成全局唯一 ID 的分布式算法&#xff0c;最初由 Twitter 设计并开源 它被设计用于解决分布式…

sentinel整合openFeign实现fall服务降级

服务提供方: 导入依赖&#xff1a; <!--openfeign--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId></dependency><!--alibaba-sentinel--><depend…

猫猫编号

解法&#xff1a; 暴力 #include<iostream> #include<algorithm> #include<vector> using namespace std; #define endl \nint main() {int n, m, sum 1;cin >> n >> m;string s;cin >> s;int pre s[0] - 0;int t 0;for (int i 1; i…

【DAY13 软考中级备考笔记】操作系统

操作系统 3月17日 – 天气&#xff1a;晴 凑着周末&#xff0c;赶紧把操作系统完结一下。 1. 管程 管程也属于操作系统中的一种同步机制&#xff0c;为了解决多线程环境中的并发控制问题。它提供了一系列的高级同步原语。 作用于信号量一样&#xff0c;但是管程便携程序更加简单…

腾讯云优惠券介绍、领取入口及使用教程

腾讯云作为国内领先的云服务提供商&#xff0c;一直以其稳定、高效、安全的服务赢得了广大用户的信赖。为了回馈广大用户&#xff0c;腾讯云经常会推出各种优惠活动&#xff0c;其中优惠券就是最为常见和受欢迎的一种。 一、腾讯云优惠券介绍 腾讯云优惠券是腾讯云官方推出的一…