如何实现PC端页面预览H5(vant)?

5,356 阅读2分钟

需求/背景

最近项目需要做一个H5,H5要求在PC端页面预览(具体需求不展开说了),类似下图的效果。大概是做完H5,然后把H5通过iframe嵌到PC端的一个页面中

image.png

H5用到的技术是Vue+Vant

本篇文章主要讲如何实现在PC端页面预览H5,记录踩过的一些坑

ps:此需求算是较常见且通用的需求,也欢迎大家评论区探讨实现方案🙌

问题关键点

  • H5如何嵌入PC端页面
  • PC端不支持滑动事件,H5轮播图如何滑动
  • PC端如何区分滑动、点击事件

具体实现

step1: iframe嵌入H5

在PC页面通过iframe嵌入H5,代码如下图

<template>
  <div class="preview">
    <!-- 页面其他模块 -->
    <div>
      <h2>pageId: {{ pageData ? pageData.pageId : '' }}</h2>
      <h3>页面数据结构:</h3>
      <json-viewer
        class="preview-pagedata"
        :value="pageData"
        :expand-depth="99"
        copyable
      />
    </div>
    
    <!-- 模拟手机预览 -->
    <div class="preview-wrapper">
      <div class="preview-header">
        <div class="preview-statbar">
          <img
            class="preview-statbar-img"
            alt="presentation"
            :src="phoneUrl"
          >
        </div>
      </div>

      <section>
        <iframe
          class="preview-content"
          src="#/home"
          frameborder="0"
        />
      </section>
    </div>
  </div>
</template>
<script>
import JsonViewer from 'vue-json-viewer';
export default {
  components: { JsonViewer },
  data() {
    return {
      pageData: {},
      phoneUrl: require('@/assets/images/phone.png')
    };
  },
  created() {
    // 监听子组件的关闭事件消息
    window.addEventListener('message', this.getPageData, false);
  },
  beforeDestroy() {
    window.removeEventListener('message', this.getPageData, false);
  },
  methods: {
    getPageData(e) {
      if (e.data.pageId) {
        this.pageData = e.data;
      }
    },
  },
};
</script>

<style scoped lang="less">
.preview {
  display: flex;
  justify-content: space-around;
  margin-top: 20px;
  color: #404040;

  &-pagedata {
    width: 800px;
    height: 520px;
    overflow: auto;
    border: 1px solid #ddd;
  }

  &-wrapper {
    width: 377px;
    height: 620px;
  }

  &-header {
    height: 20px;
    margin-top: 20px;
    text-align: center;
    background:
      -webkit-gradient(
        linear,
        left top,
        left bottom,
        from(rgba(55, 55, 55, 0.98)),
        to(#545456)
      );
    background: -webkit-linear-gradient(rgba(55, 55, 55, 0.98), #545456);
    background: linear-gradient(rgba(55, 55, 55, 0.98), #545456);
    border-radius: 4px 4px 0 0;
  }

  &-statbar {
    height: 20px;
    margin-bottom: 4px;

    &-img {
      width: 96%;
      height: 80%;
      margin: 0 2%;
      vertical-align: middle;
      border-style: none;
    }
  }

  &-content {
    width: 377px;
    height: 600px;
    overflow: auto;
    border-top: none;
    border-right: 1px solid rgb(247, 247, 247);
    border-bottom: 1px solid rgb(247, 247, 247);
    border-left: 1px solid rgb(247, 247, 247);
    border-image: initial;
    box-shadow: rgb(235 235 235) 0 2px 4px;
  }
}
</style>

效果图如下图:

image.png

step2: PC端如何支持滑动事件

嵌入后发现H5页面存在滑动事件的地方都失效了,比图轮播图

h5正常情况下滑动是下面这样的:

image.png 嵌入PC端页面后成了下面这样,滑动失效了😰

image.png 原因是:

H5没有鼠标,用触摸事件去实现滑动功能。touch事件包含touchstart、touchmove、touchend等

PC网页上的大部分操作都是用鼠标的,响应的是鼠标事件,包括mousedown、mousemove、mouseup和click事件等

如何解决? 方向:让pc页面能够识别左右滑动;自己模拟写个pc端的滑动事件 自己手动敲代码半天,发现vant有解决方案支持桌面端适配:

image.png

按上述方案后,可以滑动了,但是存在问题,滑动不准确,且滑动与点击无法区分,滑动也会触发点击事件(具体原因未知,后面有空去看看@vant/touch-emulator源码)

  • 滑动不准确问题:在图片上加上属性“pointer-events:none”,可实现

image.png

  • 滑动会触发点击事件问题:监听mousedown、和mousemove判断是滑动事件还是点击事件

    • 鼠标点击会触发:mousedown(鼠标按下) , mouseup(鼠标抬起)

    • 鼠标滑动会触发:mousedown(鼠标按下) , mousemove(鼠标移动),mouseup(鼠标抬起)

具体实现代码如下:

<template>
  <van-swipe>
    <van-swipe-item
      v-for="(item, index) in templateData.banners"
      @click="isClick ? $dialog(item.jumpUrl) : ''"
      @mousedown="mousedown"
      @mousemove="mousemove"
    >
      <van-image
        :src="$common.handlerPicSrc(item.imageUrl)"
        :style="{
          pointerEvents: 'none',
        }"
      />
    </van-swipe-item>
  </van-swipe>
</template>

<script>
export default {
  name: 'PocBanner',
  props: {
    templateData: {
      default: function () {},
      type: Object,
    },
  },
  data() {
    return {
      isClick: true,
    };
  },
  methods: {
    mousedown() {
      this.isClick = true;
    },
    mousemove() {
      this.isClick = false;
    },
  },
};
</script>