Açıklama Yok

SanHQin acb8d55adc update 10 ay önce
dist acb8d55adc update 10 ay önce
public 31345e4f65 Merge branch 'master' into HK 10 ay önce
src bee283aa9e update 10 ay önce
static 981ac0a03c first 2 yıl önce
.browserslistrc 981ac0a03c first 2 yıl önce
.editorconfig 981ac0a03c first 2 yıl önce
.env.development 981ac0a03c first 2 yıl önce
.env.production 981ac0a03c first 2 yıl önce
.env.staging 981ac0a03c first 2 yıl önce
.eslintignore 981ac0a03c first 2 yıl önce
.eslintrc.js 981ac0a03c first 2 yıl önce
.gitignore d587642444 update 2 yıl önce
.postcssrc.js 981ac0a03c first 2 yıl önce
.prettierignore 981ac0a03c first 2 yıl önce
.prettierrc 981ac0a03c first 2 yıl önce
README.md 981ac0a03c first 2 yıl önce
babel.config.js 84b2948dee update 2 yıl önce
jsconfig.json 981ac0a03c first 2 yıl önce
package.json 31345e4f65 Merge branch 'master' into HK 10 ay önce
vue.config.js 03c265806a update 1 yıl önce

README.md

vue-h5-template

基于 vue-cli4.0 + webpack 4 + vant ui + sass+ rem 适配方案+axios 封装 + jssdk配置 + vconsole移动端调试,构建手机端模板脚手架

掘金: vue-cli4 vant rem 移动端框架方案

查看 demo 建议手机端查看

Node 版本要求

Vue CLI 需要 Node.js 8.9 或更高版本 (推荐 8.11.0+)。你可以使用 nvmnvm-windows 在同一台电脑中管理多个 Node 版本。

本示例 Node.js 12.14.1

项目结构

vue-h5-template -- UI主目录
├── public -- 静态资源
├ ├── favicon.ico -- 图标
├ └── index.html -- 首页
├── src -- 源码目录
├ ├── api -- 后端交互的接口
├ ├── assets -- 静态资源目录 ├ ├── css ├ ├── index.scss -- 全局通用样式 ├ ├── mixin.scss -- 全局mixin ├ └── variables.scss -- 全局变量
├ ├── components -- 封装的组件
├ ├── config -- 环境配置
├ ├── const -- 放vue页面的配置常量
├ ├── filters -- 过滤器
├ ├── plugins -- 插件
├ └── route -- VUE路由
├ ├── index -- 路由入口
├ └── router.config.js -- 路由表
├ ├── store -- VUEX
├ └── util -- 工具包
├ ├── request.js -- axios封装
├ ├── vconsole.js -- 移动端调试插件 ├ ├── jsApiList.js -- 微信JS接口列表 ├ ├── wechatPlugin.js -- jssdk插件配置 ├ ├── storage.js -- 本地存储封装 ├ └── util -- 工具包
├ └── views -- 业务上的vue页面
├ ├── layouts -- 路由布局页面(是否缓存页面) ├ └── home -- 公众号 ├ ├── App.vue -- 根组件
├ └── main.js -- 入口js
├── .env.development -- 开发环境
├── .env.production -- 生产环境
├── .env.staging -- 测试环境
├── .editorconfig -- ESLint配置
├── .gitignore -- git忽略
├── .postcssrc.js -- CSS预处理配置(rem适配)
├── babel.config.js -- barbel配置入口
├── jsconfig.json -- vscode路径引入配置 ├── package.json -- 依赖管理
└── vue.config.js -- vue cli3的webpack配置

启动项目


git clone https://github.com/sunniejs/vue-h5-template.git

cd vue-h5-template

npm install

npm run serve

目录

✅ 配置多环境变量

package.json 里的 scripts 配置 serve stage build,通过 --mode xxx 来执行不同环境

  • 通过 npm run serve 启动本地 , 执行 development
  • 通过 npm run stage 启动测试 , 执行 development
  • 通过 npm run prod 启动开发 , 执行 development
  • 通过 npm run stageBuild 打包测试 , 执行 staging
  • 通过 npm run build 打包正式 , 执行 production
"scripts": {
  "serve": "vue-cli-service serve --open",
  "stage": "cross-env NODE_ENV=dev vue-cli-service serve --mode staging",
  "prod": "cross-env NODE_ENV=dev vue-cli-service serve --mode production",
  "stageBuild": "vue-cli-service build --mode staging",
  "build": "vue-cli-service build",
}
配置介绍

  以 VUE_APP_ 开头的变量,在代码中可以通过 process.env.VUE_APP_ 访问。
  比如,VUE_APP_ENV = 'development' 通过process.env.VUE_APP_ENV 访问。
  除了 VUE_APP_* 变量之外,在你的应用代码中始终可用的还有两个特殊的变量NODE_ENVBASE_URL

在项目根目录中新建.env.*

  • .env.development 本地开发环境配置
NODE_ENV='development'
# must start with VUE_APP_
VUE_APP_ENV = 'development'

  • .env.staging 测试环境配置
NODE_ENV='production'
# must start with VUE_APP_
VUE_APP_ENV = 'staging'
  • .env.production 正式环境配置
 NODE_ENV='production'
# must start with VUE_APP_
VUE_APP_ENV = 'production'

这里我们并没有定义很多变量,只定义了基础的 VUE_APP_ENV development staging production
变量我们统一在 src/config/env.*.js 里进行管理。

这里有个问题,既然这里有了根据不同环境设置变量的文件,为什么还要去 config 下新建三个对应的文件呢?
修改起来方便,不需要重启项目,符合开发习惯。

config/index.js

// 根据环境引入不同配置 process.env.NODE_ENV
const config = require('./env.' + process.env.VUE_APP_ENV)
module.exports = config

配置对应环境的变量,拿本地环境文件 env.development.js 举例,用户可以根据需求修改

// 本地环境配置
module.exports = {
  title: 'vue-h5-template',
  baseUrl: 'http://localhost:9018', // 项目地址
  baseApi: 'https://test.xxx.com/api', // 本地api请求地址
  APPID: 'xxx',
  APPSECRET: 'xxx'
}

根据环境不同,变量就会不同了

// 根据环境不同引入不同baseApi地址
import { baseApi } from '@/config'
console.log(baseApi)

▲ 回顶部

✅ rem 适配方案

不用担心,项目已经配置好了 rem 适配, 下面仅做介绍:

Vant 中的样式默认使用px作为单位,如果需要使用rem单位,推荐使用以下两个工具:

PostCSS 配置

下面提供了一份基本的 postcss 配置,可以在此配置的基础上根据项目需求进行修改

// https://github.com/michael-ciniawsky/postcss-load-config
module.exports = {
  plugins: {
    autoprefixer: {
      overrideBrowserslist: ['Android 4.1', 'iOS 7.1', 'Chrome > 31', 'ff > 31', 'ie >= 8']
    },
    'postcss-pxtorem': {
      rootValue: 37.5,
      propList: ['*']
    }
  }
}

更多详细信息: vant

新手必看,老鸟跳过

很多小伙伴会问我,适配的问题。

我们知道 1rem 等于html 根元素设定的 font-sizepx 值。Vant UI 设置 rootValue: 37.5,你可以看到在 iPhone 6 下 看到 (1rem 等于 37.5px):

<html data-dpr="1" style="font-size: 37.5px;"></html>

切换不同的机型,根元素可能会有不同的font-size。当你写 css px 样式时,会被程序换算成 rem 达到适配。

因为我们用了 Vant 的组件,需要按照 rootValue: 37.5 来写样式。

举个例子:设计给了你一张 750px * 1334px 图片,在 iPhone6 上铺满屏幕,其他机型适配。

  • rootValue: 70 , 样式 width: 750px;height: 1334px; 图片会撑满 iPhone6 屏幕,这个时候切换其他机型,图片也会跟着撑 满。
  • rootValue: 37.5 的时候,样式 width: 375px;height: 667px; 图片会撑满 iPhone6 屏幕。

也就是 iphone 6 下 375px 宽度写 CSS。其他的你就可以根据你设计图,去写对应的样式就可以了。

当然,想要撑满屏幕你可以使用 100%,这里只是举例说明。

<img class="image" src="https://imgs.solui.cn/weapp/logo.png" />

<style>
  /* rootValue: 75 */
  .image {
    width: 750px;
    height: 1334px;
  }
  /* rootValue: 37.5 */
  .image {
    width: 375px;
    height: 667px;
  }
</style>

▲ 回顶部

✅ VantUI 组件按需加载

项目采 用Vant 自动按需引入组件 (推荐)下 面安装插件介绍:

babel-plugin-import 是一款 babel 插件,它会在编译过程中将 import 的写法自动转换为按需引入的方式

安装插件

npm i babel-plugin-import -D

babel.config.js 设置

// 对于使用 babel7 的用户,可以在 babel.config.js 中配置
const plugins = [
  [
    'import',
    {
      libraryName: 'vant',
      libraryDirectory: 'es',
      style: true
    },
    'vant'
  ]
]
module.exports = {
  presets: [['@vue/cli-plugin-babel/preset', { useBuiltIns: 'usage', corejs: 3 }]],
  plugins
}

使用组件

项目在 src/plugins/vant.js 下统一管理组件,用哪个引入哪个,无需在页面里重复引用

// 按需全局引入 vant组件
import Vue from 'vue'
import { Button, List, Cell, Tabbar, TabbarItem } from 'vant'
Vue.use(Button)
Vue.use(Cell)
Vue.use(List)
Vue.use(Tabbar).use(TabbarItem)

▲ 回顶部

✅ Sass 全局样式

首先 你可能会遇到 node-sass 安装不成功,别放弃多试几次!!!

每个页面自己对应的样式都写在自己的 .vue 文件之中 scoped 它顾名思义给 css 加了一个域的概念。

<style lang="scss">
  /* global styles */
</style>

<style lang="scss" scoped>
  /* local styles */
</style>

目录结构

vue-h5-template 所有全局样式都在 @/src/assets/css 目录下设置

├── assets
│   ├── css
│   │   ├── index.scss               # 全局通用样式
│   │   ├── mixin.scss               # 全局mixin
│   │   └── variables.scss           # 全局变量

自定义 vant-ui 样式

现在我们来说说怎么重写 vant-ui 样式。由于 vant-ui 的样式我们是在全局引入的,所以你想在某个页面里面覆盖它的样式就不能 加 scoped,但你又想只覆盖这个页面的 vant 样式,你就可在它的父级加一个 class,用命名空间来解决问题。

.about-container {
  /* 你的命名空间 */
  .van-button {
    /* vant-ui 元素*/
    margin-right: 0px;
  }
}

父组件改变子组件样式 深度选择器

当你子组件使用了 scoped 但在父组件又想修改子组件的样式可以 通过 >>> 来实现:

<style scoped>
.a >>> .b { /* ... */ }
</style>

全局变量

vue.config.js 配置使用 css.loaderOptions 选项,注入 sassmixin variables 到全局,不需要手动引入 ,配 置$cdn通过变量形式引入 cdn 地址,这样向所有 Sass/Less 样式传入共享的全局变量:

const IS_PROD = ['production', 'prod'].includes(process.env.NODE_ENV)
const defaultSettings = require('./src/config/index.js')
module.exports = {
  css: {
    extract: IS_PROD,
    sourceMap: false,
    loaderOptions: {
      // 给 scss-loader 传递选项
      scss: {
        // 注入 `sass` 的 `mixin` `variables` 到全局, $cdn可以配置图片cdn
        // 详情: https://cli.vuejs.org/guide/css.html#passing-options-to-pre-processor-loaders
        prependData: `
                @import "assets/css/mixin.scss";
                @import "assets/css/variables.scss";
                $cdn: "${defaultSettings.$cdn}";
                 `
      }
    }
  }
}

设置 js 中可以访问 $cdn,.vue 文件中使用this.$cdn访问

// 引入全局样式
import '@/assets/css/index.scss'

// 设置 js中可以访问 $cdn
// 引入cdn
import { $cdn } from '@/config'
Vue.prototype.$cdn = $cdn

在 css 和 js 使用

<script>
  console.log(this.$cdn)
</script>
<style lang="scss" scoped>
  .logo {
    width: 120px;
    height: 120px;
    background: url($cdn+'/weapp/logo.png') center / contain no-repeat;
  }
</style>

▲ 回顶部

✅ Vuex 状态管理

目录结构

├── store
│   ├── modules
│   │   └── app.js
│   ├── index.js
│   ├── getters.js

main.js 引入

import Vue from 'vue'
import App from './App.vue'
import store from './store'
new Vue({
  el: '#app',
  router,
  store,
  render: h => h(App)
})

使用

<script>
  import { mapGetters } from 'vuex'
  export default {
    computed: {
      ...mapGetters(['userName'])
    },

    methods: {
      // Action 通过 store.dispatch 方法触发
      doDispatch() {
        this.$store.dispatch('setUserName', '值')
      }
    }
  }
</script>

▲ 回顶部

✅ Vue-router

本案例采用 hash 模式,开发者根据需求修改 mode base

注意:如果你使用了 history 模式,vue.config.js 中的 publicPath 要做对应的修改

前往:vue.config.js 基础配置

import Vue from 'vue'
import Router from 'vue-router'

Vue.use(Router)
export const router = [
  {
    path: '/',
    name: 'index',
    component: () => import('@/views/home/index'), // 路由懒加载
    meta: {
      title: '首页', // 页面标题
      keepAlive: false // keep-alive 标识
    }
  }
]
const createRouter = () =>
  new Router({
    // mode: 'history', // 如果你是 history模式 需要配置 vue.config.js publicPath
    // base: '/app/',
    scrollBehavior: () => ({ y: 0 }),
    routes: router
  })

export default createRouter()

更多:Vue Router

▲ 回顶部

✅ Axios 封装及接口管理

utils/request.js 封装 axios ,开发者需要根据后台接口做修改。

  • service.interceptors.request.use 里可以设置请求头,比如设置 token
  • config.hideloading 是在 api 文件夹下的接口参数里设置,下文会讲
  • service.interceptors.response.use 里可以对接口返回数据处理,比如 401 删除本地信息,重新登录
import axios from 'axios'
import store from '@/store'
import { Toast } from 'vant'
// 根据环境不同引入不同api地址
import { baseApi } from '@/config'
// create an axios instance
const service = axios.create({
  baseURL: baseApi, // url = base api url + request url
  withCredentials: true, // send cookies when cross-domain requests
  timeout: 5000 // request timeout
})

// request 拦截器 request interceptor
service.interceptors.request.use(
  config => {
    // 不传递默认开启loading
    if (!config.hideloading) {
      // loading
      Toast.loading({
        forbidClick: true
      })
    }
    if (store.getters.token) {
      config.headers['X-Token'] = ''
    }
    return config
  },
  error => {
    // do something with request error
    console.log(error) // for debug
    return Promise.reject(error)
  }
)
// respone拦截器
service.interceptors.response.use(
  response => {
    Toast.clear()
    const res = response.data
    if (res.status && res.status !== 200) {
      // 登录超时,重新登录
      if (res.status === 401) {
        store.dispatch('FedLogOut').then(() => {
          location.reload()
        })
      }
      return Promise.reject(res || 'error')
    } else {
      return Promise.resolve(res)
    }
  },
  error => {
    Toast.clear()
    console.log('err' + error) // for debug
    return Promise.reject(error)
  }
)
export default service

接口管理

src/api 文件夹下统一管理接口

  • 你可以建立多个模块对接接口, 比如 home.js 里是首页的接口这里讲解 user.js
  • url 接口地址,请求的时候会拼接上 config 下的 baseApi
  • method 请求方法
  • data 请求参数 qs.stringify(params) 是对数据系列化操作
  • hideloading 默认 false,设置为 true 后,不显示 loading ui 交互中有些接口不需要让用户感知
import qs from 'qs'
// axios
import request from '@/utils/request'
//user api

// 用户信息
export function getUserInfo(params) {
  return request({
    url: '/user/userinfo',
    method: 'post',
    data: qs.stringify(params),
    hideloading: true // 隐藏 loading 组件
  })
}

如何调用

// 请求接口
import { getUserInfo } from '@/api/user.js'

const params = { user: 'sunnie' }
getUserInfo(params)
  .then(() => {})
  .catch(() => {})

▲ 回顶部

✅ Webpack 4 vue.config.js 基础配置

如果你的 Vue Router 模式是 hash

publicPath: './',

如果你的 Vue Router 模式是 history 这里的 publicPath 和你的 Vue Router base 保持一直

publicPath: '/app/',
const IS_PROD = ['production', 'prod'].includes(process.env.NODE_ENV)

module.exports = {
  publicPath: './', // 署应用包时的基本 URL。 vue-router hash 模式使用
  //  publicPath: '/app/', // 署应用包时的基本 URL。  vue-router history模式使用
  outputDir: 'dist', //  生产环境构建文件的目录
  assetsDir: 'static', //  outputDir的静态资源(js、css、img、fonts)目录
  lintOnSave: !IS_PROD,
  productionSourceMap: false, // 如果你不需要生产环境的 source map,可以将其设置为 false 以加速生产环境构建。
  devServer: {
    port: 9020, // 端口号
    open: false, // 启动后打开浏览器
    overlay: {
      //  当出现编译器错误或警告时,在浏览器中显示全屏覆盖层
      warnings: false,
      errors: true
    }
    // ...
  }
}

▲ 回顶部

✅ 配置 alias 别名

const path = require('path')
const resolve = dir => path.join(__dirname, dir)
const IS_PROD = ['production', 'prod'].includes(process.env.NODE_ENV)

module.exports = {
  chainWebpack: config => {
    // 添加别名
    config.resolve.alias
      .set('@', resolve('src'))
      .set('assets', resolve('src/assets'))
      .set('api', resolve('src/api'))
      .set('views', resolve('src/views'))
      .set('components', resolve('src/components'))
  }
}

▲ 回顶部

✅ 配置 proxy 跨域

如果你的项目需要跨域设置,你需要打来 vue.config.js proxy 注释 并且配置相应参数

!!!注意:你还需要将 src/config/env.development.js 里的 baseApi 设置成 '/'

module.exports = {
  devServer: {
    // ....
    proxy: {
      //配置跨域
      '/api': {
        target: 'https://test.xxx.com', // 接口的域名
        // ws: true, // 是否启用websockets
        changOrigin: true, // 开启代理,在本地创建一个虚拟服务端
        pathRewrite: {
          '^/api': '/'
        }
      }
    }
  }
}

使用 例如: src/api/home.js

export function getUserInfo(params) {
  return request({
    url: '/api/userinfo',
    method: 'post',
    data: qs.stringify(params)
  })
}

▲ 回顶部

✅ 配置 打包分析

const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin

module.exports = {
  chainWebpack: config => {
    // 打包分析
    if (IS_PROD) {
      config.plugin('webpack-report').use(BundleAnalyzerPlugin, [
        {
          analyzerMode: 'static'
        }
      ])
    }
  }
}
npm run build

▲ 回顶部

✅ 配置 externals 引入 cdn 资源

这个版本 CDN 不再引入,我测试了一下使用引入 CDN 和不使用,不使用会比使用时间少。网上不少文章测试 CDN 速度块,这个开发者可 以实际测试一下。

另外项目中使用的是公共 CDN 不稳定,域名解析也是需要时间的(如果你要使用请尽量使用同一个域名)

因为页面每次遇到<script>标签都会停下来解析执行,所以应该尽可能减少<script>标签的数量 HTTP请求存在一定的开销,100K 的文件比 5 个 20K 的文件下载的更快,所以较少脚本数量也是很有必要的

暂时还没有研究放到自己的 cdn 服务器上。

const defaultSettings = require('./src/config/index.js')
const name = defaultSettings.title || 'vue mobile template'
const IS_PROD = ['production', 'prod'].includes(process.env.NODE_ENV)

// externals
const externals = {
  vue: 'Vue',
  'vue-router': 'VueRouter',
  vuex: 'Vuex',
  vant: 'vant',
  axios: 'axios'
}
// CDN外链,会插入到index.html中
const cdn = {
  // 开发环境
  dev: {
    css: [],
    js: []
  },
  // 生产环境
  build: {
    css: ['https://cdn.jsdelivr.net/npm/vant@2.4.7/lib/index.css'],
    js: [
      'https://cdn.jsdelivr.net/npm/vue@2.6.11/dist/vue.min.js',
      'https://cdn.jsdelivr.net/npm/vue-router@3.1.5/dist/vue-router.min.js',
      'https://cdn.jsdelivr.net/npm/axios@0.19.2/dist/axios.min.js',
      'https://cdn.jsdelivr.net/npm/vuex@3.1.2/dist/vuex.min.js',
      'https://cdn.jsdelivr.net/npm/vant@2.4.7/lib/index.min.js'
    ]
  }
}
module.exports = {
  configureWebpack: config => {
    config.name = name
    // 为生产环境修改配置...
    if (IS_PROD) {
      // externals
      config.externals = externals
    }
  },
  chainWebpack: config => {
    /**
     * 添加CDN参数到htmlWebpackPlugin配置中
     */
    config.plugin('html').tap(args => {
      if (IS_PROD) {
        args[0].cdn = cdn.build
      } else {
        args[0].cdn = cdn.dev
      }
      return args
    })
  }
}

在 public/index.html 中添加

    <!-- 使用CDN的CSS文件 -->
    <% for (var i in
      htmlWebpackPlugin.options.cdn&&htmlWebpackPlugin.options.cdn.css) { %>
      <link href="<%= htmlWebpackPlugin.options.cdn.css[i] %>" rel="preload" as="style" />
      <link href="<%= htmlWebpackPlugin.options.cdn.css[i] %>" rel="stylesheet" />
    <% } %>
     <!-- 使用CDN加速的JS文件,配置在vue.config.js下 -->
    <% for (var i in
      htmlWebpackPlugin.options.cdn&&htmlWebpackPlugin.options.cdn.js) { %>
      <script src="<%= htmlWebpackPlugin.options.cdn.js[i] %>"></script>
    <% } %>

▲ 回顶部

✅ 去掉 console.log

保留了测试环境和本地环境的 console.log

npm i -D babel-plugin-transform-remove-console

在 babel.config.js 中配置

// 获取 VUE_APP_ENV 非 NODE_ENV,测试环境依然 console
const IS_PROD = ['production', 'prod'].includes(process.env.VUE_APP_ENV)
const plugins = [
  [
    'import',
    {
      libraryName: 'vant',
      libraryDirectory: 'es',
      style: true
    },
    'vant'
  ]
]
// 去除 console.log
if (IS_PROD) {
  plugins.push('transform-remove-console')
}

module.exports = {
  presets: [['@vue/cli-plugin-babel/preset', { useBuiltIns: 'entry' }]],
  plugins
}

▲ 回顶部

✅ splitChunks 单独打包第三方模块

module.exports = {
  chainWebpack: config => {
    config.when(IS_PROD, config => {
      config
        .plugin('ScriptExtHtmlWebpackPlugin')
        .after('html')
        .use('script-ext-html-webpack-plugin', [
          {
            // 将 runtime 作为内联引入不单独存在
            inline: /runtime\..*\.js$/
          }
        ])
        .end()
      config.optimization.splitChunks({
        chunks: 'all',
        cacheGroups: {
          // cacheGroups 下可以可以配置多个组,每个组根据test设置条件,符合test条件的模块
          commons: {
            name: 'chunk-commons',
            test: resolve('src/components'),
            minChunks: 3, //  被至少用三次以上打包分离
            priority: 5, // 优先级
            reuseExistingChunk: true // 表示是否使用已有的 chunk,如果为 true 则表示如果当前的 chunk 包含的模块已经被抽取出去了,那么将不会重新生成新的。
          },
          node_vendors: {
            name: 'chunk-libs',
            chunks: 'initial', // 只打包初始时依赖的第三方
            test: /[\\/]node_modules[\\/]/,
            priority: 10
          },
          vantUI: {
            name: 'chunk-vantUI', // 单独将 vantUI 拆包
            priority: 20, // 数字大权重到,满足多个 cacheGroups 的条件时候分到权重高的
            test: /[\\/]node_modules[\\/]_?vant(.*)/
          }
        }
      })
      config.optimization.runtimeChunk('single')
    })
  }
}

▲ 回顶部

✅ 添加 IE 兼容

之前的方式 会报 @babel/polyfill is deprecated. Please, use required parts of core-js and regenerator-runtime/runtime separately

@babel/polyfill 废弃,使用 core-jsregenerator-runtime

npm i --save core-js regenerator-runtime

main.js 中添加

// 兼容 IE
// https://github.com/zloirock/core-js/blob/master/docs/2019-03-19-core-js-3-babel-and-a-look-into-the-future.md#babelpolyfill
import 'core-js/stable'
import 'regenerator-runtime/runtime'

配置 babel.config.js

const plugins = []

module.exports = {
  presets: [['@vue/cli-plugin-babel/preset', { useBuiltIns: 'usage', corejs: 3 }]],
  plugins
}

▲ 回顶部

✅ Eslint + Pettier 统一开发规范

VScode 安装 eslint prettier vetur 插件

在文件 .prettierrc 里写 属于你的 pettier 规则

{
   "printWidth": 120,
   "tabWidth": 2,
   "singleQuote": true,
   "trailingComma": "none",
   "semi": false,
   "wrap_line_length": 120,
   "wrap_attributes": "auto",
   "proseWrap": "always",
   "arrowParens": "avoid",
   "bracketSpacing": false,
   "jsxBracketSameLine": true,
   "useTabs": false,
   "overrides": [{
       "files": ".prettierrc",
       "options": {
           "parser": "json"
       }
   }]
}

Vscode setting.json 设置

    "[vue]": {
        "editor.defaultFormatter": "esbenp.prettier-vscode"
    },
    "[javascript]": {
        "editor.defaultFormatter": "esbenp.prettier-vscode"
    },
     // 保存时用eslint格式化
    "editor.codeActionsOnSave": {
        "source.fixAll.eslint": true
    },
    // 两者会在格式化js时冲突,所以需要关闭默认js格式化程序
    "javascript.format.enable": false,
    "typescript.format.enable": false,
    "vetur.format.defaultFormatter.html": "none",
    // js/ts程序用eslint,防止vetur中的prettier与eslint格式化冲突
    "vetur.format.defaultFormatter.js": "none",
    "vetur.format.defaultFormatter.ts": "none",

▲ 回顶部

✅ vconsole 移动端调试

参考地址:https://github.com/AlloyTeam/AlloyLever 参考地址:https://www.cnblogs.com/liyinSakura/p/9883777.html

import Vconsole from 'vconsole'
const vConsole = new Vconsole()
export default vConsole
  • app.vue中设置暗门,点击几次显示vconsole
    • 在app.vue中通过limit进行设置
    • 开发测试环境点击一次就可显示
    • 生产环境点击10次

▲ 回顶部

✅ 动态设置title

参考地址:https://github.com/deboyblog/vue-wechat-title 参考地址:https://www.cnblogs.com/guiyishanren/p/10666127.html

// main.js
// 引入插件 
Vue.use(require('vue-wechat-title'))

使用

// app.vue
<router-view v-wechat-title="$route.meta.title" />

▲ 回顶部

✅ 配置Jssdk

安装:

yarn add weixin-js-sdk

引用:

// util
wechatPlugin.js // jssdk插件配置
jsApiList.js // 微信JS接口列表
// main.js
// 全局注册微信js-sdk
import WechatPlugin from '@/utils/wechatPlugin'
Vue.use(WechatPlugin)

调用:

created() {
  console.log(this.$wx)
},

▲ 回顶部

✅ 本地存储storage封装

安装:

storage.js

引用:

// 引入本地存储
import { storage, sessionStorage } from '@/utils/storage'
Vue.prototype.$storage = storage
Vue.prototype.$sessionStorage = sessionStorage

调用:

created() {
  this.$storage.set('key','value')
  this.$storage.get('key')
  this.$sessionStorage.set('key','value')
  this.$sessionStorage.get('key')
},

▲ 回顶部

鸣谢 ​

vue-cli4-config vue-element-admin

Path` 要做对应的修改

前往:vue.config.js 基础配置

import Vue from 'vue'
import Router from 'vue-router'

Vue.use(Router)
export const router = [
  {
    path: '/',
    name: 'index',
    component: () => import('@/views/home/index'), // 路由懒加载
    meta: {
      title: '首页', // 页面标题
      keepAlive: false // keep-alive 标识
    }
  }
]
const createRouter = () =>
  new Router({
    // mode: 'history', // 如果你是 history模式 需要配置 vue.config.js publicPath
    // base: '/app/',
    scrollBehavior: () => ({ y: 0 }),
    routes: router
  })

export default createRouter()

更多:Vue Router

▲ 回顶部

✅ Axios 封装及接口管理

utils/request.js 封装 axios ,开发者需要根据后台接口做修改。

  • service.interceptors.request.use 里可以设置请求头,比如设置 token
  • config.hideloading 是在 api 文件夹下的接口参数里设置,下文会讲
  • service.interceptors.response.use 里可以对接口返回数据处理,比如 401 删除本地信息,重新登录
import axios from 'axios'
import store from '@/store'
import { Toast } from 'vant'
// 根据环境不同引入不同api地址
import { baseApi } from '@/config'
// create an axios instance
const service = axios.create({
  baseURL: baseApi, // url = base api url + request url
  withCredentials: true, // send cookies when cross-domain requests
  timeout: 5000 // request timeout
})

// request 拦截器 request interceptor
service.interceptors.request.use(
  config => {
    // 不传递默认开启loading
    if (!config.hideloading) {
      // loading
      Toast.loading({
        forbidClick: true
      })
    }
    if (store.getters.token) {
      config.headers['X-Token'] = ''
    }
    return config
  },
  error => {
    // do something with request error
    console.log(error) // for debug
    return Promise.reject(error)
  }
)
// respone拦截器
service.interceptors.response.use(
  response => {
    Toast.clear()
    const res = response.data
    if (res.status && res.status !== 200) {
      // 登录超时,重新登录
      if (res.status === 401) {
        store.dispatch('FedLogOut').then(() => {
          location.reload()
        })
      }
      return Promise.reject(res || 'error')
    } else {
      return Promise.resolve(res)
    }
  },
  error => {
    Toast.clear()
    console.log('err' + error) // for debug
    return Promise.reject(error)
  }
)
export default service

接口管理

src/api 文件夹下统一管理接口

  • 你可以建立多个模块对接接口, 比如 home.js 里是首页的接口这里讲解 user.js
  • url 接口地址,请求的时候会拼接上 config 下的 baseApi
  • method 请求方法
  • data 请求参数 qs.stringify(params) 是对数据系列化操作
  • hideloading 默认 false,设置为 true 后,不显示 loading ui 交互中有些接口不需要让用户感知

```javascript import qs from 'qs' // axios import request from '@/utils/request' //user api

// 用户信息 export function getUserInfo(params) { return request({

url: '/user/userinfo