溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

怎么基于vue-cli3.0構(gòu)建功能完善的移動(dòng)端架子

發(fā)布時(shí)間:2021-02-05 13:42:05 來源:億速云 閱讀:184 作者:小新 欄目:web開發(fā)

這篇文章給大家分享的是有關(guān)怎么基于vue-cli3.0構(gòu)建功能完善的移動(dòng)端架子的內(nèi)容。小編覺得挺實(shí)用的,因此分享給大家做個(gè)參考,一起跟隨小編過來看看吧。

基于vue-cli3.0構(gòu)建功能完善的移動(dòng)端架子,主要功能包括

  • webpack 打包擴(kuò)展

  • css:sass支持、normalize.css、_mixin.scss、_variables.scss

  • vw、rem布局

  • 跨域設(shè)置

  • eslint設(shè)置

  • cdn引入

  • 路由設(shè)計(jì)、登錄攔截

  • axios、api 設(shè)計(jì)

  • vuex狀態(tài)管理

項(xiàng)目地址: vue-cli3-H5

demo地址: https://zhouyupeng.github.io/vuecli3H5/#/

webpack 打包擴(kuò)展

vue-cli3.*后目錄結(jié)構(gòu)大改,去除了以往的build,config文件夾,要實(shí)現(xiàn)配置的改動(dòng)在根目錄下增加vue.config.js進(jìn)行配置

css:sass支持、normalize.css、_mixin.scss、_variables.scss

使用的css預(yù)處理器是sass,對(duì)于css mixin,變量這里做了全局引入,并且引入 normalize.css 使HTML元素樣式在跨瀏覽器上表現(xiàn)得的高度一致性

vue.config.js配置

css: {
    // 是否使用css分離插件 ExtractTextPlugin
    extract: true,
    // 開啟 CSS source maps?
    sourceMap: false,
    // css預(yù)設(shè)器配置項(xiàng)
    // 啟用 CSS modules for all css / pre-processor files.
    modules: false,
      sass: {
        data: '@import "style/_mixin.scss";@import "style/_variables.scss";' // 全局引入
      }
    }
  }

vw、rem布局

對(duì)于移動(dòng)端適配方案使用的是 網(wǎng)易新聞 的方法,

使用vw + rem布局

/**
750px設(shè)計(jì)稿
  取1rem=100px為參照,那么html元素的寬度就可以設(shè)置為width: 7.5rem,于是html的font-size=deviceWidth / 7.5
**/
html {
  font-size: 13.33333vw
}

@media screen and (max-width: 320px) {
  html {
    font-size: 42.667PX;
    font-size: 13.33333vw
  }
}

@media screen and (min-width: 321px) and (max-width:360px) {
  html {
    font-size: 48PX;
    font-size: 13.33333vw
  }
}

@media screen and (min-width: 361px) and (max-width:375px) {
  html {
    font-size: 50PX;
    font-size: 13.33333vw
  }
}

@media screen and (min-width: 376px) and (max-width:393px) {
  html {
    font-size: 52.4PX;
    font-size: 13.33333vw
  }
}

@media screen and (min-width: 394px) and (max-width:412px) {
  html {
    font-size: 54.93PX;
    font-size: 13.33333vw
  }
}

@media screen and (min-width: 413px) and (max-width:414px) {
  html {
    font-size: 55.2PX;
    font-size: 13.33333vw
  }
}

@media screen and (min-width: 415px) and (max-width:480px) {
  html {
    font-size: 64PX;
    font-size: 13.33333vw
  }
}

@media screen and (min-width: 481px) and (max-width:540px) {
  html {
    font-size: 72PX;
    font-size: 13.33333vw
  }
}

@media screen and (min-width: 541px) and (max-width:640px) {
  html {
    font-size: 85.33PX;
    font-size: 13.33333vw
  }
}

@media screen and (min-width: 641px) and (max-width:720px) {
  html {
    font-size: 96PX;
    font-size: 13.33333vw
  }
}

@media screen and (min-width: 721px) and (max-width:768px) {
  html {
    font-size: 102.4PX;
    font-size: 13.33333vw
  }
}

@media screen and (min-width: 769px) {
  html {
    font-size: 102.4PX;
    font-size: 13.33333vw
  }
}

@media screen and (min-width: 769px) {
  html {
    font-size: 102.4PX;

    #app {
      margin: 0 auto
    }
  }

vue.config.js配置

loaderOptions: {
  postcss: {
    // 這是rem適配的配置
    plugins: [
      require('postcss-px2rem')({
        remUnit: 100
      })
    ]
  }}

開發(fā)時(shí)跨域設(shè)置

devServer: {
    open: true, // 啟動(dòng)服務(wù)后是否打開瀏覽器
    host: '127.0.0.1',
    port: 8088, // 服務(wù)端口
    https: false,
    hotOnly: false,
    proxy: 'https://easy-mock.com/' // 設(shè)置代理
  }

配置完后,本地開發(fā)環(huán)境的axios的baseUrl要寫為 '' ,即空字符串。

發(fā)布到線上時(shí)如果前端代碼不是和后臺(tái)api放在 同源 下的,后臺(tái)還需做跨域處理,

eslint standard設(shè)置

使用的是 JavaScript standard 代碼規(guī)范,一個(gè)好的編碼風(fēng)格它可以幫助減少團(tuán)隊(duì)之間的摩擦,代碼閱讀起來也更加清爽,更加可讀性,不要覺得煩,用了都說好。

這是 JavaScript standard 代碼規(guī)范的全文

自定義配置,在.eslintrc.js里修改,這里是我給出的配置,4個(gè)空格縮進(jìn),不檢查結(jié)尾分號(hào),關(guān)閉單var 聲明,可自行配置

rules: {
  'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off',
  'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off',
  indent: [
    'error',
    4,
    {
      SwitchCase: 1
    }
  ],
  semi: 0, // 不檢查結(jié)尾分號(hào),
  // 強(qiáng)制使用單引號(hào)
  quotes: ['error', 'single'],
  // 關(guān)閉函數(shù)名與后面括號(hào)間必須空格規(guī)則
  'space-before-function-paren': 0,
  // 關(guān)閉var 聲明,每個(gè)聲明占一行規(guī)則。
  'one-var': 0
  }

cdn引入

對(duì)于 vue、vue-router、vuex、axios等等這些不經(jīng)常改動(dòng)的庫、我們讓webpack不對(duì)他們進(jìn)行打包,通過cdn引入,可以減少代碼的大小、也可以減少服務(wù)器的帶寬

這里使用的是360的cdn,附上一份公共cdn評(píng)測(cè)文章 點(diǎn)我

vue.config.js配置

const externals = {
  vue: 'Vue',
  'vue-router': 'VueRouter',
  vuex: 'Vuex',
  'mint-ui': 'MINT',
  axios: 'axios'

}

const cdn = {
  // 開發(fā)環(huán)境
  dev: {
    css: [
      'https://lib.baomitu.com/mint-ui/2.2.13/style.min.css'
    ],
    js: []
  },
  // 生產(chǎn)環(huán)境
  build: {
    css: [
      'https://lib.baomitu.com/mint-ui/2.2.13/style.min.css'
    ],
    js: [
      'https://lib.baomitu.com/vue/2.6.6/vue.min.js',
      'https://lib.baomitu.com/vue-router/3.0.1/vue-router.min.js',
      'https://lib.baomitu.com/vuex/3.0.1/vuex.min.js',
      'https://lib.baomitu.com/axios/0.18.0/axios.min.js',
      'https://lib.baomitu.com/mint-ui/2.2.13/index.js'
    ]
  }
}

configureWebpack: config => {
    if (isProduction) {
      // externals里的模塊不打包
      Object.assign(config, {
        externals: externals
      })
    
    } else {
      // 為開發(fā)環(huán)境修改配置...
    }
  },
chainWebpack: config => {
  // 對(duì)vue-cli內(nèi)部的 webpack 配置進(jìn)行更細(xì)粒度的修改。
  // 添加CDN參數(shù)到htmlWebpackPlugin配置中, 詳見public/index.html 修改
  config.plugin('html').tap(args => {
    if (process.env.NODE_ENV === 'production') {
      args[0].cdn = cdn.build
    }
    if (process.env.NODE_ENV === 'development') {
      args[0].cdn = cdn.dev
    }
    return args
  })
}
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="utf-8" />
  <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  <!-- DNS預(yù)解析 -->
  <link rel="dns-prefetch" href="//lib.baomitu.com" />
  <meta name="viewport"
    content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=0,minimal-ui,viewport-fit=cover" />
  <link rel="icon" href="<%= BASE_URL %>favicon.ico" />
  <!-- 使用CDN加速的CSS文件,配置在vue.config.js下 -->
  <% 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" />
  <% } %>

  <title>vuedemo</title>
</head>

<body>
  <noscript>
    <strong>We're sorry but vuedemo doesn't work properly without JavaScript
      enabled. Please enable it to continue.</strong>
  </noscript>
  <div id="app"></div>
  <!-- 使用CDN加速的JS文件,配置在vue.config.js下 -->
  <% for (var i in
  htmlWebpackPlugin.options.cdn&&htmlWebpackPlugin.options.cdn.js) { %>
  <script src="<%= htmlWebpackPlugin.options.cdn.js[i] %>"></script>
  <% } %>

  <!-- built files will be auto injected -->
</body>

</html>

路由設(shè)計(jì)、登錄攔截

const router = new Router({
  routes: [
    {
      path: '/',
      name: 'home',
      component: Home,
      meta: {
        auth: false, // 是否需要登錄
        keepAlive: true // 是否緩存組件
      }
    },
    {
      path: '/about',
      name: 'about',
      component: () =>
        import(/* webpackChunkName: "about" */ './views/About.vue'),
      meta: {
        auth: true,
        keepAlive: true
      }
    },
    {
      path: '/login',
      name: 'login',
      component: () =>
        import(/* webpackChunkName: "login" */ './views/login.vue'),
      meta: {
        auth: false,
        keepAlive: true
      }
    },
    {
      path: '*', // 未匹配到路由時(shí)重定向
      redirect: '/',
      meta: {
        // auth: true,
        // keepAlive: true
      }
    }
  ]
})

// 全局路由鉤子函數(shù) 對(duì)全局有效
router.beforeEach((to, from, next) => {
  let auth = to.meta.auth
  let token = store.getters['login/token'];

  if (auth) { // 需要登錄
    if (token) {
      next()
    } else {
      next({
        name: 'login',
        query: {
          redirect: to.path
        }
      })
    }
  } else {
    next()
  }
})

在meta中設(shè)置是否需要登錄以及是否緩存當(dāng)前組件,

在router.beforeEac路由鉤子函數(shù)中對(duì)登錄權(quán)限判斷,沒有登錄的跳到登錄頁面,并且把當(dāng)前頁面?zhèn)鬟^去,登錄后跳回這個(gè)頁面。

對(duì)于頁面緩存的在app.vue里進(jìn)行處理

<keep-alive>
  <router-view v-if="$route.meta.keepAlive"></router-view>
</keep-alive>
<router-view v-if="!$route.meta.keepAlive"></router-view>

axios、api 設(shè)計(jì)

對(duì)于axios的設(shè)計(jì)主要是請(qǐng)求攔截器, respone攔截器,以及get,post的二次封裝

axios.defaults.timeout = 12000 // 請(qǐng)求超時(shí)時(shí)間
axios.defaults.baseURL = process.env.VUE_APP_BASE_API

axios.defaults.headers.post['Content-Type'] =
  'application/x-www-form-urlencoded;charset=UTF-8' // post請(qǐng)求頭的設(shè)置
// axios 請(qǐng)求攔截器
axios.interceptors.request.use(
  config => {
    // 可在此設(shè)置要發(fā)送的token
    let token = store.getters['login/token'];
    token && (config.headers.token = token)
    Indicator.open('數(shù)據(jù)加載中')
    return config
  },
  error => {
    return Promise.error(error)
  }
)
// axios respone攔截器
axios.interceptors.response.use(
  response => {
    // 如果返回的狀態(tài)碼為200,說明接口請(qǐng)求成功,可以正常拿到數(shù)據(jù)
    // 否則的話拋出錯(cuò)誤 結(jié)合自身業(yè)務(wù)和后臺(tái)返回的接口狀態(tài)約定寫respone攔截器
    Indicator.close()
    console.log('response', response);
    if (response.status === 200 && response.data.code === 0) {
      return Promise.resolve(response)
    } else {
      Toast({
        message: response.data.msg,
        position: 'middle',
        duration: 2000
      });
      return Promise.reject(response)
    }
  },
  error => {
    Indicator.close()
    const responseCode = error.response.status
    switch (responseCode) {
      // 401:未登錄
      case 401:
        break
      // 404請(qǐng)求不存在
      case 404:
        Toast({
          message: '網(wǎng)絡(luò)請(qǐng)求不存在',
          position: 'middle',
          duration: 2000
        });
        break
      default:
        Toast({
          message: error.response.data.message,
          position: 'middle',
          duration: 2000
        });
    }
    return Promise.reject(error)
  }
)
/**
 * 封裝get方法,對(duì)應(yīng)get請(qǐng)求
 * @param {String} url [請(qǐng)求的url地址]
 * @param {Object} params [請(qǐng)求時(shí)攜帶的參數(shù)]
 */
function get (url, params = {}) {
  return new Promise((resolve, reject) => {
    axios
      .get(url, {
        params: params
      })
      .then(res => {
        resolve(res.data)
      })
      .catch(err => {
        reject(err.data)
      })
  })
}
/**
 * post方法,對(duì)應(yīng)post請(qǐng)求
 * @param {String} url [請(qǐng)求的url地址]
 * @param {Object} params [請(qǐng)求時(shí)攜帶的參數(shù)]
 */
function post (url, params) {
  return new Promise((resolve, reject) => {
    axios
      .post(url, qs.stringify(params))
      .then(res => {
        resolve(res.data)
      })
      .catch(err => {
        reject(err.data)
      })
  })
}

為了方便管理api路徑,這里把所以請(qǐng)求都放在了api文件夾下,如

import { get, post } from '@/axios/http.js'
function getIndex (params) {
  return get('/mock/5cb48c7ed491cd741c54456f/base/index', params)
}
function login(params) {
  return post('/mock/5cb48c7ed491cd741c54456f/base/login', params)
}
export {
  getIndex,
  login
}

其他

去除console.log

裝uglifyjs-webpack-plugin插件

 // 上線壓縮去除console等信息
config.plugins.push(
  new UglifyJsPlugin({
    uglifyOptions: {
      compress: {
        warnings: false,
        drop_console: true,
        drop_debugger: false,
        pure_funcs: ['console.log'] // 移除console
      }
    },
    sourceMap: false,
    parallel: true
  })
)

設(shè)置alias目錄別名

在項(xiàng)目中經(jīng)常會(huì)引用各個(gè)地方的文件,配置后可以更加方便的引入了

config.resolve.alias
      .set('assets', '@/assets')
      .set('components', '@/components')
      .set('view', '@/view')
      .set('style', '@/style')
      .set('api', '@/api')
      .set('store', '@/store')

環(huán)境變量和模式

在一個(gè)產(chǎn)品的前端開發(fā)過程中,一般來說會(huì)經(jīng)歷本地開發(fā)、測(cè)試腳本、開發(fā)自測(cè)、測(cè)試環(huán)境、預(yù)上線環(huán)境,然后才能正式的發(fā)布。對(duì)應(yīng)每一個(gè)環(huán)境可能都會(huì)有所差異,比如說服務(wù)器地址、接口地址、websorket地址…… 等等。在各個(gè)環(huán)境切換的時(shí)候,就需要不同的配置參數(shù),所以就可以用環(huán)境變量和模式,來方便我們管理。

.env        # 在所有的環(huán)境中被載入
.env.local     # 在所有的環(huán)境中被載入,但會(huì)被 git 忽略
.env.[mode]     # 只在指定的模式中被載入
.env.[mode].local  # 只在指定的模式中被載入,但會(huì)被 git 忽略

自定義的變量VUE_APP_開頭,兩個(gè)特殊的變量:

  • NODE_ENV - 會(huì)是 "development"、"production" 或 "test" 中的一個(gè)。具體的值取決于應(yīng)用運(yùn)行的模式。

  • BASE_URL - 會(huì)和 vue.config.js 中的 baseUrl 選項(xiàng)相符,即你的應(yīng)用會(huì)部署到的基礎(chǔ)路徑。

如我們定義的.env

NODE_ENV = 'development'
BASE_URL = '/'
VUE_APP_BASE_API = ''

.env.production

NODE_ENV = 'production'
BASE_URL = './'
VUE_APP_BASE_API = 'https://easy-mock.com/'

在項(xiàng)目中可以用process.env.VUE_APP_*,如process.env.VUE_APP_BASE_API獲取到定義的值

全局引入filter

把多個(gè)地方用到的過濾器寫在一個(gè)js里面,復(fù)用代碼。

// 過濾日期格式,傳入時(shí)間戳,根據(jù)參數(shù)返回不同格式
const formatTimer = function(val, hours) {
  if (val) {
    var dateTimer = new Date(val * 1000)
    var y = dateTimer.getFullYear()
    var M = dateTimer.getMonth() + 1
    var d = dateTimer.getDate()
    var h = dateTimer.getHours()
    var m = dateTimer.getMinutes()
    M = M >= 10 ? M : '0' + M
    d = d >= 10 ? d : '0' + d
    h = h >= 10 ? h : '0' + h
    m = m >= 10 ? m : '0' + m
    if (hours) {
      return y + '-' + M + '-' + d + ' ' + h + ':' + m
    } else {
      return y + '-' + M + '-' + d
    }
  }
}
export default {
  formatTimer
}

main.js引入

import filters from './filters/index'
// 注入全局過濾器
Object.keys(filters).forEach(item => {
  Vue.filter(item, filters[item])
})

使用

{{1555851774 | formatTimer()}}

vue中使用mock.js

查看我以前寫的文章點(diǎn)擊我

wepback的可視化資源分析工具插件---webpack-bundle-analyzer

用來分析哪些模塊引入了哪些代碼,進(jìn)行有目的性的優(yōu)化代碼

在打包環(huán)境中加,使用命令npm run build --report

if (process.env.npm_config_report) {
  config.plugins.push(new BundleAnalyzerPlugin())
}

怎么基于vue-cli3.0構(gòu)建功能完善的移動(dòng)端架子

感謝各位的閱讀!關(guān)于“怎么基于vue-cli3.0構(gòu)建功能完善的移動(dòng)端架子”這篇文章就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,讓大家可以學(xué)到更多知識(shí),如果覺得文章不錯(cuò),可以把它分享出去讓更多的人看到吧!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI