没错,我用Vue写了一个H5项目,来看下我踩坑记录吧。


1、按需引入

在开发过程中,会遇到很多五花八门的库。其实这些库中有很多功能/模块是用不到的,所以,这里推荐按需引入:

import { Slider } from 'element-ui';

Vue.use(Slider);
  • 1
  • 2
  • 3

像这样,如果只用到滑条,只需引入Slider,并挂载到Vue实例。

2、全局样式抽离

Css样式在前端开发中是绕不开的话题,以Vue开发为例,每个.vue文件都有自己的局部样式scoped,但是全局性的样式可以抽离到一个统一的文件(main.css),大概有以下四种情况:

  • 项目中的特有颜色(其他类比),它会在不同的地方出现
  • 全局的组件样式,比如对滚动条颜色的控制
  • 对一些引用的公共组件的定制化样式
  • 单个维度的样式,比如.fl{ float: left }

然后样式文件在项目入口引入:

import 'assets/css/main.css';
  • 1

3、统一的页面入口

用Vue开发的话,如果配置好路由,其实页面之间大可以独立运行。但是项目越来越复杂,交互越多,就更需要一个统一的入口,这样可以统一控制事件监听、处理公共组件(比如Toast)等等。所以,咱们需要一个App.vue,代码如下:

<template>
    <div class="page">
        <router-view class="page-content"></router-view>
    </div>
</template>
<script>
export default {
    name: 'app',
    data(){
        return {
            // TODO
        };
    },
};
</script>

<style lang="scss" scoped>

</style>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

然后,在Vue实例化的时候把它作为选项传入:

import App from 'modules/App.vue';
new Vue({
    router,
    ...App
}).$mount(`#app-wrapper`);
  • 1
  • 2
  • 3
  • 4
  • 5

最后,页面的跳转都会在App.vue内,一切尽在掌握。

4、缓存

听到业务需求说要做持久化我是懵逼的,不过后来理解他们的意思就是做个缓存,那就简单了,哈哈。Vue有提供keep-alive组件:

<template>
    <div class="page">
         <keep-alive>
            <router-view class="page-content"></router-view>
        </keep-alive>
    </div>
</template>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

在上一节的基础上,加上这个组件包裹它就行了。原理就是它会缓存不活动的组件,而不是销毁它。详情可以参见 keep-alive api,官方有详细的解释。

5、监听移动设备的横屏事件

如果是用RN开发,可以调用接口来监听横屏事件,H5的话,Js有没有接口可以给你调用,但是可以监听事件,通过监听orientationchange事件,可以监听横屏动作,然后通过Orientation来获取当前角度:

window.addEventListener( "orientationchange", () => {
    let angle = window.orientation;
    if(angle % 180 != 0){
        // TODO
    } else {
        // TODO
    }
    // TODO
}, false);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

根据上一节说的App.vue,这个监听事件就可以放在其中,然后向其他组件广播。

6、不同组件间通信

那么,如何向其他组件广播?如果是父子,子父这种的,都好说。但是,如果是多层级的组件间通信就不好处理了,这里推荐一种网上广为流传的方法,借用Vue实例,把它作为中间方,在各组件中注册或者监听事件。直接看代码:

// inner.js
import Vue from 'vue';

const bus = new Vue();

export {bus};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

在inner.js中,new 一个Vue实例,然后,可以这样监听事件:

import {bus} from 'common/utils/inner';

bus.$on('my_event', (bool) => {
    // TODO
});
  • 1
  • 2
  • 3
  • 4
  • 5

广播事件:

import {bus} from 'common/utils/inner';

 bus.$emit('my_event', {});
  • 1
  • 2
  • 3

这样一来,就不用管什么层级关系了,都是广播的对象。

7、简单实现Dom拖动

如果不想引用其他库的话,可以自己实现一个移动的Dom,原理就是监听touchmove事件,然后改变它的top/left值:

document.getElementById("toolbar").addEventListener('touchmove', (e) => {
    e.stopPropagation();
    e.preventDefault();
    let y = e.touches[0].clientY;
    let height = window.screen.height;
    if(y > height) {
        y = height;
    } else if (y <  0) {
        y = 0;
    }
    document.getElementById("toolbar").style.top = y + "px";
});
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

不依赖任何插件,达到手指拖动toolbar的效果(这里只是让toolbar在Y轴上拖动,所以只改了它的top值)。注意要把冒泡和默认事件禁止掉,不然会影响其他模块。

8、禁止页面被拖动

H5开发会有很多问题,有些时候客户想拖动的只是某个区域,但是整个页面都会随之拖动,那就把它禁了吧,很简单:

document.getElementById("page").addEventListener('touchmove', function(e) { 
    e.preventDefault();
}, {passive: false});
  • 1
  • 2
  • 3

对于Vue页面来说,把它的顶部Dom禁掉就可以了,这样页面就不会有拖动的效果。

9、Ios设备下的特定样式

通常,H5开发都会遇到适配问题,特别是Iphone下,同一套样式Iphone和安卓下效果的就是会有区别。所以,我们需要判断Iphone,并给它配置特定样式,代码如下:

const isIos = () => {
    var ua = navigator.userAgent.toLowerCase();
    if (/iphone|ipad|ipod/g.test(ua)) {
        return true;
    } else {
        return false;
    }
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

其实原理就是通过UserAgent去判断这个设备是否是Ios设备,如果是,就把相应的样式引用进来,如下:

if(isIos()) { //是ios系统
    require('assets/css/ios.scss');
}
  • 1
  • 2
  • 3

这样就能达到根据设备配置指定样式。

10、调用引用组件的内部方法

在Vue项目已经组件化之后,经常会面临一个很常见的问题,调用组件的内部方法。其实很简单,通过Ref就可以实现:

<my-comp  ref="myRef"> </my-comp>
  • 1

在给引用的组件加上ref之后,在代码中去调用就行了。

this.$refs.myRef.fun();
  • 1

这样就不用去传Props触发了。

11、下载文件

这个功能其实涉及到前后端的配合,如果你想下载一个文件,首先需要这个文件存在,或者是先生成,然后再获取路径下载。这是比较常规的方式了。以Excel文件为例,后台要根据业务生成Excel文件:

static async createDownloadFile(data) {
    try {
        let xls = json2xls(data);
        let fileName = `file.xlsx`;
        await fs.writeFileSync(`./dist/${fileName}`, xls, 'binary');
        return fileName;
    } catch (err) {
        logger.error(`createDownloadFile error is : ${err && err.message || ''}`);
        return;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

nodejs实现一个Excel文件下载就是这样,把文件放到服务器指定目录,将文件名称返回到前端,前端去下载。

<a  :href="downloadUri" download >保存到本地</a>
  • 1

downloadUri就是拼接好的文件路径,然后别忘记加上download属性,这个属性在移动端大部分浏览器内核是支持的,但是,IE浏览器不支持(Safari浏览器也不支持,但是实测是可以下载的),没关系,它是移动端,哈哈。

12、动画效果

有些时候,整个项目交互没有点动画过渡会显的很沉重,所以,还是加点动画吧。手写吗?我知道要定义keyframes,然后设置animation之类的,但是这个东西我还是推荐使用一个库: animation. 非常轻量,就是一个css文件。使用的时候也很简单:

<div class="animated fadeOutDown" > </div>
  • 1

像这样写样式就可以了。

13、表格

什么,要加表格?还是可以固定列,自定义的那种?我反手就是Element-ui表格,哈哈,完成。


巨坑啊,


Element-ui并不适合在移动端用,前期适配完之后,发现非常卡顿,最后发现是它的数据结构的问题,可折叠表格的数据结构就是子母嵌套的,数据量一上来,渲染过程就会页面卡死。不推荐。


这里推荐一个小众的组件: vue-easytable,功能都有主要是不卡,然后,把数据结构换成平级的,层级用样式实现。大概就是这个意思:

[
  {
    id: -1,
    children: [
        {
            id: -1.1,
        }
    ]
  },
  {
    id: 2,
  }
 ]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

换成这样:

[
 {
   id: -1,
 },
 {
   id: -1.1,
 },
 {
   id: 2,
 }
]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

通过自定义属性来设置样式,达到不同层级缩进效果。

最后

今天我看到鱿鱼须在VueConf的演讲了,Vue3.0用的是Typescript写的,想想微软还是强大,这种类Java的语言也能被他搞的这么火,吓得我赶紧去看下Typescript。前端变化真快~