(转)移动端开发通用坑

1、click300ms延迟?

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

解决方案如下:

1.fastclick可以解决在手机上点击事件的300ms延迟

2.zepto的touch模块,tap事件也是为了解决在click的延迟问题

3.触摸事件的响应顺序为 touchstart --> touchmove --> touchend --> click,也可以通过绑定ontouchstart事件,加快对事件的响应,解决300ms延迟问题

4.若移动设备兼容性正常的话(IE/Firefox/Safari(IOS 9.3)及以上),只需加上一个meta标签

<meta name="viewport" content="width=device-width">

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

2、移动端样式兼容处理

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

1.设置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" />

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

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

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

扫描二维码关注公众号,回复: 6265033 查看本文章
  1.  
    * {
  2.  
    -webkit-text-size-adjust: none;
  3.  
    }

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

  1.  
    * {
  2.  
    -webkit-tap-highlight-color: rgba( 0,0,0,0);
  3.  
    }

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

一个CSS3的属性,加上后,所关联的元素的事件监听都会失效,等于让元素变得“看得见,点不着”。IE到11才开始支持,其他浏览器的当前版本基本都支持。详细介绍见这

pointer-events: none;

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

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

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

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

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

-webkit-touch-callout: none;

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

-webkit-user-select: none;

9、calc的兼容处理nainaitea.com

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

  1.  
    div {
  2.  
    width: 95%;
  3.  
    width: -webkit-calc( 100% - 50px);
  4.  
    width: calc( 100% - 50px);
  5.  
    }

10、fixed定位缺陷

  1.  
    iOS下 fixed元素容易定位出错,软键盘弹出时,影响fixed元素定位,android下fixed表现要比iOS更好,软键盘弹出时,不会影响fixed元素定位 。iOS4下不支持position:fixed
  2.  
     
  3.  
    解决方案: 可用iScroll插件解决这个问题

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

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

cursor: pointer;

12、消除transition闪屏问题

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

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

解决方法:

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

  1.  
    -webkit-transform: translate3d( 0, 0, 0);
  2.  
    -moz-transform: translate3d( 0, 0, 0);
  3.  
    -ms-transform: translate3d( 0, 0, 0);
  4.  
    transform: translate3d( 0, 0, 0);

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

解决方法:通过正则去除

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

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

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

line-height:normal;

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

解决方法如下:

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

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

17、往返缓存问题

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

window.onunload = function () {};

18、overflow-x: auto在iOS有兼容问题

解决方法:

-webkit-overflow-scrolling: touch;

  

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

1、iOS原始输入法问题

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

解决方法:

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

2、input元素失焦问题

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

  1.  
    <template>
  2.  
    <div class="y-search" :style="styles" :clear="clear">
  3.  
    <form action= "#" onsubmit="return false;">
  4.  
    <input type= "search"
  5.  
    class="y-search-input"
  6.  
    ref="search"
  7.  
    v-model=‘model‘
  8.  
    :placeholder= "placeholder"
  9.  
    @input= "searchInputFn"
  10.  
    @keyup.enter= "searchEnterFn"
  11.  
    @foucs= "searchFocusFn"
  12.  
    @blur= "searchBlurFn"
  13.  
    />
  14.  
    <y-icons class="search-icon" name="search" size="14"></y-icons>
  15.  
    </form>
  16.  
    <div v- if="showClose" @click="closeFn">
  17.  
    <y-icons class="close-icon" name=‘close‘ size=‘12‘></y-icons>
  18.  
    </div>
  19.  
    </div>
  20.  
    </template>

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

  1.  
    searchEnterFn (e) {
  2.  
    document.getElementsByClassName(‘y-search-input‘)[ 0].blur()
  3.  
    // dosomething yourself
  4.  
    }

  

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

3、vue组件开发

这个点不能算坑,只能算是小技巧分享吧。

业务场景重现:很多时候,在开发项目的时候是需要抽离公共组件和业务组件的。而有些公共组件在全局注册的同时可能还需要拓展成vue的实例方法,通过把它们添加到 Vue.prototype 上实现,方便直接使用js全局调用。拿一个Message组件做例子吧,代码比较简单,就直接上代码了。

1.首先开发好Message.vue文件。

  1.  
    <template>
  2.  
    <div class=‘y-mask-white-dialog‘ v-show=‘show‘>
  3.  
    <div class=‘y-message animated zoomIn‘ >
  4.  
    <span v-html= "msg"></span>
  5.  
    </div>
  6.  
    </div>
  7.  
    </template>
  8.  
     
  9.  
    <script>
  10.  
    export default {
  11.  
    name: ‘yMessage‘,
  12.  
    props: {
  13.  
    msg: String,
  14.  
    timeout: Number,
  15.  
    callback: Function,
  16.  
    icon: String,
  17.  
    },
  18.  
    data() {
  19.  
    return {
  20.  
    show: true,
  21.  
    };
  22.  
    }
  23.  
    };
  24.  
    </script>
  25.  
     
  26.  
    <style lang= "stylus" scoped>
  27.  
    .y-mask-white-dialog {
  28.  
    outline: 0px; margin: 0px; padding: 0px; color: rgb(152, 104, 1); overflow-wrap: break-word;">0, 0, 0, .4);
  29.  
    position: fixed;
  30.  
    z-index: 999;
  31.  
    bottom: 0;
  32.  
    right: 0;
  33.  
    left: 0;
  34.  
    top: 0;
  35.  
    display: -webkit-box;
  36.  
    display: -webkit-flex;
  37.  
    display: -ms-flexbox;
  38.  
    display: flex;
  39.  
    -webkit-box-pack: center;
  40.  
    -webkit-justify-content: center;
  41.  
    -ms-flex-pack: center;
  42.  
    justify-content: center;
  43.  
    -webkit-box-align: center;
  44.  
    -webkit-align-items: center;
  45.  
    -ms-flex-align: center;
  46.  
    align-items: center;
  47.  
    }
  48.  
    .y-message {
  49.  
    min-width: 2.9rem;
  50.  
    max-width: 5.5rem;
  51.  
    width: 100%;
  52.  
    padding: 0.32rem;
  53.  
    font-size: 14px;
  54.  
    text-align: center;
  55.  
    border-radius: 4px;
  56.  
    background :rgba( 0,0,0,0.8);
  57.  
    color: #fff;
  58.  
    animation: zoomIn .15s ease forwards;
  59.  
    }
  60.  
    </style>

2.构建Message的Constructor

  1.  
    import Vue from ‘vue‘;
  2.  
     
  3.  
    const MsgConstructor = Vue.extend(require(‘./Message.vue‘));
  4.  
     
  5.  
    const instance = new MsgConstructor({
  6.  
    // el: document.createElement(‘div‘),
  7.  
    }).$mount(document.createElement(‘div‘));
  8.  
     
  9.  
    MsgConstructor.prototype.closeMsg = function () {
  10.  
    const el = instance.$el;
  11.  
    el.parentNode && el.parentNode.removeChild(el);
  12.  
    typeof this.callback === ‘function‘ && this.callback();
  13.  
    };
  14.  
     
  15.  
    const Message = (options = {}) => {
  16.  
    instance.msg = options.msg;
  17.  
    instance.timeout = options.timeout || 2000;
  18.  
    instance.icon = options.icon;
  19.  
    instance.callback = options.callback;
  20.  
    document.body.appendChild(instance.$el);
  21.  
     
  22.  
    const timer = setTimeout(() => {
  23.  
    clearTimeout(timer);
  24.  
    instance.closeMsg();
  25.  
    }, instance.timeout + 100);
  26.  
    };
  27.  
     
  28.  
    export default Message;

3.在main.js里面进行组件注册

  1.  
    import Message from ‘./components/Message‘;
  2.  
     
  3.  
    Vue.component(Message.name, Message)
  4.  
    Vue.prototype.$message = Message

然后你就可以尽情使用Message组件了.

  1.  
    this.$message({
  2.  
    msg: ‘test message‘
  3.  
    // ...
  4.  
    })

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

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

  1.  
    <div class="parent">
  2.  
    <img :src= "imgSrc" >
  3.  
    </div>
  4.  
     
  5.  
    <style lang= "stylus" scoped>
  6.  
    .parent {
  7.  
    width: 100px;
  8.  
    height: 100px;
  9.  
    display: flex;
  10.  
    align-items: center;
  11.  
     
  12.  
    img {
  13.  
    width : 100%;
  14.  
    height: auto;
  15.  
    }
  16.  
    }
  17.  
    </style>

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

  1.  
    @media (orientation: landscape) {
  2.  
    img {
  3.  
    width auto
  4.  
    height 100%
  5.  
    margin auto
  6.  
    }
  7.  
    }

  

5、枚举值过滤处理

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

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

  1.  
    // 配置文件
  2.  
    export default {
  3.  
    env: (process.env.NODE_ENV === ‘development‘ ? require(‘./env/dev‘) : require(‘./env/pro‘)),
  4.  
    headShow: false,
  5.  
    lng: ‘zh‘,
  6.  
    };

 枚举代码如下

  1.  
    // 获取语言环境
  2.  
    import config from ‘../config/index‘;
  3.  
     
  4.  
    const {lng} = config;
  5.  
    // 账户类型
  6.  
    const type = {
  7.  
    zh: {
  8.  
    1: ‘银行‘,
  9.  
    2: ‘支付宝‘,
  10.  
    3: ‘微信支付‘,
  11.  
    },
  12.  
    en: {
  13.  
    1: ‘bank_type‘,
  14.  
    2: ‘alipay_type‘,
  15.  
    3: ‘wxpay_type‘,
  16.  
    }
  17.  
    }
  18.  
    export default type[lng];

枚举注册代码分别如下

  1.  
    import accountType from ‘./accountType‘; // 账户类型
  2.  
     
  3.  
    const factory = {
  4.  
    accountType( value) {
  5.  
    if (value === -1) {
  6.  
    return ‘请选择账户类型‘;
  7.  
    }
  8.  
    return accountType[value] ? accountType[value] : ‘请选择账户类型‘;
  9.  
    }
  10.  
    }
  11.  
    const filter = [
  12.  
    {
  13.  
    name: ‘formatEnum‘, // 过滤类型
  14.  
    filter: function( value, type, status) {
  15.  
    return factory[type](value, status);
  16.  
    }
  17.  
    }
  18.  
    ];
  19.  
    export default {
  20.  
    filter
  21.  
    };
  22.  
    // filter
  23.  
    import baseFilter from ‘./filter/index‘;
  24.  
     
  25.  
    const filters = [
  26.  
    ...baseFilter.filter
  27.  
    ];
  28.  
    filters.map(f => {
  29.  
    Vue.filter(f.name, f.filter);
  30.  
    return ‘‘;
  31.  
    });

接下来就可以轻松使用啦

  1.  
    <li>
  2.  
    <label支付类型</label>
  3.  
    <span>
  4.  
    {{info.account_type | formatEnum(‘accountType‘)}}
  5.  
    </span>
  6.  
    </li>

6、时间过滤处理

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

时间过滤代码如下

  1.  
    const filter = [
  2.  
    {
  3.  
    name: ‘formatEnum‘, // 过滤类型
  4.  
    filter: function( value, type, status) {
  5.  
    return factory[type](value, status);
  6.  
    }
  7.  
    },
  8.  
    {
  9.  
    name: ‘formatDate‘, // 日期
  10.  
    filter: function( value, format = ‘yyyy-MM-dd‘) {
  11.  
    if (!value || value === ‘‘) return ‘‘;
  12.  
    let v = value;
  13.  
    if (!isNaN(value)) {
  14.  
    v = + value * 1000;
  15.  
    }
  16.  
    const newDate = new Date(v);
  17.  
    return newDate.Format(format);
  18.  
    },
  19.  
    }
  20.  
    ];

  

7、路由权限判定

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

  1.  
    const getWorkOrder = pageName => resolve => require([‘../pages/WorkOrder‘], pages => resolve(pages[pageName]))
  2.  
     
  3.  
    let routers = [];
  4.  
    routers = [
  5.  
    {
  6.  
    path: ‘/workorder‘,
  7.  
    name: ‘workorder‘,
  8.  
    component: room,
  9.  
    children: [
  10.  
    {
  11.  
    path: ‘list‘, // 管家端工单列表
  12.  
    name: ‘list‘,
  13.  
    rule: 3,
  14.  
    component: getWorkOrder(‘WorkOrderList‘) //WorkOrder,
  15.  
    },
  16.  
    {
  17.  
    path: ‘managerList‘, // 店长端工单列表
  18.  
    name: ‘managerList‘,
  19.  
    rule: 6,
  20.  
    component: getWorkOrder(‘ManagerWorkOrder‘) // WorkOrder,
  21.  
    },
  22.  
    ]
  23.  
    }
  24.  
    ]

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

  1.  
    import Vue from ‘vue‘;
  2.  
    import Store from ‘store‘;
  3.  
    import Router from ‘vue-router‘;
  4.  
     
  5.  
    import routers from ‘./router.config‘;
  6.  
    Vue.use(Router);
  7.  
     
  8.  
    // 遍历路由名称以及权限
  9.  
    let arr = {};
  10.  
    const routeName = function (router) {
  11.  
    if (!router) return false;
  12.  
    router.forEach((v) => {
  13.  
    arr[v.name] = v.rule;
  14.  
    routeName(v.children);
  15.  
    })
  16.  
    }
  17.  
    routeName(routers);
  18.  
     
  19.  
    const RouterModel = new Router({
  20.  
    mode: ‘history‘,
  21.  
    routes: routers,
  22.  
    });
  23.  
     
  24.  
    // 路由钩子,进入路由之前判断
  25.  
    RouterModel.beforeEach((to, from, next) => {
  26.  
    // 处理query 参数,传入到 jumpUrl,便于登录后跳转到对应页面
  27.  
    let qu = Object.entries(to.query);
  28.  
    if (qu.length > 0) {
  29.  
    qu = qu.map((item, index) => {
  30.  
    return item.join(‘=‘);
  31.  
    })
  32.  
    }
  33.  
    if (arr[to.name]) {
  34.  
    // 如果有权限需要
  35.  
    const userInfo = Store.get(‘yu_info‘);
  36.  
    const cookie = Vue.prototype.$util.getCookie(‘X-Auth-Token‘);
  37.  
    const userId = Vue.prototype.$util.getCookie(‘userid‘);
  38.  
    if (userInfo && cookie && +userId > 0) {
  39.  
    next();
  40.  
    } else {
  41.  
    // 未登录,跳转登录
  42.  
    let param = `jumpUrl=${to.path}`;
  43.  
    if (qu.length > 0) {
  44.  
    param += `&${qu. join("&")}`;
  45.  
    }
  46.  
    if (arr[to.name] && !to.query.rule) {
  47.  
    param += `&rule=${arr[to.name]}`;
  48.  
    }
  49.  
    window.location.href = `/login?${param}`;
  50.  
    }
  51.  
    } else {
  52.  
    // 如果不需要权限放行
  53.  
    next();
  54.  
    }
  55.  
    })
  56.  
     
  57.  
    export default RouterModel;

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

  1.  
     
  2.  
    getCode() {
  3.  
    // 定位到微信授权,若是不需要授权可以在此处处理
  4.  
    let query = this.$route.query;
  5.  
    let param = `jumpUrl=${query.jumpUrl || ‘/home‘}`;
  6.  
    let path = window.location.origin;
  7.  
    // 登录角色处理
  8.  
    let cfg = api[query.rule ? query.rule : 1];
  9.  
    if (query.rule) {
  10.  
    param += `&rule=${query.rule}`;
  11.  
    }
  12.  
     
  13.  
    let redirect_url = encodeURIComponent(`${path}/login?${param}`);
  14.  
    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`;
  15.  
    if (query.rule === 3) {
  16.  
    url += ‘&agentid= 1000004‘;
  17.  
    }
  18.  
    location.replace = url;
  19.  
    }
  20.  
     

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

技术分享

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

技术分享

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

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

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

  1.  
    proxyTable: {
  2.  
    ‘/api‘: {
  3.  
    target: ‘http: //www.example.com‘, // your target host
  4.  
    changeOrigin: true, // needed for virtual hosted sites
  5.  
    pathRewrite: {
  6.  
    ‘^/api‘: ‘‘ // rewrite path
  7.  
    }
  8.  
    }
  9.  
    }

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

  1.  
    // proxy api requests
  2.  
    Object.keys(proxyTable).forEach(function (context) {
  3.  
    var options = proxyTable[context]
  4.  
    if (typeof options === ‘string‘) {
  5.  
    options = { target: options }
  6.  
    }
  7.  
    app.use(proxyMiddleware(options.filter || context, options))
  8.  
    })

http-proxy-middleware地址

三、移动端开发性能优化

技术分享

1、首屏渲染优化

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

  • 减少资源请求次数
  • 加载时使用过渡样式,防止用户网络太差影响对首页的体验
  • 图片使用懒加载,这一part,我们目前项目中使用的vue的三方插件vue-lazyload,大致使用方法如下
  1.  
    // 全局注册 import VueLazyload from ‘vue-lazyload‘;
  2.  
     
  3.  
    Vue.use(VueLazyload, {
  4.  
    error: require(‘./assets/close.svg‘),
  5.  
    loading: require(‘./assets/loading.svg‘),
  6.  
    attempt: 1,
  7.  
    });
  8.  
     
  9.  
    // 使用
  10.  
    <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、雪碧图

这个老生常谈了,为了减少图片请求次数,加快页面加载,当然会考虑使用雪碧图。尽量使用::before或::after伪类,Sprites中的图片排版可以更紧 ,图片体积更小, HTML更简洁。

  1.  
    <style lang= "stylus" scoped>
  2.  
    .chose-house {
  3.  
    height: 86px;
  4.  
    width: 64px;
  5.  
    margin 0 auto
  6.  
    position relative
  7.  
    &::before {
  8.  
    content: ‘\ 20‘;
  9.  
    height: 100%;
  10.  
    width: 100%;
  11.  
    position: absolute;
  12.  
    left: 0;
  13.  
    top: 0;
  14.  
    background: url(‘../../assets/sprite-min.png‘) 0px 0px no-repeat;
  15.  
    }
  16.  
    }
  17.  
    </style>

3、路由懒加载

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

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

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

再将组件按组分块,如

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

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

  1.  
    const getWorkOrder = pageName => resolve => require([‘../pages/WorkOrder‘], pages => resolve(pages[pageName]))
  2.  
     
  3.  
    let routers = [];
  4.  
    routers = [
  5.  
    {
  6.  
    path: ‘/workorder‘,
  7.  
    name: ‘workorder‘,
  8.  
    component: room,
  9.  
    children: [
  10.  
    {
  11.  
    path: ‘list‘, // 管家端工单列表
  12.  
    name: ‘list‘,
  13.  
    rule: 3,
  14.  
    component: getWorkOrder(‘WorkOrderList‘) //WorkOrder,
  15.  
    },
  16.  
    {
  17.  
    path: ‘managerList‘, // 店长端工单列表
  18.  
    name: ‘managerList‘,
  19.  
    rule: 6,
  20.  
    component: getWorkOrder(‘ManagerWorkOrder‘) // WorkOrder,
  21.  
    },
  22.  
    ]
  23.  
    }
  24.  
    ]

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

4、全局组件按需注册

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

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

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

  1.  
    exports.Foo = require(‘./Foo.vue‘);
  2.  
    exports.Bar = require(‘./Bar.vue‘);
  3.  
    exports.Baz = require(‘./Baz.vue‘);

在main.js中进行注册

  1.  
    const components = [
  2.  
    require(‘./components/ base‘).Foo,
  3.  
    require(‘./components/ base‘).Bar,
  4.  
    require(‘./components/ base‘).Baz,
  5.  
    ];
  6.  
     
  7.  
    components.map(component => {
  8.  
    Vue.component(component.name, component);
  9.  
    });

  



 

 

hybird应用开发的坑:

1:ios状态栏与页面内容重叠(webview中),如果是在微信端的网页,可以忽略这个坑。

解决方法:判断设备类型,如果是ios则加入独有的样式:一般状态栏的高度是20px

  1.  
    var u = navigator.userAgent, app = navigator.appVersion;
  2.  
    var isiOS = !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/); //ios终端
  3.  
    if(isiOS){
  4.  
    $( "body").addClass("uh_ios7");
  5.  
    }

样式文件下加这段:

  1.  
    .uh_ios7 .uh,.uh_ios7{
  2.  
    padding: 20px 0 0;
  3.  
    }

3:当页面输入框获取焦点的时候,ios页面滚动导致头部与状态栏重叠:

首先我们下载插件: 传送门

cordova plugin add ionic-plugin-keyboard.

 然后在app.js中加入代码:

  1.  
    $ionicPlatform.ready(function () {
  2.  
    if (window.cordova && window.cordova.plugins.Keyboard) {
  3.  
    window.cordova.plugins.Keyboard.hideKeyboardAccessoryBar( false);
  4.  
    if (window.ionic.Platform.isIOS()) {
  5.  
    window.cordova.plugins.Keyboard.disableScroll( true);
  6.  
    }
  7.  
    }
  8.  
    });

注意:在ios上$ionicPlatform.ready可能进不去————解决办法就是:

将cordova.js放在页面最底部引入!!!!fuck!!

4:ios上如何让绝对定位在页面底部的输入框,随键盘的出现而上移(仅限网页)?

利用dom方法:scrollintoView()。

如果滚动页面也是DOM没有解决的一个问题。为了解决这个问题,浏览器实现了一下方法,以方便开发人员如何更好的控制页面的滚动。在各种专有方法中,HTML5选择了scrollIntoView()作为标准方法。scrollIntoView()可以在所有的HTML元素上调用,通过滚动浏览器窗口或某个容器元素,调用元素就可以出现在视窗中。如果给该方法传入true作为参数,或者不传入任何参数,那么窗口滚动之后会让调动元素顶部和视窗顶部尽可能齐平。如果传入false作为参数,调用元素会尽可能全部出现在视口中(可能的话,调用元素的底部会与视口的顶部齐平。)不过顶部不一定齐平.

例子:document.querySelector(".pinlun_input").scrollIntoView(false)    //这是js方法,不要用jquery选择器执行此方法

猜你喜欢

转载自www.cnblogs.com/ling-du/p/10908659.html