在單頁應用中常常要用到路由。 傳統的頁面跳轉是瀏覽器請求新的頁面,渲染整個新的頁面。 單頁應用是把要跳轉的頁面的以組件的形式集成在當前頁面中,跳轉時瀏覽器不用發起新請求,因為目標頁面是當前頁面的一部分,直接顯示目標頁面那一部分即可。 demo 在單頁應用中使用路由 1、下載路由插件 npm inst ...
在單頁應用中常常要用到路由。
傳統的頁面跳轉是瀏覽器請求新的頁面,渲染整個新的頁面。
單頁應用是把要跳轉的頁面的以組件的形式集成在當前頁面中,跳轉時瀏覽器不用發起新請求,因為目標頁面是當前頁面的一部分,直接顯示目標頁面那一部分即可。
demo 在單頁應用中使用路由
1、下載路由插件
npm install vue-router -S
install可以簡寫為i
我們要使用的是裡面的vue-router.js文件
2、寫一個test.html
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title></title> <!-- 引入vue.js --> <script src="js/vue.js"></script> <!-- 引入路由插件。上線時均要換為xxx.min.js --> <script src="js/vue-router.js"></script> </head> <body> <div id="app"></div> <script> // 首頁組件 var Index={ template:` <div> <p>this is the index page</p> <p><a href="#/login">login</a></p> <!-- 註意url寫法,#/開頭 --> <p><a href="#/register">register</a></p> </div> ` } // 登錄組件 var Login={ template:` <div> <p>this is the login page</p> <p><a href="#/index">index</a></p> <p><a href="#/register">register</a></p> </div> ` } // 註冊組件 var Register={ template:` <div> <p>this is the register page</p> <p><a href="#/index">index</a></p> <p><a href="#/register">register</a></p> </div> ` } // 安裝路由插件 Vue.use(VueRouter); // 創建路由對象 var router=new VueRouter({ // 配置路由規則 routes:[ //對象數組 {path:'/index',name:'index',component:Index}, //path指定映射地址,註意沒有#,component指定對應的組件 {path:'/login',name:'login',component:Login}, {path:'/register',name:'register',component:Register}, ] }); new Vue({ el:'#app', router, //啟用路由。原本是router:router,可以簡寫 template:` <div> <!--路由頁面只是當前頁面的一部分,當前頁面可以寫一些其他內容,寫的內容是所有路由頁面--> <p>this is common area</p> <router-view></router-view> <!--引入路由頁面。路由到哪個頁面,就用對應的組件替換這部分--> </div> ` }) </script> </body> </html>
3、運行
假設test.html的地址是:http://127.0.0.1:8848/vue/test.html#/ 註意後面有個#
則index的地址是:http://127.0.0.1:8848/vue/test.html#/index
login的地址是:http://127.0.0.1:8848/vue/test.html#/login
register的地址是:http://127.0.0.1:8848/vue/test.html#/register
3個頁面,但實際上路由的3個頁面都在test.html中。
<router-view></router-view>是一個路由容器,用來容納路由頁面。
單頁應用的兩種路由模式
- 哈希模式(利用
hashchange
事件監聽 url的hash 的改變)
- history模式(需要後臺配合把介面都打到我們打包後的.html文件上,比如上用test.html打包路由頁面,test.html相當於一個容器)
demo中使用的是哈希模式
哈希模式實現路由跳轉的原理
// 監聽地址欄url的改變,haschange是預定義事件 window.addEventListener("hashchange",function(e){ //haschange事件發生時,會封裝事件以參數的形式傳給處理函數 console.log(e); //這個對象的部分信息: {..., oldURL: "http://127.0.0.1:8848/vue/test.html#/index", newURL: "http://127.0.0.1:8848/vue/test.html#/register", type: "hashchange", …} console.log(location.hash); //地址欄的url已改變,獲取新的url的hash。帶有#/,比如#/index,#/login // console.log(location); //location是不帶#/的,比如index、login switch(location.hash){ //根據路由配置決定和哪些常量比較。這些常量就是路由配置中的path case '#/index': //... //如果匹配就用對應的組件替換<router-view></router-view>部分 break; case '#/login': break; case '#/register': break; } })
路由跳轉的3種方式
- <a>鏈接
- <router-link>標簽
- $router對象
new Vue({ el:'#app', router, template:` <div> <p> <a href="#/index">index</a> <!-- 要帶# --> <router-link to="/login">login</router-link> <!-- 不帶# --> <button @click="goRegister">register</button> </p> <router-view></router-view> </div> `, methods:{ goRegister(){ this.$router.push({path:'/register'}); //不帶# } } })
<router-link>、$router都是路由插件里的東西,都用路由了,那url中指定有#號,它自己會加#號,所以我們寫路徑的時候不加#號。
<a>是html的標簽,不知道url中有沒有#號,所以需要我們自己加上。
$router的常用方法
- push() 跳轉到指定的頁面,會往history中插入一條新紀錄
- replace() 和push()的用法、作用相同,只是replace()不會往history中插入一條新紀錄
- go(-1) 跳轉到history中的上一條記錄,相當於點擊瀏覽器的後退箭頭。
- forward(1) 跳轉到history中的下一條記錄,相當於點擊瀏覽器的前進箭頭。
$router還有個兄弟$route,和$router不同,$route封裝了路由信息,只有屬性(可以理解為是只讀的),常用的屬性比如hash、path、query、params。
路由的傳參和取參
1、<a>鏈接方式
// 首頁組件 var Index={ template:` <div> <p>this is the index page</p> <p>{{this.$route.query.username}} {{this.$route.query.username}}</p> <!-- 如果只在載入此組件時使用,直接取就行了 --> <p>{{username}} {{password}}</p> <!-- 如果後續還要使用,需要保存到記憶體變數中 --> </div> `, data(){ return{ username:'', password:'' } }, created(){ //路由到此組件|頁面時,會新建此組件的實例,在created()中獲取傳來的數據 this.username=this.$route.query.username; //$route,沒有r,a鏈接只能用query來取 this.password=this.$route.query.password; } } // 安裝路由插件 Vue.use(VueRouter); // 創建路由對象 var router=new VueRouter({ // 配置路由規則 routes:[ {path:'/index',name:'index',component:Index}, ] }); new Vue({ el:'#app', router, template:` <div> <a href="#/index?username=chy&password=abcd">index</a> <!-- 傳遞參數 --> <router-view></router-view> </div> ` })
參數以查詢字元串的形式拼接在url中:http://127.0.0.1:8848/vue/test.html#/index?username=chy&password=abcd
2、<router-link>方式有2種
(1)query
<!-- to前面有冒號,我這裡使用的是路由配置里的name。query --> <router-link :to="{name:'index',query:{username:'chy',password:'abcd'}}">index</router-link>
查詢字元串的形式拼接參數,獲取時也是$route.query的方式,url中會帶有參數:http://127.0.0.1:8848/vue/test.html#/index?username=chy&password=abcd
(2)params
<!--params,post方式--> <router-link :to="{name:'index',params:{username:'chy',password:'abcd'}}">index</router-link>
要用$route.params來接收,用什麼傳遞就用什麼接收。
url中不顯示參數,更安全:http://127.0.0.1:8848/vue/test.html#/index
params方式的路由配置還可以這樣寫:
// 創建路由對象 var router=new VueRouter({ // 配置路由規則 routes:[ {path:'/index/:username',name:'index',component:Index}, ] });
:參數名 可以獲取對應的參數值,http://127.0.0.1:8848/vue/test.html#/index/chy,url是RESTful風格
3、$router對象方式
new Vue({ el:'#app', router, template:` <div> <button @click="goIndex">index</button> <router-view></router-view> </div> `, methods:{ goIndex(){ this.$router.push({name:'index',query:{username:'chy',password:'abcd'}}); } } })
說明
<router-link>、$router對象方式,都可以使用query或params來傳遞參數,都可以使用path或name來指定路由頁面,
如果路由配置的path是: {path:'/index/:username',name:'index',component:Index} 這種隨參數的變化而變化的,那就使用name。
路由傳參參數不刷新的問題
現象
<router-link :to="{name:'index',params:{username:'chy1',password:'abcd1'}}">index</router-link> <router-link :to="{name:'index',params:{username:'chy2',password:'abcd2'}}">index</router-link>
比如第一次路由到index頁面,攜帶的參數是{username:'chy1',password:'abcd1'},
後續再路由到此頁面時,比如要攜帶的參數是{username:'chy2',password:'abcd2'},新的參數傳過去了,但使用的參數是第一次路由到此頁面時攜帶的參數。
即傳到同一路由頁面的參數不會刷新,3種方式都存在這個問題。
原因
Vue路由會復用組件,我把變數賦值寫在created()中,這個鉤子函數只在組件創建時執行,就是說變數賦值只執行1次(第一次路由到此頁面時)。
後續再次路由到此頁面時,新的參數是傳過去了,但變數賦值不會再執行,新的參數也就沒有賦給變數。
如果只在傳過去的時候使用參數,後面不再使用參數,可以 {{this.$route.query|params.參數名}} 直接取。
如果要把參數賦給變數,方便後續使用,該怎麼做?
2種解決方案
1、使用 :key 唯一標識一次路由
// 創建路由對象 var router=new VueRouter({ // 配置路由規則 routes:[ {path:'/index',name:'index',component:Index}, ] }); new Vue({ el:'#app', router, template:` <div> <router-link :to="{name:'index',query:{username:'chy1',password:'abcd1'}}">index</router-link> <router-link :to="{name:'index',query:{username:'chy2',password:'abcd2'}}">index</router-link> <router-view :key="$route.fullPath"></router-view> </div> `, })
query方式(<a>鏈接也是query方式),路由配置的寫為/index的形式
因為根據url的hash來判斷是否是同一個路由頁面,預設的:key是/index這種形式,會認為是同一個路由頁面;
現在設置:key="$route.fullPath"(註意P是大寫),以完整的url來判斷,query方式會在url中拼接參數,能區分不同的參數傳遞。
// 創建路由對象 var router=new VueRouter({ // 配置路由規則 routes:[ {path:'/index/:username',name:'index',component:Index}, ] }); new Vue({ el:'#app', router, template:` <div> <router-link :to="{name:'index',params:{username:'chy1',password:'abcd1'}}">index</router-link> <router-link :to="{name:'index',params:{username:'chy2',password:'abcd2'}}">index</router-link> <router-view :key="$route.fullPath"></router-view> </div> `, })
params方式,因為使用post傳遞參數,url中不帶參數,url(的hash)都是一樣的,怎麼區別?
路由配置的 path:'/index/:username' 中帶上唯一的參數標識,比如username、uid等,這樣url就不同了
說明
(1)此種方式,:key能唯一標識一次參數傳遞即可,不一定要是$route.fullPath,比如可以是:
:key="$route.fullPath" //完整的url
:key="$route.query|params.username|uid" //能唯一標識一次參數傳遞的參數
:key="new Date().getTime()" //時間戳(這個是毫秒級的)。使用時間戳時,就算2次路由的參數完全相同,也會重新創建路由頁面的組件
(2)此種方式,只要:key的值不同,就會重新創建路由頁面的組件,性能影響大,不太推薦。
2、數據監聽
// 首頁組件 var Index={ template:` <div> <p>this is the index page</p> <p>{{username}} {{password}}</p> </div> `, data(){ return{ username:'', password:'', } }, // created(){ //可以不要created() // this.username=this.$route.params.username; // this.password=this.$route.params.password; // }, watch:{ //監聽$route.query|params,當然直接監聽$route也行 '$route.params'(){ //因為有.號,所以要要引起來,不然識別不了 this.username=this.$route.params.username; //參數變化時就重新獲取參數 this.password=this.$route.params.password; } }, } // 安裝路由插件 Vue.use(VueRouter); // 創建路由對象 var router=new VueRouter({ // 配置路由規則 routes:[ {path:'/index/:username',name:'index',component:Index}, //query方式寫成/inedx,params方式寫成/index/:username ] }); new Vue({ el:'#app', router, template:` <div> <router-link :to="{name:'index',params:{username:'chy1',password:'abcd1'}}">index</router-link> <router-link :to="{name:'index',params:{username:'chy2',password:'abcd2'}}">index</router-link> <router-view></router-view> <!--不需要使用:key--> </div> `, })
這種方式,路由到同一個頁面時,會復用組件,不重新創建組件,開銷小,推薦。