何大小成

nuxt · 官网 · 自适应

最近在负责国家物联网标识管理公共服务平台官网 的重构,采用了nuxt.js。那么这次重构除了用nuxt.js,还要做到pc端和移动端的自适应设计。自适应设计暂时想到三种方式:

  1. 不同端(pc和mobile)映射到不同域名,举个例子:pc端访问的是www.baidu.com,换到移动端就改为www.m.baidu.com了。但是,这样就要有两个不同项目,若要维护两个项目也是挺麻烦的。毕竟这只是官网,只是一些元素上变化。而不像微博,知乎变化太大。
  2. css媒体查询@media。我纠结了很久到底要不要这样…结果还是放弃了。其实看起来很美好,其实开发起来是很痛苦了,做不到完美。一个页面可能很多元素需要改动。而且,移动端用的是流动布局,pc端暂时不考虑响应式就好了。
  3. 页面启动前根据ua跳转不同路由,pc端访问的是/about,换到移动端跳去 ‘/m/about’。其实跟第一种方法有点类似,但是动用的资源就一个好了,不需要nginx。

最后,我还是采用了第三种方式去进行。(如果有更好的请在留言区告诉我哦,谢谢)

准备好sass配置

  1. 安装node-sass和sass-loader
  2. 安装nuxt-sass-resources-loader
    之前也说过,怎么把全局变量,函数以及mixins放到全局不需要每个.vue里引入的方法,请参考:这里

根据ua判断给<html>加上属性

判断ua,作为公共方法(写入utils/utils.js)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 判断PC或者mobile
export const pcOrMobile = (u) => {
let browser = { //移动终端浏览器版本信息
trident: u.indexOf('Trident') > -1, //IE内核
presto: u.indexOf('Presto') > -1, //opera内核
webKit: u.indexOf('AppleWebKit') > -1, //苹果、谷歌内核
gecko: u.indexOf('Gecko') > -1 && u.indexOf('KHTML') == -1, //火狐内核
mobile: !!u.match(/AppleWebKit.*Mobile.*/), //是否为移动终端
ios: !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/), //ios终端
android: u.indexOf('Android') > -1 || u.indexOf('Linux') > -1, //android终端或者uc浏览器
iPhone: u.indexOf('iPhone') > -1, //是否为iPhone或者QQHD浏览器
iPad: u.indexOf('iPad') > -1, //是否iPad
webApp: u.indexOf('Safari') == -1 //是否web应该程序,没有头部与底部
};
if (browser.mobile || browser.ios || browser.android || browser.iPhone || browser.iPad) {
return 'mobile'
} else {
return 'pc'
}
}

plugins加上devide.js
这里的目的只是根据ua给html加上属性(mobile还是pc)。或者,到时候如果要求PC端也要做自适应还是可以在此处做文章

1) 在plugins里新建devide.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
(function(doc, win) {
let docEl = doc.documentElement
let resizeEvt = 'orientationchange' in window
? 'orientationchange'
: 'resize'
let recalc = function() {
if (pcOrMobile(window.navigator.userAgent) === 'pc') {
docEl.setAttribute('pc', '')
docEl.removeAttribute('mobile', '')
} else {
docEl.setAttribute('mobile', '')
docEl.removeAttribute('pc', '')
}
}
if (!doc.addEventListener) {
return
}
win.addEventListener(resizeEvt, recalc, false)
doc.addEventListener('DOMContentLoaded', recalc, false)
})(document, window)

如果是移动端,那就<html mobile></html>;否则,是pc端就变成<html pc></html>
2) nuxt.config.js修改

1
2
3
4
5
6
7
8
module.exports={
plugins: [
{
src: '~plugins/rem.js',
ssr: false
}
]
}

移动端:采用vw,vh作为单位

采用的方案就是用凹凸实验室的利用视口单位实现适配布局rem+vw这个方案作为移动端自适应方案。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// rem 单位换算:定为 75px 只是方便运算,750px-75px、640-64px、1080px-108px,如此类推
$vw_fontsize: 75; // iPhone 6尺寸的根元素大小基准值
// 根元素大小使用 vw 单位
$vw_design: 750;

html[mobile] {
font-size: ($vw_fontsize / ($vw_design / 2)) * 100vw;
// 同时,通过Media Queries 限制根元素最大最小值
@media screen and (max-width: 320px) {
font-size: 64px;
}
@media (max-width: 1024px) and (min-width: 540px) {
font-size: 108px;
}
}
@function rem($px) {
@return ($px / $vw_fontsize) * 1rem;
}
// body 也增加最大最小宽度限制,避免默认100%宽度的 block 元素跟随 body 而过大过小

body {
max-width: 540px;
min-width: 320px;
}

html[mobile]这里的目的就明确了,通过rem.js判断

pc端:采用px作为单位

暂时不对pc端做自适应设计

不同端不同布局(Layout)

pc端和移动端是不一样的布局,那么我针对不同的端有不同的布局:

开发移动端页面的时候,只需要在相应的.vue写上layout:mobile即可。

访问主页根据ua跳转

page的文件夹结构是:

移动端的页面放在pages/m文件夹里,所以移动端访问网页的路由是:’/m/…’
那么,如何使得如果是移动端访问就跳转?

index.vue入口里加入:

1
2
3
4
5
6
7
8
9
asyncData({
req,
redirect
}) {
let type = pcOrMobile(req.headers['user-agent'])
if (type === 'mobile') {
redirect('/m')
}
}