如何基于vue-cli3.0構(gòu)建功能完善的移動端架子
基于vue-cli3.0構(gòu)建功能完善的移動端架子,主要功能包括
- 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)配置的改動在根目錄下增加vue.config.js進(jìn)行配置
css:sass支持、normalize.css、_mixin.scss、_variables.scss
使用的css預(yù)處理器是sass,對于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布局
對于移動端適配方案使用的是 網(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è)置
devServer: {
open: true, // 啟動服務(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ā)布到線上時如果前端代碼不是和后臺api放在 同源 下的,后臺還需做跨域處理,
eslint standard設(shè)置
使用的是 JavaScript standard 代碼規(guī)范,一個好的編碼風(fēng)格它可以幫助減少團(tuán)隊(duì)之間的摩擦,代碼閱讀起來也更加清爽,更加可讀性,不要覺得煩,用了都說好。
這是 JavaScript standard 代碼規(guī)范的全文
自定義配置,在.eslintrc.js里修改,這里是我給出的配置,4個空格縮進(jìn),不檢查結(jié)尾分號,關(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é)尾分號,
// 強(qiáng)制使用單引號
quotes: ['error', 'single'],
// 關(guān)閉函數(shù)名與后面括號間必須空格規(guī)則
'space-before-function-paren': 0,
// 關(guān)閉var 聲明,每個聲明占一行規(guī)則。
'one-var': 0
}
cdn引入
對于 vue、vue-router、vuex、axios等等這些不經(jīng)常改動的庫、我們讓webpack不對他們進(jìn)行打包,通過cdn引入,可以減少代碼的大小、也可以減少服務(wù)器的帶寬
這里使用的是360的cdn,附上一份公共cdn評測文章 點(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 => {
// 對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" />
<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: '*', // 未匹配到路由時重定向
redirect: '/',
meta: {
// auth: true,
// keepAlive: true
}
}
]
})
// 全局路由鉤子函數(shù) 對全局有效
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ù)中對登錄權(quán)限判斷,沒有登錄的跳到登錄頁面,并且把當(dāng)前頁面?zhèn)鬟^去,登錄后跳回這個頁面。
對于頁面緩存的在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ì)
對于axios的設(shè)計(jì)主要是請求攔截器, respone攔截器,以及get,post的二次封裝
axios.defaults.timeout = 12000 // 請求超時時間
axios.defaults.baseURL = process.env.VUE_APP_BASE_API
axios.defaults.headers.post['Content-Type'] =
'application/x-www-form-urlencoded;charset=UTF-8' // post請求頭的設(shè)置
// axios 請求攔截器
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,說明接口請求成功,可以正常拿到數(shù)據(jù)
// 否則的話拋出錯誤 結(jié)合自身業(yè)務(wù)和后臺返回的接口狀態(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請求不存在
case 404:
Toast({
message: '網(wǎng)絡(luò)請求不存在',
position: 'middle',
duration: 2000
});
break
default:
Toast({
message: error.response.data.message,
position: 'middle',
duration: 2000
});
}
return Promise.reject(error)
}
)
/**
* 封裝get方法,對應(yīng)get請求
* @param {String} url [請求的url地址]
* @param {Object} params [請求時攜帶的參數(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方法,對應(yīng)post請求
* @param {String} url [請求的url地址]
* @param {Object} params [請求時攜帶的參數(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路徑,這里把所以請求都放在了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)常會引用各個地方的文件,配置后可以更加方便的引入了
config.resolve.alias
.set('assets', '@/assets')
.set('components', '@/components')
.set('view', '@/view')
.set('style', '@/style')
.set('api', '@/api')
.set('store', '@/store')
環(huán)境變量和模式
在一個產(chǎn)品的前端開發(fā)過程中,一般來說會經(jīng)歷本地開發(fā)、測試腳本、開發(fā)自測、測試環(huán)境、預(yù)上線環(huán)境,然后才能正式的發(fā)布。對應(yīng)每一個環(huán)境可能都會有所差異,比如說服務(wù)器地址、接口地址、websorket地址…… 等等。在各個環(huán)境切換的時候,就需要不同的配置參數(shù),所以就可以用環(huán)境變量和模式,來方便我們管理。
.env # 在所有的環(huán)境中被載入 .env.local # 在所有的環(huán)境中被載入,但會被 git 忽略 .env.[mode] # 只在指定的模式中被載入 .env.[mode].local # 只在指定的模式中被載入,但會被 git 忽略
自定義的變量VUE_APP_開頭,兩個特殊的變量:
- NODE_ENV - 會是 "development"、"production" 或 "test" 中的一個。具體的值取決于應(yīng)用運(yùn)行的模式。
- BASE_URL - 會和 vue.config.js 中的 baseUrl 選項(xiàng)相符,即你的應(yīng)用會部署到的基礎(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
把多個地方用到的過濾器寫在一個js里面,復(fù)用代碼。
// 過濾日期格式,傳入時間戳,根據(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())
}

代碼地址 項(xiàng)目地址: vue-cli3-H5
demo地址: https://zhouyupeng.github.io/vuecli3H5/#/
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- vue-cli3.0 特性解讀
- 詳解如何配置vue-cli3.0的vue.config.js
- 一份超級詳細(xì)的Vue-cli3.0使用教程【推薦】
- vue-cli3.0使用及部分配置詳解
- vue-cli3.0 腳手架搭建項(xiàng)目的過程詳解
- vue-cli3.0配置及使用注意事項(xiàng)詳解
- vue-cli3.0+element-ui上傳組件el-upload的使用
- vue-cli3.0 環(huán)境變量與模式配置方法
- 詳解基于vue-cli3.0如何構(gòu)建功能完善的前端架子
- 詳解在vue-cli3.0中自定css、js和圖片的打包路徑
- 使用Vue-cli3.0創(chuàng)建的項(xiàng)目 如何發(fā)布npm包
- vue-cli3.0實(shí)現(xiàn)一個多頁面應(yīng)用的歷奇經(jīng)歷記錄總結(jié)
相關(guān)文章
詳解Vue學(xué)習(xí)筆記進(jìn)階篇之列表過渡及其他
本篇文章主要介紹了詳解Vue學(xué)習(xí)筆記進(jìn)階篇之列表過渡及其他,具有一定的參考價值,有興趣的可以了解一下2017-07-07
vue中echarts圖表大小適應(yīng)窗口大小且不需要刷新案例
這篇文章主要介紹了vue中echarts圖表大小適應(yīng)窗口大小且不需要刷新案例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-07-07
vue項(xiàng)目中data數(shù)據(jù)之間互相訪問的實(shí)現(xiàn)
本文主要介紹了vue項(xiàng)目中data數(shù)據(jù)之間互相訪問的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-05-05
vue router 跳轉(zhuǎn)后回到頂部的實(shí)例
今天小編就為大家分享一篇vue router 跳轉(zhuǎn)后回到頂部的實(shí)例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-08-08

