vue-小愛ADMIN系列文章(二):微信微博等分享,國際化,前端性能優化,nginx服務器部署

最近在作個人小愛ADMIN後臺管理系統,結合當前市場後臺管理系統對相關功能的需求,我又開始新增了一些新的功能和組件,如分享功能組件,項目國際化功能;項目完成後,部署在nginx服務器,發現首次訪問的速度特別慢,嚴重的影響了用戶體驗,所以,我又開始進行了一系列的前端性能優化;以及將優化後的項目部署到nginx服務器二級子目錄的注意細節。javascript

分享功能

背景說明

用微信,微博等作網站的第三方登陸及用微信和支付寶進行支付,都須要註冊開發者帳號和添加網站應用,比較麻煩。另外,註冊的信息若是在前端頁面裏面進行公開,缺少安全性。第三方分享功能不須要註冊開發者帳號和添加網站應用,用戶信息相對保密,使用方法也相對簡單。css

前端ui呈現和分享渠道

封裝了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)

背景說明

因爲本項目須要多語言的支持,咱們須要作國際化。咱們使用 vue-i18n 來實現多語言的界面。

使用步驟

1.安裝vue-i18n

npm install vue-i18n --save

關於語言包,咱們有幾種方式:一種是每一個語言包一個獨立的js放到項目裏;或者將語言的對照寫在 .vue 文件裏, 或者加載遠程的JSON語言包 咱們的後臺界面須要支持的語言一般很少,更新也不會很是的頻繁,因此咱們將語言包放在項目裏,規劃項目目錄,增長 lang 目錄來存放語言對照。

2.新建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中存儲的語言類別。

3.在項目入口文件main.js中引入i18n

// i18n國際化
import i18n from "@/lang";
new Vue({
  router,
  store,
  i18n,  // 便於能夠直接在組件中經過this.$i18n使用,也能夠按需引用
  render: h => h(App),
}).$mount('#app')

4.頁面組件中使用方法$t()

<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}),這是導入變量的方法。

5.點擊切換語言方法

效果如圖:

<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);
}

基於cli3.0的vue項目的性能優化

詳細性能優化配置,請參考:vue.config.js

vue-cli 3.0 build包太大致使首屏加載過長,嚴重的影響了用戶體驗。所以,咱們須要從如下方面提供相應的解決方案。

1.productionSourceMap:false

可使得打包事後的文件不包含未壓縮的.map文件,減小壓縮後代碼體積。

2.項目中引入圖片壓縮(圖片在線免費壓縮網站 https://www.yasuotu.com/)或者將圖片放到cdn上面進行引用。

3.路由懶加載

緣由:「懶加載也叫延遲加載,即在須要的時候進行加載,隨用隨載。在單頁應用中,若是沒有應用懶加載,運用webpack打包後的文件將會異常的大,形成進入首頁時,須要加載的內容過多,延時過長,不利於用戶體驗,而運用懶加載則能夠將頁面進行劃分,須要的時候加載頁面,能夠有效的分擔首頁所承擔的加載壓力,減小首頁加載用時。」

方法一:resolve

vue-router配置路由 , 使用vue的異步組件技術 , 能夠實現按需加載 . 可是,這種狀況下一個組件生成一個js文件

代碼以下:

{
  path: '/login',
  name: 'login',
  component:function(resolve){
     require(['@/page/login.vue'],resolve)
  }
}

方法二:官網方法 import()

代碼以下:

{ 
	path: '/login',
	name: 'login',
	component:() => import('@/page/login')
}

方法三:webpack的require,ensure()

這種狀況下,多個路由指定相同的chunkName,會合並打包成一個js文件。

代碼以下:

path: '/login',
  name: 'login',
  component: r => require.ensure([], () => r(require('@/page/login')), 'demo')

4. 服務器開啓Gzip(compression-webpack-plugin)

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;

5. 生成環境剔除debuger和console(TerserPlugin/UglifyJsPlugin)

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']
          }
        }
      })
    }
}

6. 啓用CDN加速(configureWebpack,config.externals)

背景:在Vue項目中,引入到工程中的全部js、css文件,編譯時都會被打包進vendor.js,瀏覽器在加載該文件以後才能開始顯示首屏。如果引入的庫衆多,那麼vendor.js文件體積將會至關的大,影響首開的體驗。

解決方法:將引用的外部js、css文件剝離開來,不編譯到vendor.js中,而是用資源的形式引用,這樣瀏覽器可使用多個線程異步將vendor.js、外部的js等加載下來,達到加速首開的目的。

外部的庫文件,可使用CDN資源,或者別的服務器資源等。

步驟:

(1).配置要忽略的生產環境下被打包的文件

// 忽略生產環境打包的文件
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'
}

(2).定義不一樣環境下的cdn數據

具體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'
      ]
  }
}

(3).添加CDN參數到htmlWebpackPlugin配置中

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
})

(4).更改項目Router,Vuex,nprogress,mock,VueI18n等引入方式

意思是隻在開發環境引入相關的包,生產環境用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包。

7.首屏加個loading小菊花動畫;

性能優化先後的數據對比:

優化前:

優化後:

nginx服務器部署

項目開發完成後,咱們將進行服務器的部署;部署分爲:部署在跟目錄和部署在子目錄,這兩種狀況,前端publicPath配置也是不同的,不然,服務器資源會顯示404,沒法加載。

注意:本項目服務器爲 windows系統,因此如下配置爲windows系統配置;若是你是linux系統服務器,請參考linux服務器部署配置。

準備工做:

下載nginx服務器;

下載網址:請參考;選擇該穩定版本下載;下載完成後,將該文件上傳到你的服務器目錄並解壓。如圖:

運行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便可進行正常訪問;

nginx經常使用命令以下

  • 啓動服務:start nginx
  • 配置文件修改重啓服務:nginx -s reload
  • 快速中止或關閉Nginx:nginx -s stop
  • 正常中止或關閉Nginx:nginx -s quit
  • 查看Nginx的版本號:nginx -V
  • 查看windows任務管理器下Nginx的進程命令:tasklist /fi "imagename eq nginx.exe"

項目說明

小愛ADMIN是徹底開源免費的管理系統集成方案,能夠直接應用於相關後臺管理系統模板;不少重點地方都作了詳細的註釋和解釋。若是你也同樣喜歡前端開發,歡迎加入咱們的討論/學習羣,羣內能夠提問答疑,分享學習資料; 歡迎加入答疑qq羣。

技術答疑

原文出處:https://www.cnblogs.com/wdlhao/p/11427616.html

相關文章
相關標籤/搜索