移动端开发经验
移动端开发经验
前端移动端开发经验总结
https://www.cnblogs.com/shahramLu/p/6406775.html
本文是对移动端多人协作开发项目一些经验总结
3.简述一下事件穿透,及解决办法。
移动端兼容性处理
https://www.jianshu.com/p/6e058275140c
https://blog.csdn.net/hardgirls/article/details/51722519
当今的手机端,各式各样的手机,屏幕分辨率也是各有不同,为了让页面可以可以兼容各大手机,解决方案如下
设置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进行调整
移动端自适应
正在开发一个APP项目,对于自适应有些体会
在移动端,宽度自适应可以使用百分比来控制,加上flexbox,width: 20%;
但是对于高度无能为力,后来发现大厂(淘宝,网易)推崇rem,这是CSS3新定义的,和传统的px,em不一样,rem是相对于根元素
<html>的font-size来定义的,默认1rem = 16px,如果自定义了font-size
html {
font-size: 12px;
}
这时,1rem = 12px。这样对于高度可以通过rem来设置,不需要px
.section{
width:25%;
height:48px;
background-color: greenyellow;
}
.section{
width:25%;
height:3rem;
background-color: royalblue;
}
发现3rem = 48px,因为没有设置html的font-size
移动端最重要的是设备像素比dpr不同,常用的设计稿是750px,是iPhone6的物理像素,独立像素为375px,所以dpr=2
具体方案参照《使用Flexible实现手淘H5页面的终端适配》
另外一个就是随处可见的border,因为设备像素比不同,我们设置的1px,是设备独立像素,例如iPhone6的Retina屏
设备会使用4个像素点2x2,去显示1个像素点,即1像素border会变成2像素border
在Chrome中输出,发现屏幕是高清屏
可以看出左边border比右边宽,再在iPhone6的屏幕下查看
更清晰的发现右边的边框为1像素,左边的不是
@mixin border-1px($color) {
position: relative;
&:after {
display: block;
position: absolute;
left: 0;
bottom: 0;
width: 100%;
height: 100%;
border: 1px solid $color;
content: ' ';
}
}
@mixin border-1px-two($color) {
position: relative;
&:before {
content: '';
position: absolute;
width: 200%;
height: 200%;
border: 1px solid #000;
transform-origin: 0 0;
transform: scale(0.5, 0.5);
box-sizing: border-box;
}
}
通过缩放才能达到1像素
scope的使用
HTML5 新元素scope,范围样式,已经在团队协作中广泛使用
<style scoped>
个人开发可以在HTML中任何地方使用,限制样式只在元素及子元素生效,在Chrome查看
可以看到,scoped给下面写的样式,均添加了一个[data-v-*]来限制样式作用域,再看一个
在scoped下可以使用任何css样式,包括预处理器的所有特性
webkit内核两行显示省略号
文本限制在一行显示,注意需要直接写在标签上,写在父元素没有效果
1 <section class="section">
2 <p>
3 用text-overflow:ellipsis属性来实现单行文本的溢出显示省略号(…)
4 用text-overflow:ellipsis属性来实现单行文本的溢出显示省略号(…)
5 用text-overflow:ellipsis属性来实现单行文本的溢出显示省略号(…)
6 </p >
7 </section>
1 .section {
2 background-color: #999; // 自定义
3 height:20px; // 自定义
4 overflow: hidden; // 必须写
5 text-overflow: ellipsis; // 必须写
6 white-space: nowrap; // 必须写
7 }
发现没有显示省略号,删除p标签,或者将样式写到p上
在移动端绝大数浏览器都是webkit内核,可以使用私有属性-webkit-line-clamp
来限制显示的行数,还需要结合其他属性才能实现效果
1 .section {
2 background-color: #999; /*自定义*/
3 overflow : hidden;
4 text-overflow: ellipsis;
5 display: -webkit-box; /*必须结合的属性 ,将对象作为弹性伸缩盒子模型显示*/
6 -webkit-line-clamp: 2; /*必须结合的属性 ,用来限制在一个块元素显示的文本的行数*/
7 -webkit-box-orient: vertical; /*必须结合的属性 ,设置或检索伸缩盒对象的子元素的排列方式,
8 vertical:设置伸缩盒对象的子元素从上到下纵向排列*/
9 }
一、移动端开发通用坑
click300ms延迟?
讲道理,现在开发移动端基本是不会有这么一个问题的。但作为移动端以前的经典坑,我这里也拿出来说上一说吧。
移动设备上的web网页是有300ms延迟的,玩玩会造成按钮点击延迟甚至是点击失效。这是由于区分单击事件和双击屏幕缩放的历史原因造成的。但在2014年的Chrome 32版本已经把这个延迟去掉了,so you know。但如果你还是出现了300ms的延迟问题,也是有路子搞定的。
解决方案如下:
fastclick可以解决在手机上点击事件的300ms延迟
zepto的touch模块,tap事件也是为了解决在click的延迟问题
触摸事件的响应顺序为 touchstart –> touchmove –> touchend –> click,也可以通过绑定ontouchstart事件,加快对事件的响应,解决300ms延迟问题
若移动设备兼容性正常的话(IE/Firefox/Safari(IOS 9.3)及以上),只需加上一个meta标签
<meta name="viewport" content="width=device-width">
即把viewport设置成设备的实际像素,那么就不会有这300ms的延迟。
阻止旋转屏幕时自动调整字体大小
移动端开发时,屏幕有竖屏和横屏模式,当屏幕进行旋转时,字体大小则有可能会发生变化,从而影响页面布局的整体样式,为避免此类情况发生,只需设置如下样式即可
* {
-webkit-text-size-adjust: none;
}
修改移动端难看的点击的高亮效果,iOS和安卓下都有效
* {
-webkit-tap-highlight-color: rgba(0,0,0,0);
}
不过这个方法在现在的安卓浏览器下,只能去掉那个橙色的背景色,点击产生的高亮边框还是没有去掉,有待解决!
一个CSS3的属性,加上后,所关联的元素的事件监听都会失效,等于让元素变得“看得见,点不着”。IE到11才开始支持,其他浏览器的当前版本基本都支持。
pointer-events: none;
iOS下取消input在输入的时候英文首字母的默认大写
<input type="text" autocapitalize="none">
禁止 iOS 识别长串数字为电话
<meta name="format-detection" content="telephone=no" />
禁止 iOS 弹出各种操作窗口
-webkit-touch-callout: none;
禁止ios和android用户选中文字
-webkit-user-select: none;
calc的兼容处理
CSS3中的calc变量在iOS6浏览器中必须加-webkit-前缀,目前的FF浏览器已经无需-moz-前缀。 Android浏览器目前仍然不支持calc,所以要在之前增加一个保守尺寸:
div {
width: 95%;
width: -webkit-calc(100% - 50px);
width: calc(100% - 50px);
fixed定位缺陷
iOS下fixed元素容易定位出错,软键盘弹出时,影响fixed元素定位,android下fixed表现要比iOS更好,软键盘弹出时,不会影响fixed元素定位 。iOS4下不支持position:fixed
解决方案: 可用iScroll插件解决这个问题
一些情况下对非可点击元素如(label,span)监听click事件,ios下不会触发
针对此种情况只需要对不触发click事件的那些元素添加一行css代码即可
cursor: pointer;
消除transition闪屏问题
/*设置内嵌的元素在 3D 空间如何呈现:保留 3D*/
-webkit-transform-style: preserve-3d;
/*(设置进行转换的元素的背面在面对用户时是否可见:隐藏)*/
-webkit-backface-visibility: hidden;
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);
iOS系统中文输入法输入英文时,字母之间可能会出现一个六分之一的空格
解决方法:通过正则去除
input的placeholder会出现文本位置偏上的情况
PC端设置line-height等于height能够对齐,而移动端仍然是偏上,解决方案时是设置css
line-height:normal;
往返缓存问题
点击浏览器的回退,有时候不会自动执行js,特别是在mobilesafari中。这与往返缓存(bfcache)有关系。 解决方法 :
window.onunload = function () {};
overflow-x: auto在iOS有兼容问题
解决方法:
-webkit-overflow-scrolling: touch;
https://blog.csdn.net/mm782642353/article/details/82356813
移动端唤起手机app
首先,我们看下安卓的配置文件和Scheme
<activity android:name = ".MainActivity">
<intent-filter>
<action android:name = "android.intent.action.MAIN" />
<category android:name = "android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data android:host="xxx.com" android:scheme="abraham"/>
</intent-filter>
</activity>
重点关<data android:host="xxx.com" android:scheme="abraham"/>,前端就需要根据这个字来唤起app
< a href=" ">打开app</ a>
schema拼接协议的格式:[scheme]://[host]/[path]?[query]
当然ios的也有自己的协议,通常在写唤起app之前需要跟客户端的同事进行对接一下,拿到他们的协议。
注意schema协议要小写,否则会有不能响应的异常!
当然我们可以整合一下代码,把ios的也加进来:
var u = navigator.userAgent;var isAndroid = u.indexOf('Android') > -1 || u.indexOf('Linux') > -1; //android终端或者uc浏览器var isiOS2 = !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/); //ios终端if (isAndroid) {
window.location.href = "安卓提供协议url";
/***打开app的协议,有安卓同事提供***/
window.setTimeout(function() {
window.location.href = '下载的地址';
}, 2000);
} else if (isiOS2) {
window.location.href = "IOS提供协议url";
/***打开app的协议,有ios同事提供***/
window.setTimeout(function() {
window.location.href = '下载的地址';
}, 2000);
} else {
window.location.href = '下载的地址';
}
iOS原始输入法问题
iOS原始输入法,中文输入时,无法触发keyup事件,且keyup.enter事件无论中英文,都无法触发
解决方法:
改用input事件进行监听
将keyup监听替换成值的watch
让使用者安装三方输入法,比如搜狗输入法(不太现实)
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按钮。
vue组件开发
这个点不能算坑,只能算是小技巧分享吧。
业务场景重现:很多时候,在开发项目的时候是需要抽离公共组件和业务组件的。而有些公共组件在全局注册的同时可能还需要拓展成vue的实例方法,通过把它们添加到 Vue.prototype 上实现,方便直接使用js全局调用。拿一个Message组件做例子吧,代码比较简单,就直接上代码了。
1.首先开发好Message.vue文件
<template>
<div class='y-mask-white-dialog' v-show='show'>
<div class='y-message animated zoomIn' >
<span v-html="msg"></span>
</div>
</div>
</template>
<script>
export default {
name: 'yMessage',
props: {
msg: String,
timeout: Number,
callback: Function,
icon: String,
},
data() {
return {
show: true,
};
}
};
</script>
<style lang="stylus" scoped>
.y-mask-white-dialog {
background-color: rgba(0, 0, 0, .4);
position: fixed;
z-index: 999;
bottom: 0;
right: 0;
left: 0;
top: 0;
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-box-pack: center;
-webkit-justify-content: center;
-ms-flex-pack: center;
justify-content: center;
-webkit-box-align: center;
-webkit-align-items: center;
-ms-flex-align: center;
align-items: center;
}
.y-message {
min-width: 2.9rem;
max-width: 5.5rem;
width:100%;
padding: 0.32rem;
font-size: 14px;
text-align: center;
border-radius: 4px;
background :rgba(0,0,0,0.8);
color: #fff;
animation: zoomIn .15s ease forwards;
}
</style>
2.构建Message的Constructor
import Vue from 'vue';
const MsgConstructor = Vue.extend(require('./Message.vue'));
const instance = new MsgConstructor({
// el: document.createElement('div'),
}).$mount(document.createElement('div'));
MsgConstructor.prototype.closeMsg = function () {
const el = instance.$el;
el.parentNode && el.parentNode.removeChild(el);
typeof this.callback === 'function' && this.callback();
};
const Message = (options = {}) => {
instance.msg = options.msg;
instance.timeout = options.timeout || 2000;
instance.icon = options.icon;
instance.callback = options.callback;
document.body.appendChild(instance.$el);
const timer = setTimeout(() => {
clearTimeout(timer);
instance.closeMsg();
}, instance.timeout + 100);
};
export default Message;
3.在main.js里面进行组件注册
import Message from './components/Message';
Vue.component(Message.name, Message)
Vue.prototype.$message = Message
然后你就可以尽情使用Message组件了.
// <y-message msg="test message"><y-message>
// or
this.$message({
msg: 'test message'
// ...
})
巧用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 auto
height 100%
margin auto
}
}
这里我就不上轮播图的代码了,有点小多。
效果图如下
枚举值过滤处理
业务重现:考虑到项目后期会做国际化,前端需要对项目中几乎所有的枚举值进行过滤处理,从而进行展示
接下来就直接讲讲这块吧。既然要过滤,那么首选肯定是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>
时间过滤处理
这点还是属于过滤处理的一个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);
},
}
];
路由权限判定
业务重现:由于不同的用户,可能拥有不同权限,而目前我们的项目是基于微信公众号进行开发的,页面权限这边也是交给了我们前端处理。既然要前端配置权限,那么我们能想到的比较好的方式就是通过配置路由文件,完成权限判定。下面我会列举一小部分代码(以我们的工单列表)进行演示,路由配置代码如下
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权限不足的情况则会如下
使用vue-cli proxyTable进行反向代理,解决跨域问题
开发项目,在前后端联调的时候肯定是会遇上跨域的问题的。很简单,做个反向代理
vue-cli脚手架搭建的工程中,在config/index.js文件中可以利用预留的proxyTable一项,设置地址映射表,如下
proxyTable: {
'/api': {
target: 'http://www.example.com', // your target host
changeOrigin: true, // needed for virtual hosted sites
pathRewrite: {
'^/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))
})
接下来我会结合实际项目抽几个点配合代码进行较为详细的讲解。
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″>
1
除此之外,还有很多点可做优化,进而提升首屏加载速度
2、雪碧图
这个老生常谈了,为了减少图片请求次数,加快页面加载,当然会考虑使用雪碧图。大家这个应该没啥疑问吧。来个小例子,一天,设计小姐姐给了我一张设计稿,稿子如图
然后给了我6张图片,一看,每张图都有6K左右的大小。好嘛,只能自己在线合张雪碧图,不然,太影响页面加载,合完雪碧图顺带在线压缩优化下,然后总大小只有6K。还有一个点,就是尽量使用::before或::after伪类,Sprites中的图片排版可以更紧 ,图片体积更小, HTML更简洁。部分代码如下
<style lang="stylus" scoped>
.chose-house {
height: 86px;
width: 64px;
margin 0 auto
position 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);
});