最近在作個人小愛ADMIN後臺管理系統,結合當前市場後臺管理系統對相關功能的需求,我又開始新增了一些新的功能和組件,如分享功能組件,項目國際化功能;項目完成後,部署在nginx服務器,發現首次訪問的速度特別慢,嚴重的影響了用戶體驗,所以,我又開始進行了一系列的前端性能優化;以及將優化後的項目部署到nginx服務器二級子目錄的注意細節。javascript
用微信,微博等作網站的第三方登陸及用微信和支付寶進行支付,都須要註冊開發者帳號和添加網站應用,比較麻煩。另外,註冊的信息若是在前端頁面裏面進行公開,缺少安全性。第三方分享功能不須要註冊開發者帳號和添加網站應用,用戶信息相對保密,使用方法也相對簡單。css
封裝了8個經常使用的分享組件,包含仿簡書網站的底部和側欄分享組件、仿掘金網站分享組件、仿新浪網站分享組件和其餘一些網站橫向排列的分享組件。包含的分享渠道有:微信、微博、qq、qq空間、豆瓣等。html
分享效果如圖:前端
分享組件的封裝:share/index.vuevue
<template> <div class="shareContainer" ref="shareContainer"> <el-row :gutter="20"> <el-col :span="6"> <heng-share @shareToQQ="shareToQQ" @shareToQQzone="shareToQQzone" @shareToWeibo="shareToWeibo" @shareToDouban="shareToDouban"></heng-share> </el-col> <el-col :span="6"> <invite-share @shareToQQ="shareToQQ" @shareToQQzone="shareToQQzone" @shareToWeibo="shareToWeibo" @shareToDouban="shareToDouban"></invite-share> </el-col> <el-col :span="6"> <jianshu-share @shareToWeixin="shareToWeixin" @shareToQQ="shareToQQ" @shareToQQzone="shareToQQzone" @shareToWeibo="shareToWeibo" @shareToDouban="shareToDouban"></jianshu-share> </el-col> <el-col :span="6"> <jianshu-left-share @shareToWeixin="shareToWeixin" @shareToQQ="shareToQQ" @shareToQQzone="shareToQQzone" @shareToWeibo="shareToWeibo" @shareToDouban="shareToDouban"></jianshu-left-share> </el-col> </el-row> <el-row :gutter="20"> <el-col :span="6"> <info-share @shareToQQ="shareToQQ" @shareToQQzone="shareToQQzone" @shareToWeibo="shareToWeibo" @shareToDouban="shareToDouban"></info-share> </el-col> <el-col :span="6"> <juejin-share @shareToQQ="shareToQQ" @shareToQQzone="shareToQQzone" @shareToWeibo="shareToWeibo" @shareToDouban="shareToDouban"></juejin-share> </el-col> <el-col :span="6"> <sina-share @shareToQQ="shareToQQ" @shareToQQzone="shareToQQzone" @shareToWeibo="shareToWeibo" @shareToDouban="shareToDouban"></sina-share> </el-col> <el-col :span="6"> <yan-share @shareToQQ="shareToQQ" @shareToQQzone="shareToQQzone" @shareToWeibo="shareToWeibo" @shareToDouban="shareToDouban"></yan-share> </el-col> </el-row> <wx-code-modal v-if="wxModal.show" :wxModal="wxModal" @hideWxCodeModal="hideWxCodeModal"></wx-code-modal> </div> </template>
分享方法的集合: utils/share.jsjava
import { weibo,qq,qqZone,douban,shareUrl,shareTitle } from "@/utils/env"; import * as mutils from "@/utils/mUtils"; function getParamsUrl(obj){ let paramsUrl = ''; for(let key in obj){ paramsUrl += key+'='+obj[key]+'&' } return paramsUrl; } export function shareConfig(type,obj){ let baseUrl = ''; if(mutils.isEmpty(obj)){ obj = {}; } switch(type){ case 'weibo': const weiboData = { 'url':shareUrl, // 內容連接,默認當前頁面location 'title':shareTitle, // 可選參數, 默認當前頁title 'pic':obj.pic || weibo.pic, // 分享圖片的路徑(可選),多張圖片經過"||"分開。 'count':'y', /**是否顯示分享數,y|n(可選)*/ 'searchPic':true // 是否要自動抓取頁面上的圖片。true|falsetrue:自動抓取,false:不自動抓取。 } baseUrl = weibo.weiboUrl+'?appkey='+weibo.weiboAppkey+getParamsUrl(weiboData); window.open(baseUrl,'_blank'); break; case 'qq': const qqData = { 'url':shareUrl, 'title':shareTitle, 'pics':obj.pic || qq.pic, //QZone接口暫不支持發送多張圖片的能力,若傳入多張圖片,則會自動選入第一張圖片做爲預覽圖。 'source':obj.source || qq.source, // 分享來源 'desc':obj.desc || qq.desc, 'summary':obj.summary || qq.summary, } baseUrl = qq.baseUrl+'?'+getParamsUrl(qqData) window.open(baseUrl,'_blank'); break; case 'qqZone': const qqZoneData = { 'url':shareUrl, 'title':shareTitle, 'pics':obj.pic || (qqZone.pic).split(','), 'sharesource':obj.sharesource || qqZone.sharesource, // 分享來源 'desc':obj.desc || qqZone.desc, 'summary':obj.summary || qqZone.summary, } baseUrl = qqZone.baseUrl+'?'+getParamsUrl(qqZoneData) window.open(baseUrl,'_blank'); break; case 'douban': const doubanData = { 'href':shareUrl, 'name':shareTitle, 'image':obj.pic || douban.pic, } baseUrl = douban.baseUrl+'?'+getParamsUrl(doubanData) window.open(baseUrl,'_blank'); break; } }
微博分享後的效果,如圖:linux
<div align="left"> <img width = "400" height = "300" src="https://user-gold-cdn.xitu.io/2019/8/27/16cd0c2393116dc8?w=782&h=557&f=png&s=65550" /> </div>webpack
qq分享後的效果,如圖:ios
<div align="left"> <img width = "400" height = "300" src="https://user-gold-cdn.xitu.io/2019/8/27/16cd0c4d3b28e303?w=934&h=671&f=png&s=112244" /> </div>nginx
因爲本項目須要多語言的支持,咱們須要作國際化。咱們使用 vue-i18n 來實現多語言的界面。
npm install vue-i18n --save
關於語言包,咱們有幾種方式:一種是每一個語言包一個獨立的js放到項目裏;或者將語言的對照寫在 .vue 文件裏, 或者加載遠程的JSON語言包 咱們的後臺界面須要支持的語言一般很少,更新也不會很是的頻繁,因此咱們將語言包放在項目裏,規劃項目目錄,增長 lang 目錄來存放語言對照。
中文語言包配置:src/lang/zh.js
const zh = { // layout commons: { xiaoai: '小愛', admin: '管理員', editor: '趙曉編', quit: '退出', hi: '您好', index: '首頁', userManage: '用戶管理', share: '分享功能', infoManage: '信息管理', infoShow: '我的信息', infoShow1: '我的信息子菜單1', infoShow2: '我的信息子菜單2', infoShow3: '我的信息子菜單3', infoShow4: '我的信息子菜單4', infoShow5: '我的信息子菜單5', infoModify: '修改信息', infoModify1:'修改信息子菜單1', infoModify2:'修改信息子菜單2', infoModify3:'修改信息子菜單3', fundManage: '資金管理', fundList: '資金流水', chinaTabsList: '區域投資', fundData: '資金數據', fundPosition: '投資分佈', typePosition: '項目分佈', incomePayPosition: '收支分佈', permission: '權限設置', pagePer: '頁面權限', directivePer: '按鈕權限', errorPage: '錯誤頁面', page401:'401', page404:'404', wechatNumber: '微信號' }, index:{ yearLoss:'年度總盈虧', yearProfit:'年度收益率', potentialInvestor:'潛在投資人', intentionInvestor:'意向投資人', waitExamineInvestor:'待審投資人', examiningInvestor:'審覈中投資人', tenMillion:'千萬元', person:'人' } } export default zh;
英文語言包配置:src/lang/en.js
const zh = { // layout commons: { xiaoai: 'Ai.', admin: 'Admin', editor: 'Editor', quit: 'Sign Out', hi: 'Hi', index: 'Dashboard', userManage: 'Users', share: 'Share', infoManage: 'Infos', infoShow: 'InfoShow', infoShow1: 'InfoShow1', infoShow2: 'InfoShow2', infoShow3: 'InfoShow3', infoShow4: 'InfoShow4', infoShow5: 'InfoShow5', infoModify: 'InfoModify', infoModify1:'InfoModify1', infoModify2:'InfoModify2', infoModify3:'InfoModify3', fundManage: 'Money', fundList: 'MoneyList', chinaTabsList: 'AreaList', fundData: 'FundData', fundPosition: 'FundPosition', typePosition: 'TypePosition', incomePayPosition: 'IncomePayPosition', permission: 'Permission', pagePer: 'PagePermission', directivePer: 'DirectivePermission', errorPage: 'ErrorPage', page401:'401', page404:'404', wechatNumber: 'wechat' }, index:{ yearLoss:'Year Loss', yearProfit:'Year Profit', potentialInvestor:'Potential Investor', intentionInvestor:'Intention Investor', waitExamineInvestor:'Wait Examine Investor', examiningInvestor:'Examining Investor', tenMillion:'Ten Million', person:'P' } } export default zh;
導出配置:src/lang/index.js
// 引入i18n國際化插件 import { getToken} from '@/utils/auth' import Vue from 'vue' import VueI18n from 'vue-i18n' process.env.NODE_ENV === "development" ? Vue.use(VueI18n) : null; import enLocale from './en' import zhLocale from './zh' // 註冊i18n實例並引入語言文件,文件格式等下解析 const i18n = new VueI18n({ locale: getToken('lang') || 'en', messages: { zh: { ...zhLocale }, en: { ...enLocale }, } }); export default i18n;
注意: locale: getToken('lang') || 'en',主要用來存儲已經點擊過的語言項,以便在項目刷新的時候,還可以拿到cookie中存儲的語言類別。
// i18n國際化 import i18n from "@/lang"; new Vue({ router, store, i18n, // 便於能夠直接在組件中經過this.$i18n使用,也能夠按需引用 render: h => h(App), }).$mount('#app')
<div class='welcome'> <span class="name">{{$t('commons.hi')}},</span> <span class='name avatarname'> {{ $t(`commons.${name}`)}}</span> </div>
注意:$t('commons.hi'),這是直接導入的方法;$t(commons.${name}
),這是導入變量的方法。
效果如圖:
<el-submenu index="1" popper-class="langItem"> <template slot="title"> <img :src="langLogo" class='langAvatar' alt=""> </template> <el-menu-item index="1-1" @click="changeLocale('zh')"> <img :src="chinaImg" class='langAvatar' alt=""> <span class="intro">中文</span> </el-menu-item> <el-menu-item index="1-2" @click="changeLocale('en')"> <img :src="americaImg" class='langAvatar' alt=""> <span class="intro">EngList</span> </el-menu-item> </el-submenu>
// 切換語言 changeLocale(type){ setToken('lang',type); this.$i18n.locale = type; if(type === 'en'){ this.langLogo = this.americaImg; }else{ this.langLogo = this.chinaImg; } setToken('langLogo',this.langLogo); }
詳細性能優化配置,請參考:vue.config.js
vue-cli 3.0 build包太大致使首屏加載過長,嚴重的影響了用戶體驗。所以,咱們須要從如下方面提供相應的解決方案。
可使得打包事後的文件不包含未壓縮的.map文件,減小壓縮後代碼體積。
緣由:「懶加載也叫延遲加載,即在須要的時候進行加載,隨用隨載。在單頁應用中,若是沒有應用懶加載,運用webpack打包後的文件將會異常的大,形成進入首頁時,須要加載的內容過多,延時過長,不利於用戶體驗,而運用懶加載則能夠將頁面進行劃分,須要的時候加載頁面,能夠有效的分擔首頁所承擔的加載壓力,減小首頁加載用時。」
vue-router配置路由 , 使用vue的異步組件技術 , 能夠實現按需加載 . 可是,這種狀況下一個組件生成一個js文件
代碼以下:
{ path: '/login', name: 'login', component:function(resolve){ require(['@/page/login.vue'],resolve) } }
代碼以下:
{ path: '/login', name: 'login', component:() => import('@/page/login') }
這種狀況下,多個路由指定相同的chunkName,會合並打包成一個js文件。
代碼以下:
path: '/login', name: 'login', component: r => require.ensure([], () => r(require('@/page/login')), 'demo')
const CompressionPlugin = require("compression-webpack-plugin"); // gzip壓縮,優化http請求,提升加載速度 configureWebpack:config => { // 爲生產環境修改配置... if (process.env.NODE_ENV === 'production') { // 開啓gzip壓縮 config.plugins.push(new CompressionPlugin({ algorithm: 'gzip', test: new RegExp("\\.(" + ["js", "css"].join("|") + ")$"), // 匹配文件擴展名 // threshold: 10240, // 對超過10k的數據進行壓縮 threshold: 5120, // 對超過5k的數據進行壓縮 minRatio: 0.8, cache: true, // 是否須要緩存 deleteOriginalAssets:false // true刪除源文件(不建議);false不刪除源文件 })) } }
注意:使用compression-webpack-plugin開啓服務器Gzip,因此也須要在服務端進行配置,以便可以解析gzip文件;nginx端配置以下:
gzip on; gzip_comp_level 4; gzip_buffers 4 16k; gzip_types text/plain text/css application/javascript application/x-javascript text/xml application/xml application/xml+rss text/javascript; gzip_min_length 1k; gzip_http_version 1.1;
const TerserPlugin = require('terser-webpack-plugin') configureWebpack:config => { // 爲生產環境修改配置... if (process.env.NODE_ENV === 'production') { // 去除console來減小文件大小,效果同'UglifyJsPlugin' new TerserPlugin({ cache: true, parallel: true, sourceMap: true, // Must be set to true if using source-maps in production terserOptions: { compress: { warnings: false, drop_console: true, drop_debugger: true, pure_funcs: ['console.log'] } } }) } }
背景:在Vue項目中,引入到工程中的全部js、css文件,編譯時都會被打包進vendor.js,瀏覽器在加載該文件以後才能開始顯示首屏。如果引入的庫衆多,那麼vendor.js文件體積將會至關的大,影響首開的體驗。
解決方法:將引用的外部js、css文件剝離開來,不編譯到vendor.js中,而是用資源的形式引用,這樣瀏覽器可使用多個線程異步將vendor.js、外部的js等加載下來,達到加速首開的目的。
外部的庫文件,可使用CDN資源,或者別的服務器資源等。
步驟:
// 忽略生產環境打包的文件 config.externals = { "vue": "Vue", "vue-router": "VueRouter", "vuex": "Vuex", "vue-i18n": "VueI18n", "axios": "axios", 'element-ui': 'ELEMENT', 'echarts':'echarts', 'mockjs':'Mock', 'nprogress':'NProgress', 'js-cookie':'Cookies' }
具體cdn數據,請參考:https://www.bootcdn.cn/
const cdn = { // 開發環境 dev: { css: [], js: [] }, // 生產環境 build: { css: [ 'https://cdn.bootcss.com/element-ui/2.11.1/theme-chalk/index.css', 'https://cdn.bootcss.com/nprogress/0.2.0/nprogress.min.css' ], js: [ 'https://cdn.bootcss.com/vue/2.6.10/vue.min.js', 'https://cdn.bootcss.com/vue-router/3.1.2/vue-router.min.js', 'https://cdn.bootcss.com/vuex/2.3.1/vuex.min.js', 'https://cdn.bootcss.com/axios/0.19.0/axios.min.js', 'https://cdn.bootcss.com/vue-i18n/8.13.0/vue-i18n.min.js', 'https://cdn.bootcss.com/element-ui/2.11.1/index.js', 'https://cdn.bootcss.com/echarts/3.8.5/echarts.min.js', 'https://cdn.bootcss.com/Mock.js/1.0.1-beta3/mock-min.js', 'https://cdn.bootcss.com/nprogress/0.2.0/nprogress.min.js', 'https://cdn.bootcss.com/js-cookie/2.2.0/js.cookie.min.js' ] } }
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 })
意思是隻在開發環境引入相關的包,生產環境用cdn外鏈。
process.env.NODE_ENV === "development" ? Vue.use(Router) : null;// router/index.js process.env.NODE_ENV === "development" ? Vue.use(Vuex) : null;// store/index.js process.env.NODE_ENV === "development" && import('nprogress/nprogress.css') // src/permission.js process.env.NODE_ENV === "development" ? Vue.use(Mock) : null;//mockjs/index.js process.env.NODE_ENV === "development" ? Vue.use(VueI18n) : null;//lang/index.js
效果如圖:
<div align="left"> <img width = "400" height = "300" src="https://user-gold-cdn.xitu.io/2019/8/27/16cd34a2cdb5fcc0?w=698&h=432&f=png&s=83880" /> </div>
注意:使用cdn外鏈,減小打包文件體積;更多適用於在生產環境,而在開發環境,咱們還能夠繼續用之前的npm包。
性能優化先後的數據對比:
優化前:
優化後:
項目開發完成後,咱們將進行服務器的部署;部署分爲:部署在跟目錄和部署在子目錄,這兩種狀況,前端publicPath配置也是不同的,不然,服務器資源會顯示404,沒法加載。
注意:本項目服務器爲 windows系統,因此如下配置爲windows系統配置;若是你是linux系統服務器,請參考linux服務器部署配置。
準備工做:
下載網址:請參考;選擇該穩定版本下載;下載完成後,將該文件上傳到你的服務器目錄並解壓。如圖:
運行npm run build.將打包後的項目文件dist,複製到你的服務器目錄(個人dist文件目標爲:C:\ownprogram\vue\vue-touzi,個人nginx文件所在目標爲:C:\ownprogram\nginx-1.8.1);接下來,開始對nginx-1.8.1/config/nginx.config文件進行配置。
本項目部署的跟目錄爲:C:\ownprogram\vue\vue-touzi\dist\,默認爲80端口; vue.config.js中publicPath配置,以下:
module.exports = { publicPath: process.env.NODE_ENV === "production" ? "./" : "/" }
nginx.config,以下:
http { include mime.types; default_type application/octet-stream; add_header Access-Control-Allow-Origin *; add_header Access-Control-Allow-Headers X-Requested-With; add_header Access-Control-Allow-Methods GET,POST,OPTIONS; gzip on; gzip_comp_level 4; gzip_buffers 4 16k; gzip_types text/plain text/css application/javascript application/x-javascript text/xml application/xml application/xml+rss text/javascript; gzip_min_length 1k; gzip_http_version 1.1; server { listen 80; server_name localhost; charset utf-8; #access_log logs/host.access.log main; location / { root C:\ownprogram\vue\vue-touzi\dist\; index index.html index.htm; try_files $uri $uri/ /permission/index.html; proxy_set_header Accept-Encoding 'gzip'; } location /permission { alias C:\ownprogram\vue\vue-touzi\dist\permission; index index.html; try_files $uri $uri/ /permission/index.html; proxy_set_header Accept-Encoding 'gzip'; } }
由於本項目C:\ownprogram\vue\vue-touzi\dist\默認爲跟目錄,屬於dist/permission及爲二級子目錄;
router/index.js配置,以下:
//註冊路由 export default new Router({ mode:'history', // 默認爲'hash'模式 base: '/permission/', // 添加跟目錄,對應服務器部署子目錄 routes: constantRouterMap })
vue.config.js中publicPath配置,以下:
module.exports = { publicPath: process.env.NODE_ENV === "production" ? "/permission/" : "/" }
nginx.config,新增location配置,以下:
location /permission { alias C:\ownprogram\vue\vue-touzi\dist\permission; index index.html; try_files $uri $uri/ /permission/index.html; proxy_set_header Accept-Encoding 'gzip'; }
配置完成後,保存文件;重啓nginx便可進行正常訪問;
小愛ADMIN是徹底開源免費的管理系統集成方案,能夠直接應用於相關後臺管理系統模板;不少重點地方都作了詳細的註釋和解釋。若是你也同樣喜歡前端開發,歡迎加入咱們的討論/學習羣,羣內能夠提問答疑,分享學習資料; 歡迎加入答疑qq羣。
原文出處:https://www.cnblogs.com/wdlhao/p/11427616.html