Vue路由的實現(xiàn)原理
路由這個概念最初是由后端提出來的,在我們沒有SPA單頁面應用之前赦役,使用的一直都是后端路由麻敌,根據(jù)不同的路由返回不同的頁面,后來隨著單頁面應用的誕生掂摔,開始有了前端路由术羔,實現(xiàn)不刷新但是更新頁面的效果
vue-router是專為Vue打造的路由管理工具
vue-router提供三種路由模式
1.hash模式
- 默認模式,通過路徑中的hash值來控制路由跳轉(zhuǎn)乙漓,不存在兼容問題
2.history模式 - H5新增的 history API级历,相對hash而言,不會顯示#號叭披,但是需要服務器端配置
3.abstract模式 - 支持javascript的所有運行環(huán)境寥殖,常指Node.js服務器環(huán)境
hash模式實現(xiàn)原理
在正常路徑后跟一個 # 號,匹配 # 后邊的路徑為前端路由涩蜘,通過window.onhashchange方法來操控路由改變的時候切換內(nèi)容
2.onhashchange 方法的觸發(fā)時機
- 直接更改瀏覽器地址嚼贡,在最后面增加或改變#hash;
- 通過改變location.href或location.hash的值同诫;
- 通過觸發(fā)點擊帶錨點的鏈接粤策;
- 瀏覽器前進后退可能導致hash的變化,前提是兩個網(wǎng)頁地址中的hash值不同误窖。
2.示例代碼
<body>
<ul>
<li>
<a href="#/home">home</a>
</li>
<li>
<a href="#/list">list</a>
</li>
<li>
<a href="#/detail">detail</a>
</li>
</ul>
</body>
<script>
window.onhashchange = function() {
// 做頁面切換渲染等
console.log(location.href);
console.log(location.hash);
}
</script>
- 通過點擊a標簽叮盘,傳遞一個hash值秩贰,然后通過window.onhashchange方法來監(jiān)聽hash的變化,然后在這個事件觸發(fā)的時候柔吼,根據(jù)location.hash來動態(tài)的修改單頁面應用的內(nèi)容即可
history模式實現(xiàn)原理
看起來與后端路由沒有任何區(qū)別萍膛,在window.history這個對象中,包含瀏覽器的歷史嚷堡,而在HTML5中蝗罗,新增了pushState和replaceState,通過這兩個API可以改變url地址且不會發(fā)送請求蝌戒,同時還有popstate事件串塑,實現(xiàn)原理與hash相似,只不過因為沒有了 # 號北苟,所以刷新頁面還是會向服務器發(fā)送請求桩匪,而后端沒有對應的處理措施的話,會返回404友鼻,所以需要后端配合
- popstate方法的觸發(fā)時機
- 僅僅調(diào)用pushState方法或replaceState方法 傻昙,并不會觸發(fā)該事件;
- 只有用戶點擊瀏覽器倒退按鈕和前進按鈕彩扔,或者使用JavaScript調(diào)用back妆档、forward、go方法時才會觸發(fā)虫碉。
- 另外贾惦,該事件只針對同一個文檔,如果瀏覽歷史的切換敦捧,導致加載不同的文檔须板,該事件也不會觸發(fā)。
2.示例代碼
<body>
<ul>
<li>
<a href="/home">home</a>
</li>
<li>
<a href="/list">list</a>
</li>
<li>
<a href="/detail">detail</a>
</li>
</ul>
</body>
<script>
document.querySelectorAll('a').forEach(item => {
item.onclick = function (e) {
e.preventDefault();
let link = item.getAttribute('href');
window.history.pushState({link}, link, link);
};
});
window.addEventListener('popstate', function (e) {
console.log(e.state);
console.log(location.href);
})
</script>
- 當點擊瀏覽器的后退或前進按鈕兢卵,或者調(diào)用history上的go习瑰、back方法時,就會觸發(fā)事件秽荤,打印出對應的數(shù)據(jù)甜奄,e.state 中就存放著pushState方法中的state對象
- 通過在修改路由信息的同時執(zhí)行切換DOM的操作,來實現(xiàn)了路由切換
abstract模式實現(xiàn)原理
- abstract模式是不依賴于瀏覽器環(huán)境王滤,所以沒有使用hash或者history等瀏覽器才會提供的API贺嫂,而是VueRouter內(nèi)部使用數(shù)組進行模擬了路由管理,在node環(huán)境雁乡,或者原生App環(huán)境下第喳,都會默認使用abstract模式,VueRouter內(nèi)部會根據(jù)所處的環(huán)境自行判斷踱稍,默認使用hash模式曲饱,如果檢測到?jīng)]有瀏覽器API的時候悠抹,就會使用abstract模式。
SPA 路由history模式上線后刷新404
1.出現(xiàn)問題:在使用history模式的時候扩淀,由于瀏覽器路徑與后端路徑類似楔敌,所以當刷新頁面的時候,瀏覽器還是會向服務器發(fā)送請求驻谆,但是由于服務器并沒有對應的路由頁面卵凑,所以會導致404空白
2.解決方案:在服務端增加一個覆蓋所有情況的候選資源:如果 URL 匹配不到任何靜態(tài)資源,則應該返回同一個 index.html 頁面胜臊,這個頁面就是你 app 依賴的頁面勺卢。同時這么做以后,服務器就不再返回 404 錯誤頁面象对,因為對于所有路徑都會返回 index.html 文件黑忱。為了避免這種情況,在 Vue 應用里面覆蓋所有的路由情況勒魔,然后在給出一個 404 頁面甫煞。或者冠绢,如果是用 Node.js 作后臺抚吠,可以使用服務端的路由來匹配 URL,當沒有匹配到路由的時候返回 404唐全,從而實現(xiàn)后退埃跷。
1.node服務器
- 簡單粗暴的一種方法蕊玷,如果沒有讀取到靜態(tài)資源就直接返回html頁面邮利,可以用于前端調(diào)試
const http = require('http');
const fs = require('fs');
http.createServer((req,res) => {
fs.readFile(__dirname + req.url, (err, data) => {
if(!err) {
res.end(data);
}else {
fs.readFile('index.html', (e, html) => {
if(!e) {
res.end(html);
}
})
}
})
}).listen(8080, err => {
!err&&(console.log('http://localhost:8080')
})
2.nginx靜態(tài)服務器
- 常用方式,直接使用80端口
server {
listen 80;
server_name localhost;
location / {
root html;
index index.html;
try_files $uri $uri/ /index.html;
}
}
- 在nginx安裝目錄下垃帅,將打包后的文件放置在安裝目錄下的 html 目錄中延届,接著打開conf目錄中的nginx.conf文件,修改server部分如上贸诚,然后在nginx根目錄使用nginx -t測試配置文件修改后的語法是否正確(如果有問題會報錯)方庭,如果沒有錯誤的話,使用命令nginx -s reload命令重啟讓配置文件生效酱固,打開瀏覽器械念,輸入localhost即可看到項目部署完成
- 常用方式,同時運行多個程序時运悲,80端口被占用時
server {
listen 8000;
server_name localhost;
location / {
root html/project;
index index.html;
try_files $uri $uri/ /index.html;
}
}
- 在html目錄下新建文件夾龄减,例如project,將打包后的文件放置在project文件夾下班眯,在conf/nginx.conf文件中希停,原80端口的下方新加入上述代碼烁巫,接著重復nginx -t與nginx -s reload再次打開瀏覽器,輸入localhost:8000就可以看到項目部署完成
$$route和$router的區(qū)別
1.route來獲取當前路由的各種參數(shù)
1.path String 保存當前絕對路徑信息
2.params Object 保存當前的params參數(shù)對象
3.hash String 保存當前的hash信息,不帶#號肴楷,如果沒有hash為空字符串
4.query Object 保存當前的query參數(shù)對象
5.meta Object 保存當前路由的源信息
6.fullPath String 保存完成解析后的路徑信息水由,包含hash、query等參數(shù)
7.name String 保存路由name值
2.$router是路由實例對象赛蔫,包含的是VueRouter實例上的方法以及配置屬性砂客,常用于編程式導航;
1.push Function(Object|String)
- this.$router.push('/home?tab=all')
- this.$router.push({path: '/home', query:{tab:'all'}})
2.replace Function(Object|String)
- this.$router.replace('/home?tab=all')
- this.$router.replace({path: '/home', query:{tab:'all'}})
3.go Function(Number)
this.$router.go(-1) 操作history的API進行后退
this.$router.go(1) 操作history的API進行前進
自定義過濾器詳解
1.在Vue1.x的版本中呵恢,是有內(nèi)置過濾器的鞠值,而到了2.0以后,廢除了內(nèi)置過濾器渗钉,允許我們自定義過濾器
2.自定義過濾器的使用方法
- 在插值表達式{{}}以及v-bind:指令綁定的屬性的冒號內(nèi)彤恶,可以使用自定義過濾器
- 使用時,在js表達式的結(jié)尾使用管道符來指示過濾器
- 示例: {{date| formatDate}} 或者 <input v-bind:value="date | formatDate" />
3.自定義過濾器的使用場景 - 在我們前端拿到后臺的數(shù)據(jù)時鳄橘,經(jīng)常有些數(shù)據(jù)是不能直接展示出來的声离,需要經(jīng)過處理之后再展示,在Vue中瘫怜,我們可以通過methods來做术徊,也可以通過computed計算屬性來做,但是最好還是通過過濾器filters來做鲸湃,因為它是在原數(shù)據(jù)基礎(chǔ)上進行過濾赠涮,不會修改原有數(shù)據(jù),使用computed以及methods屬于大材小用了
4.過濾器的定義 - 在Vue中分為全局過濾器和局部過濾器
// 全局過濾器
Vue.filter(過濾器名稱, function(value) {
return value; // 處理value暗挑,vlaue就是需要過濾的數(shù)據(jù)
})
// 局部過濾器
new Vue({
el: '#app',
filters: {
'過濾器名稱'(value) {
return value; // 處理value笋除,vlaue就是需要過濾的數(shù)據(jù)
}
}
})
5.實現(xiàn)自定義過濾器
1.無參數(shù)過濾器
Vue.filter('formatDate', function(value) {
if(!value) return;
return new Date(value).toLocaleString();
})
// html
<div>{{ 1562731217574 | formatDate }}</div>
2.有參數(shù)過濾器
Vue.filter('formatPrice', function(value, num) {
if(!value) return;
return value.toFixed(num);
})
// html
<div>{{ 15.6264 | formatPrice(2)}}</div>
3.多個參數(shù)的過濾器
Vue.filter('formatText', function(value, start, end) {
if(!value) return;
return start + '-' + value + '-' + end;
})
// html
<div>{{ '中間' | formatText('開始','結(jié)束')}}</div>
4.過濾器串聯(lián),可以多個串聯(lián)
<div>{{ '中間' | formatText('開始','結(jié)束') | formatText('串聯(lián)start','串聯(lián)end') }}</div>
assets和static/public的區(qū)別
在vue-cli工具中炸裆,有兩個存放靜態(tài)資源的目錄垃它,一個是src目錄下的assets,另一個在vue-cli2下是static目錄,在vue-cli3下是public目錄嗤瞎,那這兩個目錄的區(qū)別是什么呢墙歪?
首先需要知道:在.vue組件中,所有的templates和css都會被vue-html-loader 和 css-loader解析贝奇,尋找資源的URL虹菲。
例如: <img src="./assets/logo.png">或者 background: url('./assets/logo.png'),這兩個url路徑都會被webpack解析成資源模塊依賴掉瞳,而由于這些靜態(tài)文件大都不是js文件毕源,而vue-cli工具利用各種loader幫助我們解析了這些資源
資源處理規(guī)則
1.相對路徑, ./assets/logo.png 將會被解析成一個模塊依賴。
2.沒有前綴的路徑, assets/logo.png 將會被看成./assets/logo.png進行解析模塊依賴
3.前綴帶~的URL 會被當成模塊請求, 例如:<img src="~assets/logo.png">
4.相對根目錄的URL/assets/logo.png 是不會被處理的
javascript中使用靜態(tài)資源
- 例如:imgUrl: require('./assets/logo.png')
assets和static/public的區(qū)別
- 在assets目錄下的靜態(tài)資源會被webpack解析成資源模塊依賴陕习,在項目打包的時候會隨著項目一起打包
- 而在static/public目錄下的靜態(tài)資源不會被解析霎褐,是真正的靜態(tài)資源
本文CSDN地址:前端面試題(六)