移动端H5

移动端H5的一些总结

页面禁止滚动(滑动穿透)

1.在移动端h5中,经常会遇到下图这种情况的弹窗,弹窗背景后面的内容不允许滚动
2.只需要在背景节点身上加上@touchmove.prevent即可(vue中),此时处于该节点及其子节点等将无法实现页面滚动
如果弹窗内的内容不滚动,只有点击时,该方式适用; 内容滚动时是不适用的
移动端H5_第1张图片
**当弹窗内需要滚动时,就需要使用下面这种方式了
3.弹出弹窗时,禁止滚动,并停留在当前位置

const disableScroll = (ref) => {
  var scrollTopVal = document.documentElement.scrollTop || document.body.scrollTop;
  // 禁止滑动
  const selectdom = ref || 'app';
  this.$refs[selectdom].style.position = "fixed";
  this.$refs[selectdom].style.top = "-" + scrollTopVal + 'px';
  this.$refs[selectdom].style.width = '100%';
  this.$refs[selectdom].style.overflow = "hidden";
}

4.关闭弹窗时,打开页面滚动功能,恢复在停留位置

const enableScroll = (ref) => {
  /** *取消滑动限制***/
  const selectdom = ref || 'app';
  var scrollVal = Math.abs(parseFloat(this.$refs[selectdom].style.top));
  this.$refs[selectdom].style.position = "";
  this.$refs[selectdom].style.overflow = "";
  this.$refs[selectdom].style.top = "";
  if (document.body) {
    document.body.scrollTop = scrollVal;
  }
  if (document.documentElement) {
    document.documentElement.scrollTop = scrollVal;
  }
}

IOS全面屏安全区

像iphonex、iphone12、iphone13等等,这些全面屏手机存在一个安全区,一般需要进行适配

/* 适配 iPhone XS Max / iPhone XR */
@media only screen and (device-width: 375px) and (device-height: 812px) and (-webkit-device-pixel-ratio: 3),
    (device-width: 414px) and (device-height: 896px),
    (device-width: 390px) and (device-height: 844px) and (-webkit-device-pixel-ratio: 3),
    (device-width: 428px) and (device-height: 926px) and (-webkit-device-pixel-ratio: 3) {
    #app {
      padding-top: env(safe-area-inset-top); // 顶部安全区
      // env(safe-area-inset-bottom) 底部安全区
    }
}

超出固定宽度显示省略号(需要给固定宽度)

1.单行

width: 100px;
white-space: nowarp;
overflow: hidden;
text-overflow: ellipsis;

2.多行

width: 200px;
/* height: 100px; 如果设置了高度,且高度超过文本显示行数,在第三行会正常出现省略号,但是三行之后的仍然正常显示*/
background-color: pink;
/* 设置高度是行高的倍数,防止文本露出一半 */
line-height: 20px;
/* 旧版弹性盒 */
display: -webkit-box;
/* 弹性盒子元素垂直排列 */
-webkit-box-orient: vertical;
/* 控制要显示的行数 */
-webkit-line-clamp: 3;
overflow: hidden;

防止点击穿透

@click.stop 或者点击事件中 事件参数e.preventDefault()阻止默认事件

锚点索引

在移动端社交通讯类app中,通常会出现类似通讯录的ui功能,如下图
实现方案一:

  1. 索引dom身上挂上href属性,值为锚点id
  2. 锚点dom身上挂上id属性

预加载

在app中经常会通过特定条件触发弹窗与动画,但是当资源较大时,无法立刻加载出,会出现图片断层或者动画卡顿,用户体验度会不太好,在显示之前预先加载后,使用时可以避免这些情况
方案一

// 存放本地图片路径的数组
const imgSrcArr = [
 	'./images/egg.png',
    './images/put-grey.png',
    './images/activityRuleBg.png',
    './images/myPrize.png',
    ..., // 可以存放本地图片路径或者网络图片地址
];

// 存放生成的img对象
const imgWrap = [];

/**
* 预加载图片资源
* @param {array} arr 存放本地图片路径的数组(预加载)
*/
preloadImg(arr: string[]) {
   for(let i =0; i< arr.length ;i++) {
      this.imgWrap[i] = new Image();
      this.imgWrap[i].src = arr[i];
  }
}

preloadImg(imgSrcArr);

内容横向滚动

<div class="box">
	<ul>
		<li>li>
	ul>
div>

<style lang="less">
.box {
	width: 100%;
    height: 80px;
    overflow-x: scroll;
    ul {
    	display: flex;
		height: 80px;
		width: max-content;  // 设置宽度为内容的最大宽度
		flex-wrap: nowrap;
		overflow: hidden; // 超出的隐藏 上面父级我们写了overflow-x: scroll; 会让他滚动
    }
}
style>

获取服务器时间

const nowTime = () => {
  let xmlHttp = new XMLHttpRequest();
  if( !xmlHttp ){
     xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
  }
  xmlHttp.open("HEAD", location.href, false);
  xmlHttp.send();
  const severtime = new Date(xmlHttp.getResponseHeader("Date"));
  return severtime.getTime();
};

// 获取指定日期时间戳
new Date('2023-2-9 12:00:00');

解码与编码

具体参考: 传送门

编码 解码
encodeURIComponent decodeURIComponent
encodeURI decodeURI
escape unescape

元素标签在ts中的类型

interface Type {
    "a": HTMLAnchorElement;
    "abbr": HTMLElement;
    "address": HTMLElement;
    "applet": HTMLAppletElement;
    "area": HTMLAreaElement;
    "article": HTMLElement;
    "aside": HTMLElement;
    "audio": HTMLAudioElement;
    "b": HTMLElement;
    "base": HTMLBaseElement;
    "bdi": HTMLElement;
    "bdo": HTMLElement;
    "blockquote": HTMLQuoteElement;
    "body": HTMLBodyElement;
    "br": HTMLBRElement;
    "button": HTMLButtonElement;
    "canvas": HTMLCanvasElement;
    "caption": HTMLTableCaptionElement;
    "cite": HTMLElement;
    "code": HTMLElement;
    "col": HTMLTableColElement;
    "colgroup": HTMLTableColElement;
    "data": HTMLDataElement;
    "datalist": HTMLDataListElement;
    "dd": HTMLElement;
    "del": HTMLModElement;
    "details": HTMLDetailsElement;
    "dfn": HTMLElement;
    "dialog": HTMLDialogElement;
    "dir": HTMLDirectoryElement;
    "div": HTMLDivElement;
    "dl": HTMLDListElement;
    "dt": HTMLElement;
    "em": HTMLElement;
    "embed": HTMLEmbedElement;
    "fieldset": HTMLFieldSetElement;
    "figcaption": HTMLElement;
    "figure": HTMLElement;
    "font": HTMLFontElement;
    "footer": HTMLElement;
    "form": HTMLFormElement;
    "frame": HTMLFrameElement;
    "frameset": HTMLFrameSetElement;
    "h1": HTMLHeadingElement;
    "h2": HTMLHeadingElement;
    "h3": HTMLHeadingElement;
    "h4": HTMLHeadingElement;
    "h5": HTMLHeadingElement;
    "h6": HTMLHeadingElement;
    "head": HTMLHeadElement;
    "header": HTMLElement;
    "hgroup": HTMLElement;
    "hr": HTMLHRElement;
    "html": HTMLHtmlElement;
    "i": HTMLElement;
    "iframe": HTMLIFrameElement;
    "img": HTMLImageElement;
    "input": HTMLInputElement;
    "ins": HTMLModElement;
    "kbd": HTMLElement;
    "label": HTMLLabelElement;
    "legend": HTMLLegendElement;
    "li": HTMLLIElement;
    "link": HTMLLinkElement;
    "main": HTMLElement;
    "map": HTMLMapElement;
    "mark": HTMLElement;
    "marquee": HTMLMarqueeElement;
    "menu": HTMLMenuElement;
    "meta": HTMLMetaElement;
    "meter": HTMLMeterElement;
    "nav": HTMLElement;
    "noscript": HTMLElement;
    "object": HTMLObjectElement;
    "ol": HTMLOListElement;
    "optgroup": HTMLOptGroupElement;
    "option": HTMLOptionElement;
    "output": HTMLOutputElement;
    "p": HTMLParagraphElement;
    "param": HTMLParamElement;
    "picture": HTMLPictureElement;
    "pre": HTMLPreElement;
    "progress": HTMLProgressElement;
    "q": HTMLQuoteElement;
    "rp": HTMLElement;
    "rt": HTMLElement;
    "ruby": HTMLElement;
    "s": HTMLElement;
    "samp": HTMLElement;
    "script": HTMLScriptElement;
    "section": HTMLElement;
    "select": HTMLSelectElement;
    "slot": HTMLSlotElement;
    "small": HTMLElement;
    "source": HTMLSourceElement;
    "span": HTMLSpanElement;
    "strong": HTMLElement;
    "style": HTMLStyleElement;
    "sub": HTMLElement;
    "summary": HTMLElement;
    "sup": HTMLElement;
    "table": HTMLTableElement;
    "tbody": HTMLTableSectionElement;
    "td": HTMLTableDataCellElement;
    "template": HTMLTemplateElement;
    "textarea": HTMLTextAreaElement;
    "tfoot": HTMLTableSectionElement;
    "th": HTMLTableHeaderCellElement;
    "thead": HTMLTableSectionElement;
    "time": HTMLTimeElement;
    "title": HTMLTitleElement;
    "tr": HTMLTableRowElement;
    "track": HTMLTrackElement;
    "u": HTMLElement;
    "ul": HTMLUListElement;
    "var": HTMLElement;
    "video": HTMLVideoElement;
    "wbr": HTMLElement;
}

时间戳转日期特定格式

日期格式:
1、(Y-M-D) => 年 - 月 - 日
2、(h-m-s) => 时 - 分 - 秒

/**
 * 时间戳转日期格式
 * @param {number} timestamp 时间
 * @param {string} format 日期格式(Y-M-D) => 年-月-日    (h-m-s) => 时-分-秒
 */
 formatDate(timestamp: number, format: string) {
    let dateStr = format;
    const time = new Date(timestamp * 1000);
    const newArr = [];
    const formatArr = ['Y', 'M', 'D', 'h', 'm', 's'];
    newArr.push(`${time.getFullYear()}`.padStart(2, '0'));
    newArr.push(`${(time.getMonth() + 1)}`.padStart(2, '0'));
    newArr.push(`${(time.getDate())}`.padStart(2, '0'));
    newArr.push(`${(time.getHours())}`.padStart(2, '0'));
    newArr.push(`${(time.getMinutes())}`.padStart(2, '0'));
    newArr.push(`${(time.getSeconds())}`.padStart(2, '0'));

    newArr.forEach((item, index) => {
      dateStr = dateStr.replace(formatArr[index], item);
    });
    return dateStr;
  }

监听内容是否出现在可视区

一般用于做一些模块曝光判断

const exposuredObserver = new IntersectionObserver((entries) => {
  const [itemEntry] = entries;
    if (itemEntry.isIntersecting) {
      if (!this.isExposured) {
        this.$emit('bannerAdExposured');
        this.exposuredObserver?.disconnect();
      }
    }
}, {
  threshold: 0,
});
this.exposuredObserver.observe(this.$refs.bannerAd);

利用html2canvas截图并转换成base64

安装:npm i html2canvas

// 获取需要截取的dom节点
const posterImg = document.getElementById('share-poster') || null;
// 节点信息
const posInfo = posterImg?.getBoundingClientRect() || null;
// 生成canvas画布
const canvas = await html2canvas(posterImg, {
   allowTaint: true, // 是否允许画布污染
   useCORS: true, // 是否允许图片跨域
   width: posInfo.width, // 切图宽度
   height: posInfo.height, // 切图高度
   scale: window.devicePixelRatio, // 物理像素比
   dpi: 300,
});
canvas.getContext('2d');
// base64
const addr = canvas.toDataURL('image/jpeg', 1.0);
const base64 = addr.replace(/^data:image\/jpeg;base64,/, 'data:image/jpg;base64,');

Element.getBoundingClientRect获取元素的大小及其相对于视口的位置

传送门
返回值:返回值是一个 DOMRect 对象,这个对象是由该元素的 getClientRects() 方法返回的一组矩形的集合, 即:是与该元素相关的CSS 边框集合
属性值:

属性 描述
top 元素上边距离页面上边的距离
left 元素右边距离页面左边的距离
right 元素右边距离页面左边的距离
bottom 元素下边距离页面上边的距离
width 元素宽度
height 元素高度

你可能感兴趣的:(移动端,前端,css,vue.js)