当前位置: 首页 > 知识库问答 >
问题:

javascript - 如何在H5页面实现横屏主动切换功能?

夹谷岳
2024-12-05

如何在H5页面实现横屏主动切换功能。
注意是主动切换横屏,而非是检测横竖屏。
目前尝试了两种方案,一种是通过旋转根节点,同时交换根节点宽高,并通过定位来实现布局中心点的偏移来实现样式上的横屏切换。但是这种方案遇到了一个问题,因为项目中引入了vant组件库,横屏后会导致组件库的一些样式计算出现问题,例如气泡弹出框,横屏后的弹出框的位置计算错误。同时一些选择器,还是需要竖屏下的上下操作才能滑动。以下是实现的一个简单的html示例

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>横屏切换示例</title>
    <link rel="stylesheet" href="https://unpkg.com/vant@2.12/lib/index.css" />
  </head>
  <style>
    #app {
      transition: all 0.2s;
    }

    .landscape {
      width: 100vh;
      height: 100vw;
      position: absolute;
      top: calc((100vh - 100vw) / 2);
      left: calc(-1 * (100vh - 100vw) / 2);
      transform: rotate(90deg);
      transform-origin: 50% 50%;
    }
    .my-swipe .van-swipe-item {
      color: #fff;
      font-size: 20px;
      line-height: 150px;
      text-align: center;
      background-color: #39a9ed;
    }
  </style>

  <body>
    <div id="app">
      <van-button type="primary" id="toggleFullscreen" @click="switchDirection">
        {{ direction === directionObj.portrait ? "切换为横屏" : "切换为竖屏" }}
      </van-button>
      <van-popover
        v-model="showPopover"
        placement="bottom"
        trigger="click"
        :actions="actions"
        get-container="#app"
        id="popoverBtn"
      >
        <!-- :offset="[-112,-112]" -->
        <template #reference>
          <van-button type="primary">打开popover</van-button>
        </template>
      </van-popover>
      <van-button type="primary" @click="openDialog">打开dialog</van-button>
      <van-button type="primary" @click="showPopup = true">打开Popup</van-button>
      <van-tabs>
        <van-tab title="标签 1">内容 1</van-tab>
        <van-tab title="标签 2">内容 2</van-tab>
        <van-tab title="标签 3">内容 3</van-tab>
        <van-tab title="标签 4">内容 4</van-tab>
      </van-tabs>
      <van-button type="primary" @click="previewImg">预览图片</van-button>
      <div class="content">
        <p>点击按钮切换横竖屏模式。</p>
      </div>
      <van-swipe class="my-swipe" :autoplay="3000" indicator-color="white">
        <van-swipe-item>1</van-swipe-item>
        <van-swipe-item>2</van-swipe-item>
        <van-swipe-item>3</van-swipe-item>
        <van-swipe-item>4</van-swipe-item>
      </van-swipe>
      <van-popup v-model="showPopup" position="bottom">
        <van-picker title="标题" show-toolbar :columns="columns" />
      </van-popup>
    </div>
    <script src="https://unpkg.com/vue@2/dist/vue.js"></script>
    <script src="https://unpkg.com/vant@2.12/lib/vant.min.js"></script>
    <script>
      const directionObj = {
        portrait: "portrait", // 竖屏
        landscape: "landscape", // 横屏
      };
      new Vue({
        el: "#app",
        data: () => {
          return {
            directionObj: directionObj,
            direction: "portrait",
            showPopover: false,
            // 通过 actions 属性来定义菜单选项
            actions: [{ text: "选项一" }, { text: "选项二" }, { text: "选项三" }],
            showPopup: false,
            columns: ["杭州", "宁波", "温州", "绍兴", "湖州", "嘉兴", "金华", "衢州"],
          };
        },
        watch: {
          direction(newValue) {
            const appDom = document.getElementById("app");
            if (newValue === directionObj.portrait) {
              appDom.classList.remove(directionObj.landscape);
              appDom.classList.add(directionObj.portrait);
            } else {
              appDom.classList.remove(directionObj.portrait);
              appDom.classList.add(directionObj.landscape);
            }
          },
        },
        methods: {
          switchDirection() {
            if (this.direction === directionObj.portrait) {
              this.direction = directionObj.landscape;
            } else {
              this.direction = directionObj.portrait;
            }
          },
          openDialog() {
            window.vant.Dialog.confirm({
              title: "标题",
              message: "弹窗内容",
              getContainer: "#app",
            }).then(() => {
              console.log("ok");
            });
          },
          previewImg() {
            window.vant.ImagePreview({
              images: [
                "https://img01.yzcdn.cn/vant/apple-1.jpg",
                "https://img01.yzcdn.cn/vant/apple-2.jpg",
              ],
              startPosition: 0,
            });
          },
        },
      });
    </script>
  </body>
</html>

另外一种也是先通过样式旋转根节点,来实现横屏,然后在用户手动横屏后通过检测设备方向API来取消样式,使页面自然的横屏展示,但是如果用户设置了锁定屏幕,则也有一定的问题。

共有1个答案

方宜
2024-12-05

思路

  1. 通过旋转根节点实现横屏

    • 在切换横屏时,通过旋转根节点来实现横屏效果。
  2. 检测设备方向

    • 在用户手动横屏后,通过设备方向 API 来取消样式,使页面自然横屏展示。
  3. 处理屏幕锁定

    • 如果用户锁定了屏幕方向,提示用户解锁屏幕方向。
  4. 兼容性处理

    • 确保在不同浏览器中都能正常工作。

代码实现

HTML 和 CSS

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>横屏切换示例</title>
    <link rel="stylesheet" href="https://unpkg.com/vant@2.12/lib/index.css" />
  </head>
  <style>
    #app {
      transition: all 0.2s;
    }

    .landscape {
      width: 100vh;
      height: 100vw;
      position: absolute;
      top: calc((100vh - 100vw) / 2);
      left: calc(-1 * (100vh - 100vw) / 2);
      transform: rotate(90deg);
      transform-origin: 50% 50%;
    }

    .portrait {
      /* 竖屏样式 */
    }

    .my-swipe .van-swipe-item {
      color: #fff;
      font-size: 20px;
      line-height: 150px;
      text-align: center;
      background-color: #39a9ed;
    }
  </style>
  <body>
    <div id="app">
      <van-button type="primary" id="toggleFullscreen" @click="switchDirection">
        <template v-if="direction === directionObj.portrait">切换为横屏</template>
        <template v-else>切换为竖屏</template>
      </van-button>
      <!-- 其他 Vant 组件 -->
    </div>
    <script src="https://unpkg.com/vue@2/dist/vue.js"></script>
    <script src="https://unpkg.com/vant@2.12/lib/vant.min.js"></script>
    <script>
      const directionObj = {
        portrait: "portrait", // 竖屏
        landscape: "landscape", // 横屏
      };

      new Vue({
        el: "#app",
        data: () => ({
          directionObj: directionObj,
          direction: "portrait",
          showPopover: false,
          actions: [{ text: "选项一" }, { text: "选项二" }, { text: "选项三" }],
          showPopup: false,
          columns: ["杭州", "宁波", "温州", "绍兴", "湖州", "嘉兴", "金华", "衢州"],
        }),
        mounted() {
          const appDom = document.getElementById("app");
          appDom.classList.add(this.direction);
        },
        watch: {
          direction(newValue) {
            const appDom = document.getElementById("app");
            appDom.classList.toggle('landscape', newValue === directionObj.landscape);
            appDom.classList.toggle('portrait', newValue === directionObj.portrait);
          },
        },
        methods: {
          switchDirection() {
            if (this.direction === directionObj.portrait) {
              this.direction = directionObj.landscape;
              this.adjustVantComponentsForLandscape();
            } else {
              this.direction = directionObj.portrait;
              this.resetVantComponents();
            }
          },
          adjustVantComponentsForLandscape() {
            const popovers = document.querySelectorAll('.van-popover');
            popovers.forEach(popover => {
              popover.style.top = '50%';
              popover.style.left = '50%';
              popover.style.transform = 'translate(-50%, -50%)';
            });
          },
          resetVantComponents() {
            const popovers = document.querySelectorAll('.van-popover');
            popovers.forEach(popover => {
              popover.style.top = '';
              popover.style.left = '';
              popover.style.transform = '';
            });
          },
        },
      });

      window.addEventListener('orientationchange', () => {
        const appDom = document.getElementById('app');
        if (window.orientation === 90 || window.orientation === -90) {
          appDom.classList.remove('portrait');
          appDom.classList.add('landscape');
        } else {
          appDom.classList.remove('landscape');
          appDom.classList.add('portrait');
        }
      });

      function lockOrientation() {
        if (screen.orientation && screen.orientation.lock) {
          screen.orientation.lock('landscape').catch(err => {
            console.error('屏幕方向锁定失败:', err);
          });
        } else {
          alert('您的浏览器不支持屏幕方向锁定,请手动切换到横屏模式。');
        }
      }

      // 在切换横屏时调用
      lockOrientation();
    </script>
  </body>
</html>

总结

  1. 通过旋转根节点实现横屏:在切换横屏时,通过旋转根节点来实现横屏效果。
  2. 检测设备方向:在用户手动横屏后,通过设备方向 API 来取消样式,使页面自然横屏展示。
  3. 处理屏幕锁定:如果用户锁定了屏幕方向,提示用户解锁屏幕方向。
  4. 兼容性处理:确保在不同浏览器中都能正常工作。
 类似资料:
  • 本文向大家介绍Android实现页面滑动切换动画,包括了Android实现页面滑动切换动画的使用技巧和注意事项,需要的朋友参考一下 本文实例为大家分享了Android实现页面滑动切换动画的具体代码,供大家参考,具体内容如下 实现两个页面滑动切换,一些相册的效果也是如此 一个Activity的界面配置文件 activity_main.xml: MainActivity.java: 在res/anim

  • 本文向大家介绍Android横竖屏切换实例总结,包括了Android横竖屏切换实例总结的使用技巧和注意事项,需要的朋友参考一下 本文实例总结了Android横竖屏切换相关技巧。分享给大家供大家参考,具体如下: 一、禁止横竖屏切换 Android横竖屏切换在手机开发中比较常见,很多软件在开发过程中为了避免横竖屏切换时引发不必要的麻烦,通常禁止掉横竖屏的切换,即通过在AndroidManifest.x

  • Since 10.0.8 setLandscape(android only) 横竖屏自由切换 setLandscape 使用方法 // 切换横屏 AlipayJSBridge.call('setLandscape', {}, function(e){ console.log(e) }); // 切换竖屏 AlipayJSBridge.call('setPortrait', {}, fun

  • 关键信息:前端、web应用、vue、vue-router 在公司的项目遇到了底部 tab 栏切换的场景,类似于 appstore 底部 tab 的模式,如下图: 我在最开始开发的时候,选择每个 tab 都是一个大的路由,结构如下: 但是这种单页面设计模式会遇到的问题就是在切换 Tab1 到 Tab2 的时候,此时我想做的只是隐藏 Tab1 而不希望这个页面整个卸载掉(排除使用 keep-alive

  • 本文向大家介绍Android横竖屏幕切换小结,包括了Android横竖屏幕切换小结的使用技巧和注意事项,需要的朋友参考一下 Android手机或平板都会存在横竖屏切换的功能,通常是由物理重力感应触发的,但是有时候也不尽然,通常在设置里面我们可以对手机的横竖屏切换进行关闭。 AndroidManifest.xml activity_main.xml MainActivity.java 以上内容给大家

  • 本文向大家介绍Android 屏幕横竖切换详解,包括了Android 屏幕横竖切换详解的使用技巧和注意事项,需要的朋友参考一下 Android 屏幕横竖切换 Android 里面控制Activity的方向,只要在AndroidManifest.xml里面对应的Activity节点下加一句 android:screenOrientation="landscape"(landscape是横屏,port

  • 本文向大家介绍实现一个页面锁屏的功能相关面试题,主要包含被问及实现一个页面锁屏的功能时的应答技巧和注意事项,需要的朋友参考一下 <!DOCTYPE html> <html> <head> <title>Ctrl+l监控锁屏</title> </head> <body> <div id="message_div"></div> <script type="text/javascript" langu

  • 本文向大家介绍Android 实现视频字幕Subtitle和横竖屏切换示例,包括了Android 实现视频字幕Subtitle和横竖屏切换示例的使用技巧和注意事项,需要的朋友参考一下 系统自带的VideoView有些视频格式不支持,那么我们可以用第三方实现的VideoView替代系统的来播放视频,比较流行的有ijkplayer、vitamio。 最近有个需求就是需要给视频添加字幕,其实也挺简单的。