【项目记录】Vue H5适配/vue中Axios的封装

3,370 阅读4分钟

项目场景

已有PC非后台、资讯介绍类项目,技术栈Vue、Nuxt。

现在业务上想添加移动端入口,将PC整改为简洁版的H5

两种解决方案:

  • 在原有PC项目上加页面

    • 优点:可复用服务端接口,静态资源等

    • 缺点:移动端需做适配,代码上不太符合规范

  • 新建项目

    • 优点:可完全当作H5来做
    • 缺点:不可复用服务端接口,静态资源等,工作量比前者大

疑问:正确处理方式是??欢迎各位给出见解~~~

经过商榷,我们选择了新建项目


基于Vue H5开发(仅个人记录)

1. 使用vue-cli初始化项目:vue init webpack

2. 移动端适配:

使用手淘flexible方案

npm install lib-flexible --save   
删除index.html中
<meta name="viewport" content="width=device-width,initial-scale=1.0">
因为lib-flexible会自动插入,如果写了,会用默认的

npm install px2rem-loader --save-dev
在build/utils.js文件找到cssLoader 方法下添加如下代码
const cssLoader = {
    loader: 'css-loader',
    options: {
      sourceMap: options.sourceMap,
      importLoader: 5 // 在加载cssLoader之前加载的loader个数
    }
}
//添加如下代码
const px2remLoader = {
    loader: 'px2rem-loader',
    options: {
      emUnit: 75 // 设计稿的1/10
    }
}
修改 generateLoaders 方法
function generateLoaders(loader, loaderOptions) {
    const loaders = options.usePostCSS ? [cssLoader, postcssLoader, px2remLoader] : [cssLoader, px2remLoader]
    if (loader) {
      loaders.push({
        loader: loader + '-loader',
        options: Object.assign({}, loaderOptions, {
          sourceMap: options.sourceMap
        })
    })
}

刷新,打开控制台可以看到代码中的px已经被转成了rem

字体需要用px

在iPhone3G和iPhone4的Retina屏下面,希望看到的文本字号是相同的。也就是说,我们不希望文本在Retina屏幕下变小,另外,我们希望在大屏手机上看到更多文本,以及,现在绝大多数的字体文件都自带一些点阵尺寸,通常是16px和24px,所以我们不希望出现13px和15px这样的奇葩尺寸。

如此一来,就决定了在制作H5的页面中,rem并不适合用到段落文本上。所以在Flexible整个适配方案中,考虑文本还是使用px作为单位。只不过使用[data-dpr]属性来区分不同dpr下的文本字号大小。

定制一个font-dpr()Sass混合宏

@mixin font-dpr($font-size){
    font-size: $font-size;

    [data-dpr="2"] & {
        font-size: $font-size * 2;
    }

    [data-dpr="3"] & {
        font-size: $font-size * 3;
    }
}

在main.js引入

import './assets/css/common.scss'

在页面组件使用

@include font-dpr(18px);

为什么不用px2rem-loader实现字体px

Vue 在<style scoped lang="scss">

font-size: 28px; /*px*/
border: 1px solid #ddd; /*no*/
不生效,依旧转为rem

猜想是因为scss将诸事注销导致

在<style>默认的css中会生效

3. 封装axios,统一接口管理

新建data文件夹,http.js 用来封装axios,api.js 用来统一管理接口

http.js

import axios from 'axios';
import qs from 'qs';
import {Toast} from "vant";

//响应时间
axios.defaults.timeout = 5000;
//配置请求头
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=UTF-8';

// let baseUrl="http://localhost:8081/api";
let baseUrl="";

//POST传参序列化(添加请求拦截器)
axios.interceptors.request.use((config) => {
  //在发送请求之前做某件事
  if(config.method  === 'post'){
    config.data = qs.stringify(config.data);
  }
  return config;
},(error) =>{
  Toast('错误的传参');
  return Promise.reject(error);
});


//返回状态判断(添加响应拦截器)
axios.interceptors.response.use((res) =>{
  //对响应数据做些事
  if(!res.data.success){
    return Promise.resolve(res);
  }
  return res;
}, (error) => {
  return Promise.reject(error);
});

//返回一个Promise(发送post请求)
export function fetchPost(url, params) {
  return new Promise((resolve, reject) => {
    axios.post(baseUrl+url, params)
      .then(response => {
        resolve(response.data);
      }, err => {
        reject(err);
      })
      .catch((error) => {
        reject(error)
      })
  })
}

//返回一个Promise(发送get请求)
export function fetchGet(url) {
  return new Promise((resolve, reject) => {
    axios.get(baseUrl+url)
      .then(response => {
        resolve(response.data)
      }, err => {
        reject(err)
      })
      .catch((error) => {
        reject(error)
      })
  })
}
export default {
  fetchPost,
  fetchGet,
}

api.js

import { fetchGet, fetchPost } from "./http";

/**
 * 获取something
 */
export const getSomething = () => {
  return fetchGet("/getSomething");
};

export default {
    getSomething
}

*.vue使用

 import Api from "../data/api";
  export default {
    name: 'Index',
    data () {
      return {

      }
    },
    mounted() {
      Api.getStudentList().then(res => {
          console.log(res)
      })
    }
  }

4. reset css

App.vue

<style>
  #app {
    margin: 0;
    overflow: hidden;
  }
  html {
    -webkit-text-size-adjust: none;
    -ms-text-size-adjust: none;
    font-family: "黑体";
  }
  input[type="submit"],input[type="reset"],input[type="button"],input:focus,button:focus,select:focus,textarea:focus{
    outline: none;
  }
  input{
    font-family: "黑体";
    -webkit-appearance:none;
    resize: none; border-radius: 0;
  }
  body,div,ul,li,ol,h1,h2,h3,h4,h5,h6,input,textarea,select,p,dl,dt,dd,a,img,button,form,table,th,tr,td,tbody,article,
  aside, details,figcaption,figure,footer,header,hgroup, menu,nav,section{
    -webkit-tap-highlight-color:rgba(0, 0, 0, 0);
  }
  article, aside, details,figcaption,figure,footer,header,hgroup, menu,nav,section {
    display: block;
  }
  img {
    max-width: 100%;
    height: auto;
    width:auto\9;
    -ms-interpolation-mode:bicubic;
  }
  body,div,ul,li,ol,h1,h2,h3,h4,h5,h6,input,textarea,select,p,dl,dt,dd,a,img,button,form,table,th,tr,td,tbody,article,
  aside, details,figcaption,figure,footer,header,hgroup, menu,nav,section{
    margin:0;
    padding:0;
    border:none;
  }
  em,i{
    font-style:normal;
  }
  strong{
    font-weight: normal;
  }
  .clearfix:after{
    content:"";
    display:block;
    visibility:hidden;
    height:0;
    clear:both;
  }
  .clearfix{zoom:1;}
  a{
    text-decoration:none;
    color:#333;
    font-family: '黑体',Microsoft YaHei,Tahoma,Arial,sans-serif;}
  a:hover{
    color:#FED503;
    text-decoration:none;
  }
  ul,ol{
    list-style:none;
  }
  h1, h2, h3, h4, h5, h6{
    font-size:100%;
    font-family: Microsoft YaHei;
  }
  img{
    border: none;
  }
  b {
    font-size: 100% !important;
  }
  span{
    font-size: 100% !important;
  }
</style>

5. 其他点

vue-awesome-swiper 实现中间大两边小轮播

vue props监听变化的坑

vue通过props传递照片地址给子组件的坑

  • 图片是在static文件夹下,可以直接传递
img:"../../static/list_1.png",
  • 如果在assets文件夹下,是需要require传入的,否则webpack解析不到正确的路径

持续记录