1 Vue路由的兩種模式
小白回答:hash模式url帶#號,history模式不帶#號
大牛解答:hash模式url裏面永遠帶着#號,我們在開發當中默認使用這個模式。那麼什麼時候要用history模式呢?如果用戶考慮url的規範那麼就需要使用history模式,因爲history模式沒有#號,是個正常的url適合推廣宣傳。當然其功能也有區別,比如我們在開發app的時候有分享頁面,那麼這個分享出去的頁面就是用vue或是react做的,咱們把這個頁面分享到第三方的app裏,有的app裏面url是不允許帶有#號的,所以要將#號去除那麼就要使用history模式,但是使用history模式還有一個問題就是,在訪問二級頁面的時候,做刷新操作,會出現404錯誤,那麼就需要和後端人配合讓他配置一下apache或是nginx的url重定向,重定向到你的首頁路由上就ok啦。
hash與history的區別:
hash | history | |
---|---|---|
url顯示 | 有#,很Low | 無#,好看 |
回車刷新 | 可以加載到hash值對應頁面 | 一般就是404掉了 |
支持版本 | 支持低版本瀏覽器和IE瀏覽器 | HTML5新推出的API |
hash模式
我們先來認識下這位朋友#,這個#就是hash符號,中文名哈希符或錨點,當然這在我們前端領域姑且這麼稱呼。
然後哈希符後面的值,我們稱之爲哈希值。OK,接下來我們繼續分析他的原理。路由的哈希模式其實是利用了window可以監聽onhashchange事件,也就是說你的url中的哈希值(#後面的值)如果有變化,前端是可以做到監聽並做一些響應(搞點事情),這麼一來,即使前端並沒有發起http請求他也能夠找到對應頁面的代碼塊進行按需加載。
後來人們給他起了一個霸氣的名字叫前端路由,成爲了單頁應用標配。
history模式
我們先介紹一下H5新推出的兩個神器:pushState與replaceState
具體自行百度,簡而言之,這兩個神器的作用就是可以將url替換並且不刷新頁面,好比掛羊頭賣狗肉,http並沒有去請求服務器該路徑下的資源,一旦刷新就會暴露這個實際不存在的“羊頭”,顯示404。
那麼如何去解決history模式下刷新報404的弊端呢,這就需要服務器端做點手腳,將不存在的路徑請求重定向到入口文件(index.html),前後端聯手,齊心協力做好“掛羊頭賣狗肉”的完美特效。
總之,pushState方法不會觸發頁面刷新,只是導致history對象發生變化,地址欄會有反應。
history模式下,build之後本地 index.html 打開是無效的。
hash模式下,build之後本地 index.html 打開正常!
2 Vue組件之間如何傳值
-
父組件向子組件傳值:
父組件:
<template> <div class="parentOne"> <children-item :content="item" v-for="item in list" :key="item.id"></children-item> </div> </template> <script> import ChildrenItem from "../children/ChildrenOne.vue" export default { name: "ParentOne", data() { return { list: [ { id: "001", title: "這是父組件第一項內容" }, { id: "002", title: "這是父組件第二項內容" }, { id: "003", title: "這是父組件第三項內容" } ] } }, components: { "children-item": ChildrenItem } } </script> <style> </style>
**在父組件中使用子組件,並且在子組件中添加需要傳遞的值
:content="item"**
子組件:
<template> <div class="ChildrenOne"> <ul> <li v-for="childItem in content">{{childItem}}</li> <li>{{message}}</li> </ul> </div> </template> <script> export default { name: 'ChildrenOne', props: ["content"], data() { return { message: this.content.id } } } </script> <style></style>
在子組件中添加props數組,接收從父組件中傳遞過來的
content
值,然後就可以在上邊的template中像使用data中的數據一樣使用props中的接收值,從而實現父組件向子組件的傳值 -
子組件向父組件傳值:
子組件向父組件傳值這一個技術點有個專業名詞,叫做“發佈訂閱模式”,很明顯在這裏子組件爲發佈方,而父組件爲訂閱方
子組件:
<template> <div class="ChildrenTwo"> <ul> <li v-for="childItem in content" @click="ChildrenOnclick()">{{childItem}}</li> </ul> </div> </template> <script> export default { name: 'ChildrenTwo', props: ["content", "index"], data() { return { } }, created() { console.log(this.index); }, methods: { ChildrenOnclick() { console.log(this.index); // 發佈訂閱模式 this.$emit("delete", this.index) } } } </script> <style> </style>
在該子組件中中觸發li的
click
事件,調用ChildrenOnclick
方法,在該方法中通過使用$emit
方法定義了一個delete
方法,並傳遞index值給父組件父組件:
<template> <div class="parentTwo"> <children-item :content="item" :index="index" v-for="(item,index) in list" :key="item.id" @delete="handleParentClick" > </children-item> </div> </template> <script> import ChildrenItem from "../children/ChildrenTwo.vue" export default { name: "ParentTwo", data() { return { list: [ { id: "001", title: "這是父組件第一項內容" }, { id: "002", title: "這是父組件第二項內容" }, { id: "003", title: "這是父組件第三項內容" } ] } }, methods: { handleParentClick(index) { this.list.splice(index, 1); } }, components: { "children-item": ChildrenItem } } </script> <style> </style>
在父組件使用子組件時,使用子組件中自定義的
delete
方法實現接收到子組件傳遞過來的值@delete="handleParentClick"
,調用handleParentClick
方法將傳遞的值作爲參數傳入父組件 -
兄弟(或者沒有關係)組件的組件傳值:
-
建立中轉站:bus.js
-
在需要引用的地方引入bus.js
import bus from '@/bus.js'
兄弟組件2:
<template> <div id="two"> <h3>小弟組件</h3> <p> <button @click="say">給大哥說話</button> </p> </div> </template> <script> // 引入bus.js進來 import bus from '@/bus.js' export default { name: 'Two', methods: { // 實現給大哥傳遞數據的 say () { // 讓bus調用自己的事件 bus.$emit('receive', '1000元保護費') } } } </script> <style lang="less" scoped> #two{ width: 300px; height: 100px; border:1px solid greenyellow; } </style>
在兄弟組件2小弟組件中,通過
click
事件調用say方法,在say方法裏再調用bus.$emit
,向receive
事件傳遞值1000元保護費
兄弟組件1:
<template> <div id="one"> <h3>大哥組件</h3> <span>接收小弟的禮物:{{money}}</span> </div> </template> <script> // 引入bus.js進來 import bus from '@/bus.js' export default { name: 'One', // 在created中給bus綁定事件,時機最靠前,隨時可以響應使用 data () { return { // 接收小弟來到數據 money: '' } }, created () { // this:組件實例對象 // 注意:設置爲箭頭函數 bus.$on('receive', val => { // val:是其他應用處給傳遞的數據 // 把獲得的數據賦予money this.money = val }) } } </script> <style lang="less" scoped> #one{ width: 300px; height: 100px; border:1px solid red; margin-bottom:20px; } </style>
在兄弟組件1大哥組件中,在created()方法裏調用
bus.$on
,執行receive
方法,接收小弟組件傳遞過來的值(1000元保護費
),然後進行其他操作,這樣就完成了兄弟組件之間的值傳遞提一筆:只要沒有直接套用關係的組件都是兄弟
-
3 MVC與MVVM的區別
MVVM與MVC最大的區別就是:MVVM實現了View和Model的自動同步,也就是當Model的屬性改變時,我們不用再自己手動操作Dom元素,來改變View的顯示,而是改變屬性後該屬性對應View層顯示會自動改變
進一步理解
一、MVC
MVC允許在不改變視圖的情況下改變視圖對用戶輸入的響應方式,用戶對View的操作交給了Controller處理,在Controller中響應View的事件調用Model的接口對數據進行操作,一旦Model發生變化便通知相關視圖進行更新。
? 如果前端沒有框架,只使用原生的html+js,MVC模式可以這樣理解。將html看成view;js看成controller,負責處理用戶與應用的交互,響應對view的操作(對事件的監聽),調用Model對數據進行操作,完成model與view的同步(根據model的改變,通過選擇器對view進行操作);將js的ajax當做Model,也就是數據層,通過ajax從服務器獲取數據。
二、MVVM
MVVM與MVC最大的區別就是:它實現了View和Model的自動同步,也就是當Model的屬性改變時,我們不用再自己手動操作Dom元素,來改變View的顯示,而是改變屬性後該屬性對應View層顯示會自動改變。
這裏我們拿典型的MVVM模式的代表,Vue,Vue實例中的data相當於Model層,而ViewModel層的核心是Vue中的雙向數據綁定,即Model變化時VIew可以實時更新,View變化也能讓Model發生變化。
整體看來,MVVM比MVC精簡很多,不僅簡化了業務與界面的依賴,還解決了數據頻繁更新的問題,不用再用選擇器操作DOM元素。因爲在MVVM中,View不知道Model的存在,Model和ViewModel也觀察不到View,這種低耦合模式提高代碼的可重用性。
這裏只是簡單地說一下區別,詳細的可以參考以下文章:
https://www.jianshu.com/p/b0aab1ffad93
https://blog.csdn.net/u013282174/article/details/51220199
https://www.jianshu.com/p/f07cf01056b1
4 Vue的生命週期
啥也先別說,開局一張圖:
Vue的生命週期可以分爲以下八個階段:
beforeCreate 實例創建前
created 實例創建完成
beforeMount 掛載前
mounted 掛載完成
beforeUpdate 更新前
updated 更新完成
beforeDestory 銷燬前
destoryed 銷燬完成
-
BeforeCreated:
這個鉤子是new Vue()之後觸發的第一個鉤子,在當前階段中data、methods、computed以及watch上的數據和方法均不能被訪問。
-
created
這個鉤子在實例創建完成後發生,當前階段已經完成了數據觀測,也就是可以使用數據,更改數據,在這裏更改數據不會觸發updated函數。可以做一些初始數據的獲取,注意請求數據不易過多,會造成白屏時間過長。在當前階段無法與Dom進行交互,如果你非要想,可以通過vm.$nextTick來訪問Dom。
-
Beforemounted
這個鉤子發生在掛載之前,在這之前template模板已導入渲染函數編譯。而當前階段虛擬Dom已經創建完成,即將開始渲染。在此時也可以對數據進行更改,不會觸發updated。
-
mounted
這個鉤子在掛載完成後發生,在當前階段,真實的Dom掛載完畢,數據完成雙向綁定,可以訪問到Dom節點,使用
$ref
屬性對Dom進行操作。也可以向後臺發送請求,拿到返回數據。 -
BeforeUpdate
這個鉤子發生在更新之前,也就是響應式數據發生更新,虛擬dom重新渲染之前被觸發,你可以在當前階段進行更改數據,不會造成重渲染。
-
updated
這個鉤子發生在更新完成之後,當前階段組件Dom已完成更新。要注意的是避免在此期間更改數據,因爲這可能會導致無限循環的更新。
-
BeforeDestroy
這個鉤子發生在實例銷燬之前,在當前階段實例完全可以被使用,我們可以在這時進行善後收尾工作,比如清除計時器。
-
destroyed
這個鉤子發生在實例銷燬之後,這個時候只剩下了dom空殼。組件已被拆解,數據綁定被卸除,監聽被移出,子實例也統統被銷燬。
提一筆:
在使用生命週期時有幾點注意事項需要我們牢記。
1.第一點就是上文曾提到的created階段的ajax請求與mounted請求的區別:前者頁面視圖未出現,如果請求信息過多,頁面會長時間處於白屏狀態。
2.除了beforeCreate和created鉤子之外,其他鉤子均在服務器端渲染期間不被調用。
3.上文曾提到過,在updated的時候千萬不要去修改data裏面賦值的數據,否則會導致死循環。
4.Vue的所有生命週期函數都是自動綁定到this的上下文上。所以,你這裏使用箭頭函數的話,就會出現this指向的父級作用域,就會報錯。
Vue生命週期先寫到這兒吧,發現需要寫的東西很多,後期專門寫一篇Vue生命週期的博文
5 Vue-Router有哪幾種導航鉤子
全局前置守衛:
const router = new VueRouter({ ... })
router.beforeEach((to, from, next) => {
// ...
})
全局解析守衛:
你可以用 router.beforeResolve 註冊一個全局守衛。這和 router.beforeEach 類似,
區別是在導航被確認之前,同時在所有組件內守衛和異步路由組件被解析之後,解析守衛就被調用。
全局後置鉤子:
你也可以註冊全局後置鉤子,然而和守衛不同的是,這些鉤子不會接受 next 函數也不會改變導航本身:
router.afterEach((to, from) => {
// ...
})
路由獨享的守衛:
const router = new VueRouter({
routes: [
{
path: '/foo',
component: Foo,
beforeEnter: (to, from, next) => {
// ...
}
}
]
})
組件內的守衛:
你可以在路由組件內直接定義以下路由導航守衛:
const Foo = {
template: `...`,
beforeRouteEnter (to, from, next) {
// 在渲染該組件的對應路由被 confirm 前調用
// 不!能!獲取組件實例 `this`
// 因爲當守衛執行前,組件實例還沒被創建
},
beforeRouteUpdate (to, from, next) {
// 在當前路由改變,但是該組件被複用時調用
// 舉例來說,對於一個帶有動態參數的路徑 /foo/:id,在 /foo/1 和 /foo/2 之間跳轉的時候,
// 由於會渲染同樣的 Foo 組件,因此組件實例會被複用。而這個鉤子就會在這個情況下被調用。
// 可以訪問組件實例 `this`
},
beforeRouteLeave (to, from, next) {
// 導航離開該組件的對應路由時調用
// 可以訪問組件實例 `this`
}
}
6 路由之間怎麼跳轉
聲明式–<router-link :to="{name:'index',query:{id:'xxx',name:'xxx'}}">
編程式–this.$router.push({name:‘組件名’)};
7 Vue全家桶都有哪些
Vue-cli 項目構建工具;vue-router 路由;vuex 狀態管理;axios http請求工具;webpack
這題感覺沒啥意思,但目錄都寫好了,不想重新改了…
8 Vue和Jquery的區別有哪些
區別一:
1).jQuery是一個類庫,提供了很多的方法,不能算框架,在過去和現在Jquery是最流行的web前端js庫,可是現在無論國內還是國外,他的使用率正在漸漸被其他的js庫所替代。隨着瀏覽器廠商對H5規範統一遵循以及ECMA6在瀏覽器端的實現,jquery的使用率會越來越低。
2).vue的介紹:vue是一個剛興起不久的前端框架,有一套完整的體系,是一個精簡的MVVM。從技術角度講,vue.js專注於MVVM模型的ViewModel層,通過雙向數據綁定把view層和Model層連接起來,通過對數據的操作就可以完成對頁面視圖的渲染。
區別二:
1).jQuery是直接操作DOM的;使用選擇器($)選取DOM對象,對其進行賦值、取值、事件綁定等操作;
和原生的js區別只在於可以更方便的選取和操作DOM對象;? 數據和界面是在一起,比如獲取input標籤的內容
? 2)vue基於一種MVVM模式,使用數據驅動的方式,通過Vue對象將數據和View完全分離開來。
? 對數據進行操作,不在需要引用相應的DOM對象,通過vue對象,將數據和相應的DOM對象相互綁定起來。
區別三
? 1).JQuery適用的場景:JQuery側重樣式操作,比如一些H5的動畫頁面;需要js來操作頁面樣式的頁面? 2).Vue適用的場景:vue側重數據綁定,比如複雜數據操作的後臺頁面;表單填寫頁面
9 v-if和v-show的區別
v-if是通過動態創建或者移除元素實現動態切換 v-show是通過控制元素的css樣式display:none樣式實現切換 一般來說,v-if 有更高的切換消耗 而 v-show 有更高的初始渲染消耗。 因此,如果需要頻繁切換 v-show 較好,如果在運行時條件不大可能改變 v-if 較好。
10 Vue封裝組件的流程
-
建立組件模板
-
通過props接收外部數據
-
在需要的模塊中引入該組件,使用該組件,最終在網頁中輸出組件與數據
這個在網上沒有找到比較好的文章,所以是自己根據自己爲數不多的封裝小組件的經驗寫的,如果大家有更好的更規範的流程,可以在下方評論,我及時更新
11 methods和watch,computed的區別
- computed–computed是在HTML DOM加載後馬上執行的,如賦值;computed計算屬性是基於它們的依賴進行緩存的,調用函數時,只要依賴的數據沒發生改變時,會直接從緩存中拿數據,不會再次執行函數
- methods–methods則必須要有一定的觸發條件才能執行,如點擊事件;只要發生重新渲染,method 調用總會執行該函數。
- watch–檢測一個數據的變化;對應一個對象,鍵是觀察表達式,值是對應回調。值也可以是方法名,或者是對象,包含選項。
- 執行順序–先computed再watch,不執行methods;等觸發某一事件後,則是:先methods再watch。
12 如何解決SPA應用首屏加載過慢
-
將全局引入轉換爲按需引入文件
-
在 config/index.js 文件中將productionSourceMap 的值設置爲false. 不生成映射資源
-
路由懶加載:懶加載即組件的延遲加載,通常vue的頁面在運行後進入都會有一個默認的頁面,而其他頁面只有在點擊後才需要加載出來,使用懶加載可以將頁面中的資源劃分爲多份,從而減少第一次加載的時候耗時
這種優化,就是將每個組件的js代碼獨立出來,在使用到這個組件時,才向服務器請求文件,並且請求過一次後就會緩存下來,再次使用到這個組件時,就會使用緩存,不再發送請求
-
壓縮css和js文件
-
使用cdn託管(就是把原服務器上數據複製到其他服務器上,用戶訪問時,哪臺服務器近訪問到的就是哪臺服務器上的數據。)
13 Vue項目對SEO不友好的解決方法
開局一張圖:
先分析下原因:
1.搜索引擎的基礎爬蟲的原理就是抓取你的url,然後獲取你的html源代碼並解析。 而你的頁面通常用了vue等js的數據綁定機制來展示頁面數據,爬蟲獲取到的html是你的模型頁面而不是最終數據的渲染頁面,所以說用js來渲染數據對seo並不友好。
2.seo 本質是一個服務器向另一個服務器發起請求,解析請求內容。但一般來說搜索引擎是不回去執行請求到的js的。也就是說,如果一個單頁應用,html在服務器端還沒有渲染部分數據數據,在瀏覽器才渲染出數據,而搜索引擎請求到的html是沒有渲染數據的。 這樣就很不利於內容被搜索引擎搜索到。 所以服務端渲染就是儘量在服務器發送到瀏覽器前 頁面上就是有數據的。
3.一般的數據邏輯操作是放在後端的。排序這個如果僅僅是幾條數據,前後端排序開起來是一樣的,如果是有1000條數據,前端要排序就要都請求過來。這樣顯然是不合理的。
常用的解決方案:
1.頁面預渲染
2.服務端渲染
3.路由採用h5 history模式
大廠如何做優化的呢?
1) bilibili做了基本的seo優化,比如
(1)TDK描敘詳細。
(2)提升網頁加載速度:對外聯css,以及js使用了延遲加載以及dns-prefetch,preload。
(3)外聯較多,關鍵詞排名高。2) 掘金網站使用了vue-meta-info 管理網站的meta,應該配合使用了prerender-spa-plugin 對SEO進行了優化
3) Element在logo上加了首頁的地址,並且只有logo是放在h1標籤中。
4) 有一些流量不太高的網站比如http://www.marshall.edu (Marshall University)做了seo社會化分享優化,在meta信息中出現了property=”og:title”這種新東西;https://we.dji.com/zh-CN/campus (大疆招聘)使用了Nuxt
這些網站中出現率最高的公共組件或公共方法有四個:
1) 麪包屑導航
2) Icon
3) 搜索框
4) Button組件關於收錄問題:
搜索引擎判斷一個網站權重高低的尺度無非兩個:收錄和外鏈。因此百度收錄的高低很大程度上影響着網站在百度的排名
目前百度spider抓取新鏈接的途徑有兩個:
一是主動出擊發現抓取;
二就是從百度站長平臺的鏈接提交工具中獲取數據,其中通過主動推送功能“收”上來的數據最受百度spider的歡迎。
對於站長來說,如果鏈接很長時間不被收錄,建議嘗試使用主動推送功能,尤其是新網站,主動推送首頁數據,有利於內頁數據的抓取。
參考文章:
https://blog.csdn.net/codeliuguisheng/article/details/79634422
https://blog.csdn.net/chjj0904/article/details/79388438
@_@
博文參考文章:
https://blog.csdn.net/wang1006008051/article/details/81805932
https://blog.csdn.net/fifteen718/article/details/82529433
https://www.imooc.com/article/257885
https://juejin.im/post/5d1b464a51882579d824af5b