1.Vue的雙向數據綁定原理是什么?
答案:vue.js是采用數據劫持結合發布者-訂閱者模式的方式,通過Object.defineProperty()
來劫持各個屬性的setter,getter,在數據變動時發布消息給訂閱者,觸發相應的監聽回調。
具體步驟:
第一步:需要observe的數據對象進行遞歸遍歷,包括子屬性對象的屬性,都加上setter,getter
這樣的話,給這個對象的某個值賦值,就會觸發setter,那么就能監聽到了數據變化.
第二步:compile解析模板指令,將模板中的變量替換成數據,然后初始化渲染頁面視圖,並將每個
指令對應的節點綁定更新函數,添加監聽數據的訂閱者,一旦數據有變動,收到通知,更新視圖.
第三步:Watcher訂閱者是Observer和Compile之間通信的橋梁,主要做的事情是:
1.在自身實例化時往屬性訂閱器(dep)里面添加自己
2.自身必須有一個update()方法
3.待屬性變動dep.notice()通知時,能調用自身的update()方法,並觸發Compile中綁定的回調,
則功成身退。
第四步:MVVM作為數據綁定的入口,整合Observer、Compile和Watcher三者,通過Observer來
監聽自己的model數據變化,通過Compile來解析編譯模板指令,最終利用Watcher搭起Observer和
Compile之間的通信橋梁,達到數據變化->視圖更新:視圖交互變化(input)->數據model變更的雙向綁定效果.
2.請詳細說下你對vue生命周期的理解
答案:總共分為8個階段創建前/后,載入前/后,更新前/后,銷毀前后。
創建前/后:beforeCreated階段,vue實例的掛載元素$el和數據對象data
都為undefined,還未初始化。在created階段,Vue實例的數據對象data有了,
$el還沒有。
載入前/后:在beforeMount階段,vue實例的$el和data都初始化了,但還是掛載之前
為虛擬DOM節點,data.message還未替換。在mounted階段,vue實例掛載完成,
data.message成功渲染。
銷毀前/后:在執行destory方法后,對data的改變不會再觸發周期函數,說明此時vue
實例已經解除了事件監聽以及和dom的綁定,但是dom結構依然存在.
3.封裝vue組件的過程.
答案:首先,組件可以提升整個項目的開發效率。能夠把頁面抽象成多個相對獨立的模塊,
解決了我們傳統項目開發:效率低、難維護、復用性性等問題。
然后,使用Vue.extend方法創建一個組件,然后使用Vue.component方法注冊組件。
子組件需要數據,可以在props中接收定義。而子組件修改好數據后,想把數據傳遞給父組件。
可以采用emit方法。
4.mvc和mvvm
答案:
MVC 模型-視圖-控制器(Model-View-Controller) Model和View永遠不能相互通信,
只能通過Controller傳遞。
Controller可以直接與Model對話(讀寫調用Model),Model通過Nottification和KVO機制
與Controller間接通信。
Controller可以直接與View對話,通過outlet,直接操作View,outlet直接對應到View中的控件,
View通過action向Controller報告事件的發生(如用戶Touch我了)
Controller是View的直接數據源(數據很可能是Controller從Model中取得並經過加工了)。
Controller是View的代理(delegate),以同步View與Controller。
MVVM
Model - ViewModel - View
什么是MVVM:一個MVC的增強版,我們正式連接了視圖和控制器,並將表示邏輯從Controller移
出放到一個新的對象里,即ViewModel。MVVM聽起來很復雜,但它本質上就是一個精心優化的
MVC架構。
Model層是少不了的了,我們得有東西充當DTO(數據傳輸對象),當然,用字典也是可以的,
編程么,要靈活一些。Model層是比較薄的一層,如果學過Java的小伙伴的話,對JavaBean應該不陌生.
ViewModel層,就是View和Model層的粘合劑,他是一個放置用戶輸入驗證邏輯,視圖顯示邏輯,發起網絡請求
和其他各種各樣的代碼的極好的地方。說白了,就是把原來ViewController層的業務邏輯和頁面邏輯
等剝離出來放到ViewModel層。
View層,就是ViewController層,他的任務就是從ViewModel層獲取數據,然后顯示。
5.Vue首屏加載非常慢,如何解決?
答案:Vue首屏加載非常慢.
原因:當打包應用時,將所有JavaSript代碼打包在一個文件中,導致js代碼非常龐大,嚴重影響了頁面加載速度。
1.配置打包工具,將組件分別打包到不同的js代碼塊中
build/webpack.base.config.js
output:{
path:config.bulid.assetsRoot,
filename:'[name].js',
//新增
chunkFilename:"[name].js",
publicPath:process.env.NODE_ENV=="production"
?config.bulid.assetsPublicPath
:config.dev.assetsPublicPath
}
2.當路由請求到該組件時,才動態加載組件的內容
路由字典中,路由配置和以前完全一樣
但是在引入組件對象時:
import Index from '@/views/Index.vue'
改為
const Index=()=>import('@/views/Index.vue')//僅定義函數暫未執行
//暫時不引人Index.vue
當用戶在Vue中請求當前組件對應的路由地址時,由vue-router自動調用加載函數,
動態請求Index.vue組件對象
6.實現訂閱/發布者模式?
答案:
var ublisher={ };
//定義發布者
publish.list=[];
//緩存列表 存放訂閱者回調函數
// 增加訂閱者
publisher.listen =function(fn){
publisher.list.push(fn);
// 訂閱消息添加到緩存列表
}
// 發布消息
publisher.trigger =function(){
for(vari = 0,fn; fn = this.list[i++];){
var that =this
fn.apply(null,arguments);
}
}
7. 什么是虛擬DOM樹:
答案:
什么是: 僅包含可能變化的節點和可能變化的屬性的樹結構
<body>
<div id=”app”>
<img src=”logo.png”> alt title id ….
<h1>{{uname}}</h1>id class title name
<hr>
<h2>{{score}}</h2>
</div>
{
el:”#app”,
children:[
{el:”h1”, innerText:uname},
{el:”h2”,innerText:score}
]
}
為什么: 內容少,便於快速遍歷比較不同
如何發揮作用:
當data中模型變量改變時,會通知虛擬DOM樹
虛擬DOM樹先緩存本次的修改在元素對象上
將一批修改生成新的DOM子樹和原虛擬DOM樹做對比。
一旦發現不同的元素或內容,就只更新有修改的元素
虛擬DOM樹中,封裝了傳統DOM API: createElement() appendChild() .innerHTML,避免了程序員編寫大量重復的代碼。
8. Vue 如何去除url中的 #
答案:
vue-router 默認使用 hash 模式,所以在路由加載的時候,項目中的 url 會自帶 #。如果不想使用 #, 可以使用 vue-router 的另一種模式 history
new Router({
mode: 'history',
routes: [ ]
})
需要注意的是,當我們啟用 history 模式的時候,由於我們的項目是一個單頁面應用,所以在路由跳轉的時候,就會出現訪問不到靜態資源而出現 404 的情況,這時候就需要服務端增加一個覆蓋所有情況的候選資源:如果 URL 匹配不到任何靜態資源,則應該返回同一個 index.html 頁面
9. Vue組件間如何通信
答案:
組件通信
父組件向子組件通信
子組件通過 props 屬性,綁定父組件數據,實現雙方通信
子組件向父組件通信
將父組件的事件在子組件中通過 $emit 觸發
非父子組件、兄弟組件之間的數據傳遞
/*新建一個Vue實例作為中央事件總嫌*/
let event = new Vue();
/*監聽事件*/
event.$on('eventName', (val) => {
//......do something
});
/*觸發事件*/
event.$emit('eventName', 'this is a message.')