今天正好有机会, 整理一下如何新建一个 vue 移动端模板框架

vue create vue_h5
回车

Vue CLI v4.1.1
? Please pick a preset:
  ee (router, vuex, babel)
  单元测试 (node-sass, babel, router, vuex, eslint, unit-jest)
  标准项目 (node-sass, babel, router, vuex, eslint)
  default (babel, eslint)
> Manually select features
回车

? Please pick a preset: Manually select features
? Check the features needed for your project:
 (*) Babel
 ( ) TypeScript
 (*) Progressive Web App (PWA) Support
 (*) Router
 (*) Vuex
>(*) CSS Pre-processors
 (*) Linter / Formatter
 ( ) Unit Testing
 ( ) E2E Testing

以上是我新建选择的组件

移动端项目 最为关键的就是 px => rem 单位转换问题

引入Vant UI框架

  1. cnpm install vant -S 引入 babel-plugin-import

  2. 配置按需加载 需要修改 babel.config.js main.js 这两个文件

    -- babel.config.js 
    module.exports = {
      presets: [
        '@vue/app'
      ],
      plugins: [
        ['import', {
          libraryName: 'vant',
          libraryDirectory: 'es',
          style: true
        }, 'vant']
      ]
    }
    -- main.js
    import { Button, NavBar, Cell } from 'vant'
    import 'vant/lib/button/style'
    
    Vue.use(Button).use(Cell).use(NavBar)
    
  3. 统一单位 px -> rem 需要用到 postcss-pxtorem lib-flexible (这里方案很多,就不多说了)
    cnpm isntall lib-flexible -S
    cnpm install postcss-pxtorem -D
    main.js引入 import ‘lib-flexible/flexible’
    之后配置一下 vue.config.js (默认项目是没有的,自己新建在根目录 )

    /**
     * 配置参考: https://cli.vuejs.org/zh/config/
     */
    module.exports = {
      publicPath: process.env.NODE_ENV === 'production' ? './' : '/',
      productionSourceMap: false,
      devServer: {
        open: true,
        port: 8017,
        proxy: {
          '/api': {
            target: 'http://apitest.oucnet.com',
            secure: false,
            ws: true,
            changeOrigin: true,
            pathRewrite: { '^/api': '' }
          }
        },
        overlay: {
          errors: true,
          warnings: true
        }
      },
      css: {
        loaderOptions: {
          postcss: {
            plugins: [
              require('postcss-pxtorem')({
                rootValue: 37.5, // 换算的基数
                propList: ['*']
              })
            ]
          }
        }
      }
    }
    

注: 这里 publicPath 可能你用的是 vue-cli3 这个参数名称应该是 baseUrl 我这里是
vue-cli4.1.1, 我这里的换算值是 37.5 对应的设计稿是 375 宽的 但是我们一般拿到的设计稿是 750宽的
所以你要调整一下。

这里调整方式我给我两种方案
第一种 修改设计稿宽度 我这里使用的蓝湖
在这里插入图片描述
第二种 就是修改 postcss-pxtorem 转换规则 还是按750px 做

vue.config.js 需要改一下 不转换 vant 组件

css: {
    loaderOptions: {
      postcss: {
        plugins: [
          require('postcss-pxtorem')({
            rootValue: 75, // 换算的基数
            propList: ['*'],
            selectorBlackList: ['.van-']
          })
        ]
      }
    }
  }

最终效果
在这里插入图片描述

重要组件修改

  • router/index.js 修改
import Vue from 'vue'
import Router from 'vue-router'

Vue.use(Router)

const routes = [
  {
    path: '*',
    component: () => import('@/views/pages/404'),
    name: '404',
    meta: { title: '404未找到' }
  },
  { path: '/', name: 'index', component: () => import('@/views/index'), meta: { title: '加载中···' } }
]

const router = new Router({
  mode: 'history',
  scrollBehavior: () => ({ y: 0 }),
  base: process.env.BASE_URL,
  routes
})

// 拦截器
router.beforeEach((to, from, next) => {
  // 动态标题
  window.document.title = to.meta.title
  // 处理业务问题...
  next()
})

// 处理Router的BUG 当前显示的路由再次点击会打印错误
const originalPush = Router.prototype.push
Router.prototype.push = function push (location) {
  return originalPush.call(this, location).catch(err => err)
}

export default router
  • axios 以及vuex 的配置 引入两个组件 cnpm install lodash axios -S
    store/index.js 修改
import Vue from 'vue'
import Vuex from 'vuex'
import cloneDeep from 'lodash/cloneDeep'

Vue.use(Vuex)

export default new Vuex.Store({
  state: {
  },
  mutations: {
    // 重置vuex本地储存状态
    resetStore (state) {
      Object.keys(state).forEach((key) => {
        state[key] = cloneDeep(window.SITE_CONFIG['storeState'][key])
      })
    }
  },
  actions: {
  },
  modules: {
  }
})

axios 配置 我这里在新建了 src/utils/request.js

import axios from 'axios'
import router from '@/router'
import { clearLoginInfo } from '@/utils'
import { Toast } from 'vant'
const http = axios.create({
  baseURL: window.SITE_CONFIG['apiURL'],
  timeout: 1000 * 180,
  withCredentials: true
})

/**
 * 请求拦截
 */
http.interceptors.request.use(config => {
  return config
}, error => {
  return Promise.reject(error)
})

/**
 * 响应拦截
 */
http.interceptors.response.use(response => {
  if (response.data.code === 401) {
    clearLoginInfo()
    router.replace({ name: 'login' })
    return Promise.reject(response.data.msg)
  }
  return response
}, err => {
  if (err && err.response) {
    switch (err.response.status) {
      case 301: err.message = '请求的数据具有新的位置且更改是永久的'; break
      case 302: err.message = '请求的数据临时具有不同 URI'; break
      case 304: err.message = '未按预期修改文档'; break
      case 305: err.message = '必须通过代理来访问请求的资源'; break
      case 400: err.message = '请求中有语法问题,或不能满足请求'; break
      case 402: err.message = '所使用的模块需要付费使用'; break
      case 403: err.message = '当前操作没有权限'; break
      case 404: err.message = '服务器找不到给定的资源'; break
      case 407: err.message = '客户机首先必须使用代理认证自身'; break
      case 415: err.message = '请求类型不支持,服务器拒绝服务'; break
      case 417: err.message = '未绑定登录账号,请使用密码登录后绑定'; break
      case 426: err.message = '用户名不存在或密码错误'; break
      case 429: err.message = '请求过于频繁'; break
      case 500: err.message = '服务器内部错误,无法完成请求'; break
      case 501: err.message = '服务不支持请求'; break
      case 502: err.message = '网络错误,服务器接收到上上游服务器无效响应'; break
      case 503: err.message = '服务器无法处理请求'; break
      case 504: err.message = '网络请求超时'; break
      case 999: err.message = '系统未知错误,请反馈给管理员'; break
    }
  } else {
    err.message = '连接服务器失败!'
  }
  Toast(err.message)
  return Promise.reject(err)
})

export default http

main.js 配置

import Vue from 'vue'
import App from './App.vue'
import './registerServiceWorker'
import router from './router'
import store from './store'
import { Button, NavBar, Cell } from 'vant'
import 'vant/lib/button/style'
import 'lib-flexible/flexible'
import cloneDeep from 'lodash/cloneDeep'
import http from '@/utils/request'

Vue.config.productionTip = false

Vue.use(Button).use(Cell).use(NavBar)

// 挂载全局
Vue.prototype.$http = http

// 保存整站vuex本地储存初始状态
window.SITE_CONFIG['storeState'] = cloneDeep(store.state)

new Vue({
  router,
  store,
  render: h => h(App)
}).$mount('#app')

配置 本地开发域名 上线上线打包域名 需要修改 index.html 和 package.json

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, viewport-fit=cover">
    <link rel="icon" href="<%= BASE_URL %>favicon.ico">
    <title>H5项目模板</title>

    <!-- 站点配置 -->
    <script>
      window.SITE_CONFIG = {};
      window.SITE_CONFIG['nodeEnv'] = '<%= process.env.VUE_APP_NODE_ENV %>';
      window.SITE_CONFIG['apiURL'] = '';                      // api请求地址
      window.SITE_CONFIG['storeState'] = {};                  // vuex本地储存初始化状态(用于不刷新页面的情况下,也能重置初始化项目中所有状态)
    </script>

    <!-- 本地测试环境 -->
    <% if (process.env.VUE_APP_NODE_ENV === 'dev') { %>
    <script>window.SITE_CONFIG['apiURL'] = '/api';</script>
    <% } %>
    <!-- 集成上线环境 -->
    <% if (process.env.VUE_APP_NODE_ENV === 'prod:sit') { %>
    <script>window.SITE_CONFIG['apiURL'] = 'http://127.0.0.1:1000';</script>
    <% } %>
  </head>
  <body>
    <noscript>
      <strong>We're sorry but 05_h5 doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
    </noscript>
    <div id="app"></div>
    <!-- built files will be auto injected -->
  </body>
</html>
"scripts": {
    "serve": "vue-cli-service serve",
    "build": "vue-cli-service build --mode development",
    "build:sit": "vue-cli-service build --mode production.sit",
    "lint": "vue-cli-service lint"
  },

最后打包本地测试页面 cnpm run build
打包上线页面 cnpm run build:sit

Logo

前往低代码交流专区

更多推荐