前沿

17年后开始公司的一个移动端项目(电商网站),框架选用是vue,这篇文章也是在花费1个月的时间,项目一期完成之后总结性文章,其中包括通用的移动端开发的遇到的坑以及vue移动端开发特有的一些坑,本博客旨在后在开发移动端的时候可以尽量避免掉踩过的坑

  • 移动端开发遇到的问题
  • vue移动开发特有坑以及小技巧分享
  • 移动端开发性能优化

一、移动端开发通用坑

1、click300ms延迟问题

讲道理,现在开发移动端基本是不会有这么一个问题的。但作为移动端以前的经典坑,我这里也拿出来说上一说吧。移动设备上的web网页是有300ms延迟的,玩玩会造成按钮点击延迟甚至是点击失效。这是由于区分单击事件和双击屏幕缩放的历史原因造成的。但在2014年的Chrome 32版本已经把这个延迟去掉了,so you know。但如果你还是出现了300ms的延迟问题,也是有路子搞定的。
解决方案如下:

  • fastclick可以解决在手机上点击事件的300ms延迟,直接引入即可
  • zepto的touch模块,tap事件也是为了解决在click的延迟问题
  • 若移动设备兼容性正常的话(IE/Firefox/Safari(IOS 9.3)及以上),只需加上一个meta标签
<meta name="viewport" content="width=device-width">

即把viewport设置成设备的实际像素,那么就不会有这300ms的延

2、移动端样式兼容处理

当今的手机端,各式各样的手机,屏幕分辨率也是各有不同,为了让页面可以可以兼容各大手机,解决方案如下

  • 设置meta标签viewport属性,使其无视设备的真实分辨率,直接通过dpi,在物理尺寸和浏览器之间重设分辨率,从而达到能有统一的分辨率的效果。并且禁止掉用户缩放
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no" />

使用rem进行屏幕适配,设置好root元素的font-size大小,然后在开发的时候,所有与像素有关的布局统一换成rem单位。针对不同的手机,使用媒体查询对root元素font-size进行调整

3、移动端宽高相等的元素(不定具体px)

  • 移动端开发时一般都会遇到需要一个正方形的元素,比如9宫格展示啦,评论图片啦,这时候就需要宽高相等,解决办法如下
// 这里vw就是屏幕的宽度,宽高都是屏幕的百分之30,这样就巧妙的让宽高都一样了
.div{width: 30vw;height: 30vw;
}

4、阻止旋转屏幕时自动调整字体大小

移动端开发时,屏幕有竖屏和横屏模式,当屏幕进行旋转时,字体大小则有可能会发生变化,从而影响页面布局的整体样式,为避免此类情况发生,只需设置如下样式即可

* {-webkit-text-size-adjust: none;
}

5、修改移动端难看的点击的高亮效果,iOS和安卓下都有效

* {-webkit-tap-highlight-color: rgba(0,0,0,0);
}

不过这个方法在现在的安卓浏览器下,只能去掉那个橙色的背景色,点击产生的高亮边框还是没有去掉,有待解决!

6、iOS下取消input在输入的时候英文首字母的默认大写

<input type="text" autocapitalize="none">

7、禁止 iOS 识别长串数字为电话

<meta name="format-detection" content="telephone=no" />

8、禁止 iOS 弹出各种操作窗口

-webkit-touch-callout: none;

9、禁止ios和android用户选中文字

-webkit-user-select: none;

10、calc的兼容处理

CSS3中的calc变量在iOS6浏览器中必须加-webkit-前缀,目前的FF浏览器已经无需-moz-前缀。 Android浏览器目前仍然不支持calc,所以要在之前增加一个保守尺寸:

div { width: 95%; width: -webkit-calc(100% - 50px); width: calc(100% - 50px);
}

11、fixed定位缺陷

iOS下fixed元素容易定位出错,软键盘弹出时,影响fixed元素定位,android下fixed表现要比iOS更好,软键盘弹出时,不会影响fixed元素定位 。iOS4下不支持position:fixed

解决方案: 可用iScroll插件解决这个问题

12、一些情况下对非可点击元素如(label,span)监听click事件,ios下不会触发

div { cursor: pointer;
}

针对此种情况只需要对不触发click事件的那些元素添加一行css代码即可

13、消除transition闪屏问题

/*设置内嵌的元素在 3D 空间如何呈现:保留 3D*/
-webkit-transform-style: preserve-3d;
/*(设置进行转换的元素的背面在面对用户时是否可见:隐藏)*/
-webkit-backface-visibility: hidden;

14、CSS动画页面闪白,动画卡顿

解决方法:

1.尽可能地使用合成属性transform和opacity来设计CSS3动画,不使用position的left和top来定位
2.开启硬件加速

-webkit-transform: translate3d(0, 0, 0);-moz-transform: translate3d(0, 0, 0);-ms-transform: translate3d(0, 0, 0);transform: translate3d(0, 0, 0);

15、iOS系统中文输入法输入英文时,字母之间可能会出现一个六分之一的空格

解决方法:通过正则去除

this.value = this.value.replace(/\u2006/g, '');

16、input的placeholder会出现文本位置偏上的情况

input 的placeholder会出现文本位置偏上的情况:PC端设置line-height等于height能够对齐,而移动端仍然是偏上,解决方案时是设置css

line-height:normal;

17、浮动子元素撑开父元素盒子高度

解决方法如下:

  1. 父元素设置为 overflow: hidden;
  2. 父元素设置为 display: inline-block; 等

这里两种方法都是通过设置css属性将浮动元素的父元素变成间接变成BFC元素,然后使得子元素高度可以撑开父元素。这里需要注意的时,最好使用方法1, 因为inline-block元素本身会自带一些宽高度撑开其本身。

18、往返缓存问题

点击浏览器的回退,有时候不会自动执行js,特别是在mobilesafari中。这与往返缓存(bfcache)有关系。 解决方法 :

window.onunload = function () {};

19、css滚动优化

解决方法:

-webkit-overflow-scrolling: touch;

20、点击穿透

一个CSS3的属性,加上后,所关联的元素的事件监听都会失效,等于让元素变得“看得见,点不着”。IE到11才开始支持,其他浏览器的当前版本基本都支持。详细介绍见这里:https://developer.mozilla.org/zh-CN/docs/Web/CSS/pointer-events

pointer-events: none;

二、vue移动开发特有坑以及小技巧分享

1、iOS原始输入法问题

iOS原始输入法,中文输入时,无法触发keyup事件,且keyup.enter事件无论中英文,都无法触发

解决方法:

  1. 改用input事件进行监听
  2. 将keyup监听替换成值的watch
  3. 让使用者安装三方输入法,比如搜狗输入法(不太现实)

2、input元素失焦问题

业务场景重现: 项目中需要写一个搜索组件,相关代码如下

<template><div class="y-search" :style="styles" :clear="clear"><form action="#" onsubmit="return false;"><input type="search"class="y-search-input"ref="search"v-model='model':placeholder="placeholder"@input="searchInputFn"@keyup.enter="searchEnterFn"@foucs="searchFocusFn"@blur="searchBlurFn"/><y-icons class="search-icon" name="search" size="14"></y-icons></form><div v-if="showClose" @click="closeFn"><y-icons class="close-icon" name='close' size='12'></y-icons></div></div>
</template>

其中我需要在enter的时候进行对应的搜索操作并实现失焦,解决方法其实很简单,在enter时进行DOM操作即可

searchEnterFn (e) {document.getElementsByClassName('y-search-input')[0].blur()// dosomething yourself
}

对了,这里还有一个坑,就是在移动端使用input类型为search的时候,必须使用form标签包裹起来,这样在移动端呼出键盘的enter才会是搜索按钮,否则只是默认的enter按钮。

4、巧用flex布局让图片等比缩放

这也是一个小技巧!项目中需要开发swiper轮播图,那么你懂的,图片肯定是需要保证等比缩放展示。

<div class="parent"><img :src="imgSrc" alt="">
</div><style lang="stylus" scoped>
.parent {width: 100px;height: 100px;display: flex;align-items: center;img {width :100%;height: auto;}
}
</style>

是不是贼简单,是的,贼简单这个样式同时适应手机全屏预览竖屏的情况,当手机横屏的时候,加一个媒体查询即可搞定

@media (orientation: landscape) {img {width autoheight 100%margin auto}
}

这里我就不上轮播图的代码了,有点小多。有需要的小伙伴可以私聊我,我后期直接传到github上去,代码可以自行查阅。

5、枚举值过滤处理

业务重现:考虑到项目后期会做国际化,前端需要对项目中几乎所有的枚举值进行过滤处理,从而进行展示

接下来就直接讲讲这块吧。既然要过滤,那么首选肯定是vue提供的filter指令。这里我举一个支付方式的枚举值处理的例子。首先配置代码如下

// 配置文件
export default {env: (process.env.NODE_ENV === 'development' ? require('./env/dev') : require('./env/pro')),headShow: false,lng: 'zh',
};

枚举代码如下

// 获取语言环境
import config from '../config/index';const {lng} = config;
// 账户类型
const type = {zh: {1: '银行',2: '支付宝',3: '微信支付',},en: {1: 'bank_type',2: 'alipay_type',3: 'wxpay_type',}
}
export default type[lng];

枚举注册代码分别如下

import accountType from './accountType'; // 账户类型const factory = {accountType(value) {if (value === -1) {return '请选择账户类型';}return accountType[value] ? accountType[value] : '请选择账户类型';}
}
const filter = [{name: 'formatEnum', // 过滤类型filter: function(value, type, status) {return factory[type](value, status);}}
];
export default {filter
};
// filter
import baseFilter from './filter/index';const filters = [...baseFilter.filter
];
filters.map(f => {Vue.filter(f.name, f.filter);return '';
});

接下来就可以轻松使用啦

<li><label支付类型</label><span>{{info.account_type | formatEnum('accountType')}}</span>
</li>

6、时间过滤处理

这点还是属于过滤处理的一个part,但是手机端有个兼容问题,如果是时间戳转的话,那么可以转化成任意我们想要的形式,但是String类型的时间转化的话,他只能兼容 "yyyy/MM/dd" 形式的时间值,因为我们DateTime组件默认的形式是"yyyy-MM-dd",那么只需要在DateTime组件正则替换一下即可,代码如下

currentValue = _this.currentValue = _this.value ? _this.value.replace(/-/g, '/') : '';

时间过滤代码如下

const filter = [{name: 'formatEnum', // 过滤类型filter: function(value, type, status) {return factory[type](value, status);}},{name: 'formatDate', // 日期filter: function(value, format = 'yyyy-MM-dd') {if (!value || value === '') return '';let v = value;if (!isNaN(value)) {v = +value * 1000;}const newDate = new Date(v);return newDate.Format(format);},}
];

7、路由权限判定

业务重现:由于不同的用户,可能拥有不同权限,而目前我们的项目是基于微信公众号进行开发的,页面权限这边也是交给了我们前端处理。既然要前端配置权限,那么我们能想到的比较好的方式就是通过配置路由文件,完成权限判定。下面我会列举一小部分代码(以我们的工单列表)进行演示,路由配置代码如下

const getWorkOrder = pageName => resolve => require(['../pages/WorkOrder'], pages => resolve(pages[pageName]))let routers = [];
routers = [{path: '/workorder',name: 'workorder',component: room,children: [{path: 'list', // 管家端工单列表name: 'list',rule: 3,component: getWorkOrder('WorkOrderList') //WorkOrder,},{path: 'managerList', // 店长端工单列表name: 'managerList',rule: 6,component: getWorkOrder('ManagerWorkOrder') // WorkOrder,},]}
]

然后进行路由统一过滤处理

import Vue from 'vue';
import Store from 'store';
import Router from 'vue-router';import routers from './router.config';
Vue.use(Router);// 遍历路由名称以及权限
let arr = {};
const routeName = function (router) {if (!router) return false;router.forEach((v) => {arr[v.name] = v.rule;routeName(v.children);})
}
routeName(routers);const RouterModel = new Router({mode: 'history',routes: routers,
});// 路由钩子,进入路由之前判断
RouterModel.beforeEach((to, from, next) => {// 处理query 参数,传入到 jumpUrl,便于登录后跳转到对应页面let qu =  Object.entries(to.query);if (qu.length > 0) {qu = qu.map((item, index) => {return item.join('=');})}if (arr[to.name]) {// 如果有权限需要const userInfo = Store.get('yu_info');const cookie = Vue.prototype.$util.getCookie('X-Auth-Token');const userId = Vue.prototype.$util.getCookie('userid');if (userInfo && cookie && +userId > 0) {next();} else {// 未登录,跳转登录let param = `jumpUrl=${to.path}`;if (qu.length > 0) {param += `&${qu.join("&")}`;}if (arr[to.name] && !to.query.rule) {param += `&rule=${arr[to.name]}`;}window.location.href = `/login?${param}`;}} else {// 如果不需要权限放行next();}
})export default RouterModel;

然后在登陆界面定位到微信授权

getCode() {// 定位到微信授权,若是不需要授权可以在此处处理let query = this.$route.query;let param = `jumpUrl=${query.jumpUrl || '/home'}`;let path = window.location.origin;// 登录角色处理let cfg = api[query.rule ? query.rule : 1];if (query.rule) {param += `&rule=${query.rule}`;}let redirect_url = encodeURIComponent(`${path}/login?${param}`);let url =  `https://open.weixin.qq.com/connect/oauth2/authorize?appid=${cfg.tempApp}&redirect_uri=${redirect_url}&response_type=code&scope=snsapi_userinfo&state=1#wechat_redirect`;if (query.rule === 3) {url += '&agentid=1000004';}location.replace = url;
}

如果不是微信端,访问到到rule规则的界面时,则会如下

而当微信授权通过的时候,rule权限不足的情况则会如下

8、使用vue-cli proxyTable进行反向代理,解决跨域问题

开发项目,在前后端联调的时候肯定是会遇上跨域的问题的。很简单,做个反向代理呗,对于想了解正向代理和反向代理的,请点击这里

vue-cli脚手架搭建的工程中,在config/index.js文件中可以利用预留的proxyTable一项,设置地址映射表,如下

proxyTable: {'/api': {target: 'http://www.example.com', // your target hostchangeOrigin: true, // needed for virtual hosted sitespathRewrite: {'^/api': ''  // rewrite path}}
}

然后使用http-proxy-middleware插件对api请求地址进行代理

// proxy api requests
Object.keys(proxyTable).forEach(function (context) {var options = proxyTable[context]if (typeof options === 'string') {options = { target: options }}app.use(proxyMiddleware(options.filter || context, options))
})

http-proxy-middleware地址

三、移动端开发性能优化

对于这点,有一篇文章建议大家可以先看看《移动前端H5性能优化指南》。接下来我会结合实际项目抽几个点配合代码进行较为详细的讲解。

1、首屏渲染优化

决定用户体验最重要的一个点之一,这个点的重要性,相信不用我说了。下面直接谈实战。

  • 减少资源请求次数

  • 加载时使用过渡样式,防止用户网络太差影响对首页的体验

  • 图片使用懒加载,这一part,我们目前项目中使用的vue的三方插件vue-lazyload,大致使用方法如下

    // 全局注册
    import VueLazyload from 'vue-lazyload';
    

Vue.use(VueLazyload, {
error: require(’./assets/close.svg’),
loading: require(’./assets/loading.svg’),
attempt: 1,
});

// 使用
<img v-lazy=“room.img” :alt=“room.community_name” width=“100%”>

  • HTML使用Viewport,Viewport可以加速页面的渲染。

    <meta name=”viewport” content=”width=device-width, initial-scale=1″>

    除此之外,还有很多点可做优化,进而提升首屏加载速度。

  • 2、雪碧图

    这个就很普遍了,为了减少图片请求次数,加快页面加载,当然会考虑使用雪碧图。来个小例子,一天,设计小姐姐给了我一张icon表,

    每张icon都有1k大小。好嘛,只能自己在线合张雪碧图,合完雪碧图顺带在线压缩优化下,然后总大小只有1 2K。还有一个点,就是尽量使用::before或::after伪类,Sprites中的图片排版可以更紧 ,图片体积更小, HTML更简洁。部分代码如下

    <style lang="stylus" scoped>.chose-house {height: 20px;width: 20px;margin 0 autoposition relative&::before {content: '\20';height: 100%;width: 100%;position: absolute;left: 0;top: 0;background: url('../../assets/sprite-min.png') 0px 0px no-repeat;}}
    </style>
    

    3、路由懒加载

    关于路由懒加载这一部分,尤大在vue-router文档中也有所提及,链接点击这里。

    其实在vue项目中使用路由懒加载非常简单,我们要做的就是把路由对应的组件定义成异步组件,代码如下

    //在router/index.js中引入组件时可使用如下异步方式引入
    const Foo = resolve => {// require.ensure 是 Webpack 的特殊语法,用来设置 code-split point// (代码分块)require.ensure(['./Foo.vue'], () => {resolve(require('./Foo.vue'))})
    }
    // or
    const Foo = resolve => require(['./Foo.vue'], resolve)
    

    再将组件按组分块,如

    const Foo = r => require.ensure([], () => r(require('./Foo.vue')), 'group-foo')
    

    实际项目中的代码则如同我在章节《路由权限判定》提及到的一样

    const getWorkOrder = pageName => resolve => require(['../pages/WorkOrder'], pages => resolve(pages[pageName]))let routers = [];
    routers = [{path: '/workorder',name: 'workorder',component: room,children: [{path: 'list', // 管家端工单列表name: 'list',rule: 3,component: getWorkOrder('WorkOrderList') //WorkOrder,},{path: 'managerList', // 店长端工单列表name: 'managerList',rule: 6,component: getWorkOrder('ManagerWorkOrder') // WorkOrder,},]}
    ]
    

    如上将组件通过传递pageName参数分别打包到了各个chunk中,这样每个组件加载时都只会加载自己对应的代码,从而加快渲染速度!

    4、全局组件按需注册

    当时我们为了优化首屏渲染速度,也是考虑到这一点,项目的src/main.js文件主要负责注册全局组件,插件,路由,以及实例化Vue等。在webpack的配置里面也是当成entry入口进行了配置,如果我在main.js里面讲每个组件都进行import的话,那么它将会全部一起注册打包,页面加载也会将每个组件文件都加载下来,这样对渲染速度还是有一定影响的。

    解决方法就是:按需注册,这样在打包的时候,会按需加载首页(其他界面也同样适用)使用到的全局组件。基本步骤如下:

    将需要注册的组件写进components/base.js文件中,然后exports出来

    exports.Foo = require('./Foo.vue');
    exports.Bar = require('./Bar.vue');
    exports.Baz = require('./Baz.vue');
    

    在main.js中进行注册

    const components = [require('./components/base').Foo,require('./components/base').Bar,require('./components/base').Baz,
    ];components.map(component => {Vue.component(component.name, component);
    });
    

移动端 / 微信浏览器开发遇到的坑相关推荐

  1. h5微信页面在手机微信端和微信web开发者工具中都能正常显示,但是在pc端微信浏览器上打不开(显示空白)

    记录一个最近在微信端页面开发时出现的问题:页面在手机微信端和微信web开发者工具中都能正常显示,但是在pc端微信浏览器上打不开(显示空白). 原因:pc端微信浏览器不支持es6,而我的代码使用了 le ...

  2. PC端微信浏览器js点击事件失效

    **电脑端微信浏览器js点击事件失效**前段时间发现开发的一个微信公众号上一个按钮的点击事件在手机上是正常的,电脑端手机微信里却不起作用.在网上找了好久都没有找到解决办法.后来查看其它的页面的同样的点 ...

  3. h5微信页面在手机微信端和微信web开发者工具中都能正常显示,但是在pc端微信浏览器上打不开(显示空白)...

    h5微信页面在手机微信和微信开发者工具中都能正常显示,但是在pc端微信浏览器上打不开或者数据加载不出来. 原因:pc端微信浏览器不支持ES6语法,我的代码中使用了一些ES6的特性 解决:将ES6转换为 ...

  4. JSAPI微信支付开发流程和坑

    首先,我先简要说明一下微信支付开发的流程 众所周知,工欲善其事,必先利其器,微信官方推出了web微信开发工具,有windows.linux.版本的,根据自己的开发环境选择合适自己的,登陆公众平台--& ...

  5. 移动端微信浏览器调试工具整理eruda,微信x5调试工具无法使用,推荐新工具eruda、vconsole和debugxweb

    新版本微信x5调试工具,debugtbs.qq.com无法使用,提示不支持切换x5内核 推荐新工具eruda和debugxweb.qq.com 目录 区别 一.移动端 eruda 二.debugxwe ...

  6. 微信PC端 微信浏览器打开控制台

    1. 版本回退 下载旧版本微信客服端,3.2.1版本之前的都可以,这里是https://link.csdn.net/?target=https%3A%2F%2Fwebcdn.m.qq.com%2Fsp ...

  7. 解决电脑端微信浏览器不支持vue、axios等问题

    网上搜罗了一大圈关于微信不支持vue的问题,大部分都说是版本问题.后来我直接用官网的demo试了下是没问题的,然后把demo的vue.js改为我本地的,结果也是可以的-_-... 最终...我吧vue ...

  8. PC端微信浏览器模拟器

    有部分公众号文章只能使用微信浏览器打开,通过chorme设置ua仍然会被拦截,这时候可以选择下面的工具进行模拟: 微信浏览器模拟器下载地址 亲测可用,注意设置UA: Mozilla/5.0 (Linu ...

  9. 记响应式布局vh/vw单位在安卓端微信浏览器以及UC浏览器的坑

    页面使用vh来控制元素高度的时候,在安卓端浏览器虚拟键盘弹出时,导致视口高度改变,以至于vh的取值改变 // 正常模式下 100vh = document.documentElement.client ...

最新文章

  1. Cannot call sendError() after the response has been committed
  2. [js高手之路]寄生组合式继承的优势
  3. BeetleX使用bootstrap5开发SPA应用
  4. vm中linux物理内存不足解决方案
  5. 2021年Q1移动互联网行业数据研究报告
  6. 利用cookies让sweetalert只出现一次
  7. Hive文件数创建过多的问题
  8. 50-000-040-配置-MAC 安装MySQL my.cnf配置文件
  9. Win11掉帧严重是怎么回事?Win11玩游戏掉帧的解决方法
  10. 柱面投影、拼接视差、球面投影
  11. 天气预报接口使用及示例
  12. KETTLE使用通配符匹配多个文件输入到一张表中
  13. wx.login 和 wx.getUserProfile 同时使用问题
  14. case when 嵌套
  15. 计算机网络基础交换机的基本配置实验报告,计算机网络基础实验报告
  16. jquery vue 替代_vue能代替jquery吗
  17. Java安全(十三) SSM-Spring框架
  18. 华为无线设备配置Mesh业务
  19. JavaEE笔记——设计模式
  20. 运动解剖测试题软件,2015教师招聘体育学科运动解剖学经典题

热门文章

  1. 没想到 Hash 冲突还能这么玩,你的服务中招了吗?
  2. 摩天大楼里的云服务器
  3. 如何利用js实现萤火虫效果
  4. 两角和与差的三角函数公式的证明
  5. 机器学习中的树模型下——集成类树
  6. 计算机考证二级可以考几个证
  7. 虚拟机网络连接图标消失问题
  8. 《视觉SLAM十四讲 第二版》笔记及课后习题(第七讲)
  9. CTU(coding_tree_unit)
  10. Android自定义View--简易画板