### 優化
1、加載速度的優化
①雪碧圖---->base64、iconfont
②代碼壓縮
③圖片視頻壓縮
④cdn緩存
⑤路由懶加載(異步組件) 首頁引入的大文件進行分批次引入
2、運行效率優化
①減少http請求,頁面打開之后基本不涉及到數據更改
<keep-alive include="['a','b']" exclude="['a','b']"></keep-alive>
正常的組件切換的時候執行創建和銷毀,加上keep-alive后,組件保存到緩存中,不會執行創建和銷毀。
②數據本地化(localStorage session(可以用keep-alive代替) cookie)
a、發起ajax前,先看一下本地緩存有沒有,如果有就在緩存中取,如果沒有再發起請求
b、localStorage的二次封裝
(1)考慮兼容問題
(2)簡化讀取與存儲
(3)有時間限制
c、圖片懶加載
ui框架
插件:vue-lazyload
3、用戶體驗優化
①加載體驗
②加載的loading條
### 路由懶加載(異步組件)(router.js)
原理:將每個組件都打成一個包,這樣首頁引入的大文件就進行分批引入。
實現:將所有的同步組件引入方式改為異步組件引入方式。
// import Recommend from "pages/Recommend.vue"; // import Singer from "pages/Singer.vue"; // import Detail from "pages/Detail.vue"; // 改為路由懶加載方式引入:引入組件的方式從同步變為異步 const Recommend=()=>import("pages/Recommend.vue"); const Singer=()=>import("pages/Singer.vue"); const Detail=()=>import("pages/Detail.vue");
此時,npm run build后在dist/js中多一個 chunk-00e2fa9f.7be196b5.js 文件。注意:npm run build后dist/js中的map文件可以全部刪除。
### <keep-alive></keep-alive>(App.vue)
原理:<keep-alive>是vue的一個內置組件,被<keep-alive>包裹的組件,不會反復的經歷創建與銷毀,它在第一次創建后就會保存在緩存中,下次頁面切換時直接從緩存中讀取。
場景:頁面打開后,基本涉及到數據更改的組件用<keep-alive>包裹,<keep-alive>和<template>一樣,不會顯示在頁面上。
生命周期:加上keep-alive后產生的兩個生命周期:activated、deactivated
created() { console.log("歌手創建") }, mounted() { console.log("歌手掛載") }, activated() { console.log("歌手緩存激活,進入keep-alive") }, deactivated() { console.log("歌手緩存停用,離開keep-alive") },
第一次進入歌手頁面,會觸發創建、掛載、緩存激活,離開時觸發緩存停用,后面再進入和離開只會觸發緩存激活和緩存停用。這樣用keep-alive包裹的組件不進行數據請求了,以此來減少http請求,如果需要數據請求,在activated生命周期進行數據請求。
屬性:<keep-alive include="" exclude="" max=5></keep-alive>
include:包括,這里填寫的組件是將被緩存的組件,屬性值為字符串或正則
exclude:排除,這里填寫的組件是不需要被緩存的組件(實時更新的組件),屬性值為字符串或正則
max:最多能緩存多少個組件,屬性值為Number
注意:
1、include 和 exclude 屬性允許組件有條件地緩存。二者都可以用逗號分隔字符串、正則表達式或一個數組來表示:
<!-- 逗號分隔字符串 -->
<keep-alive include="a,b">
<component :is="view"></component>
</keep-alive>
<!-- 正則表達式 (使用 `v-bind`) -->
<keep-alive :include="/a|b/">
<component :is="view"></component>
</keep-alive>
<!-- 數組 (使用 `v-bind`) -->
<keep-alive :include="['a', 'b']">
<component :is="view"></component>
</keep-alive>
2、include和exclude不能同時使用
例子:App.vue中給router-view套上keep-alive標簽:
<keep-alive>
<router-view></router-view>
</keep-alive>
此時,在推薦和歌手組件來回切換的時候,在Network里的js,就會進行緩存,不會一直請求。
### 數據本地化:localStorage的二次封裝
思路:
(1)考慮兼容問題
(2)簡化讀取與存儲
(3)有時間限制
代碼實現:
①在utils中新建localStorage.js文件:
export default{ set(key,data,expiresTime){ let obj={ data:data, ctime:(new Date()).getTime(),//時間戳,同Date.now() expiresTime:expiresTime||1000*60*60 // 如果沒有傳過期時間,則設置過期時間一個小時 } localStorage.setItem(key,JSON.stringify(obj)); }, get(key){ let obj=JSON.parse(localStorage.getItem(key)); let getItem=(new Date()).getTime(); if(getItem-obj.ctime>=obj.expiresTime){ // 如果超時 localStorage.removeItem(key); return null; }else{ // 未超時 return obj.data; } } }
②main.js中引入並注冊到Vue對象中:
import LocalStorage from "utils/localStorage.js";
Vue.prototype.$localStorage=LocalStorage;
③在任意組件,如Singer.vue中,通過this.$localStorage對象可以使用set()和get():
this.$localStorage.set("name","吳小明") console.log(this.$localStorage.get("name"))
### 圖片懶加載插件:vue-lazyload(Singer.vue)
①下載依賴:
npm install vue-lazyload
②引入和添加配置項(main.js):
import VueLazyLoad from "vue-lazyload"; Vue.use(VueLazyLoad,{ preLoad:1.3, // 預加載 error:require("./assets/musicLogo.png"), // 錯誤時顯示 loading:require("./assets/musicLogo.png"), // 加載時顯示 attempt:1 // 每次加載多少張 });
③v-lazy指令(Singer.vue):
將需要圖片懶加載的img中 :src 替換為 v-lazy:
<img :src="info.avatar">
替換為
<img v-lazy="info.avatar">
此時,在Singer.vue中Network的img只加載了首屏的圖片,隨着屏幕滾動,加載更多的圖片。
### UI框架
pc端:iView框架:https://www.iviewui.com/
移動端:mint-ui
### mint-ui(Rank.vue)
①下載依賴:
npm install mint-ui
②main.js中做全局引入,任何組件都可以用:
import MintUI from "mint-ui"; import "mint-ui/lib/style.css"; Vue.use(MintUI);
③Rank.vue中引入想要使用的組件(Toast提示和loading條):
import {Toast,Indicator} from "mint-ui";
④設置Toast提示的按鈕和點擊事件:
<button @click="toast">toast</button> methods: { toast(){ Toast({ message:"點擊我了,操作成功", // 信息 position:"center", // 位置 duration:3000 // 持續時間 }); } }
⑤模擬數據加載時的loading條:
created() { Indicator.open({ text:"加載中", spinnerType:"fading-circle" }); setTimeout(() => { Indicator.close(); }, 2000); }
⑥在main.js中已經引入mint-ui和css文件的前提下,可以直接在組件中使用mt-button組件(Toast()需要在使用的時候在組件中進行引入):
<mt-button type="default">default</mt-button>
<mt-button type="primary">primary</mt-button>
<mt-button type="danger">danger</mt-button>
### 封裝加載loading條(Recommend.vue)
①創建Loading組件:
<template>
<div class="loading">
<img :src="img">
</div>
</template>
<script>
// 以base64的方式引入圖片
import img from "../assets/loading.gif";
export default {
data() {
return {
img:img
}
},
}
</script>
<style lang="less">
@import "~style/index.less";
.loading{
position: fixed;
top: 0;bottom: 0;
left: 0;right: 0;
margin: auto;
display: flex;
justify-content: center;
align-items: center;
img{
.w(30);
.h(30);
}
}
</style>
②Recommend.vue中引入組件,並且在data中聲明 loading:true
import Loading from "components/Loading.vue"; data() { return { loading:true, songList:[] } }
③對ul中數據進行loading條優化,Loading組件和ul是二選一的關系:
<Loading v-if="loading"></Loading> <ul v-else class="songList"> <!-- --> <li v-for="(item,index) in songList" :key="index" @click="goDateil(item.creator.encrypt_uin)"> <img :src="item.imgurl"> <div class="info"> <h2>{{item.creator.name}}</h2> <p>{{item.dissname}}</p> </div> </li> </ul>
④在拿到songList數據的同時,設置 this.loading=false;
axios.get(url,(err,data)=>{ }).then((data)=>{ this.songList=data.data.list; this.loading=false; });
### axios請求以post方式請求 x-www 格式的數據(demo)
原理:axios請求格式默認為json,有的時候需要請求 x-www-form-urlencoded 的格式,此時頁面會報404,需要將 content-type 屬性設置為 application/x-www-form-urlencoded ,再將data參數用qs.stringify()進行轉化。
①下載axios和qs依賴:
npm install axios qs
②main.js中引入axios,並設置給Vue:
import axios from "./utils/axios.js";
Vue.prototype.$axios=axios;
③根目錄下新建vue.config.js文件處理跨域:
module.exports={ devServer:{ port:8989, proxy:{ "/maoEr":{ target:"https://www.missevan.com",// 目標服務器路徑 changeOrigin:true,// 是否允許改變源,默認為true pathRewrite:{// 重寫路徑 "^/maoEr":"" } }, } } }
④App.vue中做數據請求(引入qs:import qs from "qs";):
mounted() { let url="/maoEr/site/getcomment"; let data={ order:1, pagesize:10, type:1, eId:1284079, p:1 } const options={ method:"POST", headers:{"content-type":"application/x-www-form-urlencoded"}, data:qs.stringify(data),// 需要下載qs依賴,npm i qs,node中queryString()有同樣效果 url:url, } this.$axios(options).then((data)=>{ console.log(data) }); }
注意:如果使用node中的queryString有一樣的效果,可以不用下載qs依賴。
①先引入queryString:
const querystring = require('querystring');
②
data:qs.stringify(data),
替換為
data:querystring.stringify(data),
### nginx代理(demo)
線上環境:npm run build 打包成一個靜態文件夾,丟到服務器目錄下,上線完成。
場景:解決npm run build之后的代理失效
原理:在vue.config.js中配置的代理服務器是由本地的npm run serve啟動的服務器做支持,而npm run build后的index.html沒有服務器支持,代理失效,數據請求全部失效。
注意:npm run build后的index.html直接打開會報錯,此時將其中所有的css和js文件前面加上 . ,表示當前路徑下。
步驟:
①下載nginx:http://nginx.org/en/download.html
②將dist文件夾拷貝到nginx/html文件夾中
③雙擊nginx.exe,cmd打開nginx目錄,輸入nginx -s reload,沒有報錯就成功了
④在地址欄輸入當前電腦的ip,可以進入welcome to nginx,相當於雙擊打開index.html,在地址后面加上 /dist 可以打開 npm run build 后的項目。此時打開Network,可以發現請求地址由 http://localhost:52330/maoEr/site/getcomment 變為 http://192.168.43.185/maoEr/site/getcomment
⑤nginx/conf/nginx.conf文件下設置跨域代理:
location /maoEr {
proxy_pass https://www.missevan.com/;#注意這個域名后面有 / ,如果是ip不用加 /
}
⑥遠程服務器上雙擊nginx.exe,nginx文件夾進入cmd,輸入nginx -s reload
nginx命令:
nginx -s reload
start nginx
nginx -s stop
### 前端攔截 前端安全
1、鑒權 token session+cookie
2、攔截 路由攔截器 路由守衛 路由導航
### 路由守衛
1、全局前置守衛(所有的路由跳轉都會經過這個函數):(router/index.js)
router.beforeEach((to,from,next)=>{ console.log("去哪里",to) console.log("從哪來",from) let token=false; if(to.name=="About"){ if(token){ next(); }else{ next("/login"); } }else{ next(); } })
場景:控制某些頁面未登錄情況下不可進,跳轉至登錄頁面。
2、路由獨享守衛(路由配置項中使用,只對當前路由起作用):(router/index.js)
{ path: '/login', name: 'Login', component: () => import('../views/Login.vue'), beforeEnter: (to, from, next) => { console.log("去哪兒",to) console.log("從哪來",from) next(); } }
3、組件內守衛:(About.vue)
(1)進入路由前(此時路由還沒有進來,組件未創建,沒有this):
beforeRouteEnter(to, from, next) { console.log("組件進入前") next(); }
(2)路由更新時:
組件復用時,例如用動態導航傳參(在路由中更改about的path為 /about/:id,通過params接收參數),在mounted生命周期中只有第一次能獲取到參數,這會造成在詳情頁的地址欄更換,但頁面不變。此時,可以用到beforeRouterUpdate(),可以用to.params.id獲取到參數。
beforeRouterUpdate(to, from, next) { console.log("組件更新",to.params.id) next(); }
另外,可以通過watch監聽獲取參數:
watch: { $route(newValue){ console.log("watch",newValue.params.id) } }
(3)路由離開時,可以在離開前做一些判斷:
beforeRouteLeave(to, from, next) { console.log("組件要離開",this) // console.log("去哪兒", to); // console.log("從哪來", from); let state = confirm("確定要離開嗎"); if (state) { next(); } }
### mint-ui下拉刷新,上拉加載更多
①下載依賴:
npm install mint-ui
②main.js中做全局引入:
import MintUI from "mint-ui" import "mint-ui/lib/style.css" Vue.use(MintUI)
③Home.vue中:
<template>
<div class="home">
這里是首頁
<mt-loadmore
:top-method="loadTop"
:bottom-method="loadBottom"
:bottom-all-loaded="allLoaded"
ref="loadmore"
>
<ul>
<li v-for="(item,index) in list" :key="index">{{item.name}}</li>
</ul>
</mt-loadmore>
</div>
</template>
<script>
export default {
data() {
return {
list: [
{ name: "AAA" },
{ name: "BBB" },
{ name: "CCC" },
{ name: "DDD" },
{ name: "EEE" },
{ name: "FFF" },
{ name: "RRR" },
{ name: "HHH" },
{ name: "NNN" }
],
allLoaded: false
};
},
methods: {
loadTop() {
let url = "/api/city/city/getHotCityList?version=6.0.4&referer=2";
this.$axios
.get(url, () => {})
.then(data => {
this.list = data.data.hot_city_List; // 拿到數據后讓頁面回到原位
this.$refs.loadmore.onTopLoaded();
});
},
loadBottom() {
setTimeout(() => {
this.list = this.list.concat([
{ name: "窗前明月光" },
{ name: "疑是地上霜" },
{ name: "舉頭望明月" },
{ name: "低頭思故鄉" }
]);
console.log(this.list);
this.allLoaded = false;
this.$refs.loadmore.onBottomLoaded();
}, 1000);
}
}
};
</script>
<style>
.home {
overflow: scroll; // 注意:如果上拉函數無法觸發,是因為這里沒有設置超出滾動
}
li {
height: 50px;
font-size: 20px;
}
.mint-loadmore-text {
font-size: 20px !important;
}
.mint-loadmore-content {
font-size: 20px !important;
}
</style>
### Q:
1、自己封裝過哪些組件和模塊?
組件:loading條的封裝
模塊:localStorage的二次封裝
