首先什么是mvvm:
MVVM 是 Model-View-ViewModel的縮寫。mvvm 是一種設(shè)計思想。Model 層代表數(shù)據(jù)模型,也可以在 Model 中定義數(shù)據(jù)修改和操作的業(yè)務(wù)邏輯;View 代表 UI 組件,它負責將數(shù)據(jù)模型轉(zhuǎn)化成 UI 展現(xiàn)出來,ViewModel 是一個同步 View 和 Model 的對象。
在 MVVM 架構(gòu)下,View 和 Model 之間并沒有直接的聯(lián)系,而是通過 ViewModel 進行交互,Model 和 ViewModel 之間的交互是雙向的, 因此 View 數(shù)據(jù)的變化會同步到 Model 中,而 Model 數(shù)據(jù)的變化也會立即反應(yīng)到 View 上。
ViewModel 通過雙向數(shù)據(jù)綁定把 View 層和 Model 層連接了起來,而 View 和 Model 之間的同步工作完全是自動的,無需人為干涉,因此開發(fā)者只需關(guān)注業(yè)務(wù)邏輯,不需要手動操作 DOM, 不需要關(guān)注數(shù)據(jù)狀態(tài)的同步問題,復(fù)雜的數(shù)據(jù)狀態(tài)維護完全由 MVVM 來統(tǒng)一管理。
vue生命周期的理解:
總共分為 8 個階段創(chuàng)建前/后,載入前/后,更新前/后,銷毀前/后。
創(chuàng)建前/后: 在beforeCreate 階段,vue 實例的掛載元素 el 還沒有。
載入前/后:在 beforeMount 階段,vue 實例的$el 和 data 都初始化了,但還是掛載之前為虛擬的 dom 節(jié)點,data.message 還未替換。在 mounted 階段,vue 實例掛載完成,data.message 成功渲染。
更新前/后:當 data 變化時,會觸發(fā)beforeUpdate 和 updated 方法。
銷毀前/后:在執(zhí)行 destroy 方法后,對 data 的改變不會再觸發(fā)周期函數(shù),說明此時 vue 實例已經(jīng)解除了事件監(jiān)聽以及和 dom 的綁定,但是 dom 結(jié)構(gòu)依然存在。
vue的雙向綁定的原理:
vue.js 是采用數(shù)據(jù)劫持結(jié)合發(fā)布者-訂閱者模式的方式,通過 Object.defineProperty()來劫持各個屬性的 setter,getter,在數(shù)據(jù)變動時發(fā)布消息給訂閱者,觸發(fā)相應(yīng)的監(jiān)聽回調(diào)。
具體步驟:
- 第一步:需要 observe 的數(shù)據(jù)對象進行遞歸遍歷,包括子屬性對象的屬性,都加上 setter 和 getter 這樣的話,給這個對象的某個值賦值,就會觸發(fā) setter,那么就能監(jiān)聽到了數(shù)據(jù)變化。
- 第二步:compile 解析模板指令,將模板中的變量替換成數(shù)據(jù),然后初始化渲染頁面視圖,并將每個指令對應(yīng)的節(jié)點綁定更新函數(shù),添加監(jiān)聽數(shù)據(jù)的訂閱者,一旦數(shù)據(jù)有變動,收到通知,更新視圖。
- 第三步:Watcher 訂閱者是 Observer 和 Compile 之間通信的橋梁,主要做的事情是:
在自身實例化時往屬性訂閱器(dep)里面添加自己;
自身必須有一個 update()方法;
待屬性變動 dep.notice()通知時,能調(diào)用自身的 update() 方法,并觸發(fā) Compile 中綁定的回調(diào),則功成身退。 - 第四步:MVVM 作為數(shù)據(jù)綁定的入口,整合 Observer、Compile 和 Watcher 三者,通過 Observer 來監(jiān)聽自己的 model 數(shù)據(jù)變化,通過 Compile 來解析編譯模板指令,最終利用 Watcher 搭起 Observer 和 Compile 之間的通信橋梁,達到數(shù)據(jù)變化 -> 視圖更新;視圖交互變化(input) -> 數(shù)據(jù) model 變更的雙向綁定效果。
vuex相關(guān):
有 5 種屬性,分別是 state、getter、mutation、action、module。
- store 特性:
vuex 就是一個倉庫,倉庫里放了很多對象。其中 state 就是數(shù)據(jù)源存放地,對應(yīng)于一般 vue 對象里面的 data。
state 里面存放的數(shù)據(jù)是響應(yīng)式的,vue 組件從 store 讀取數(shù)據(jù),若是 store 中的數(shù)據(jù)發(fā)生改變,依賴這相數(shù)據(jù)的組件也會發(fā)生更新。
它通過 mapState 把全局的 state 和 getters 映射到當前組件的 computed 計算屬性。 - getter 特性:
getter 可以對 state 進行計算操作,它就是 store 的計算屬性。
雖然在組件內(nèi)也可以做計算屬性,但是 getters 可以在多給件之間復(fù)用。
如果一個狀態(tài)只在一個組件內(nèi)使用,是可以不用 getters。 - mutation 特性:
action 類似于 muation, 不同在于:action 提交的是 mutation,而不是直接變更狀態(tài)。
action 可以包含任意異步操作。
注冊全局組件:
在components下寫好test.vue組件模板,然后在main.js中引入再全局注冊:
import testel from './components/test';
Vue.component('testel ',testel );
vue組件之間的傳值:
- 父組件向子組件傳遞數(shù)據(jù)
//父組件通過標簽上面定義傳值
<template>
<Main :obj="data"></Main>
</template>
<script>
//引入子組件
import Main form "./main"
exprot default{
name:"parent",
data(){
return {
data:"我要向子組件傳遞數(shù)據(jù)"
}
},
//初始化組件
components:{
Main
}
}
</script>
//子組件通過props方法接受數(shù)據(jù)
<template>
<div>{{data}}</div>
</template>
<script>
exprot default{
name:"son",
//接受父組件傳值
props:["data"]
}
</script>
- 子組件向父組件傳遞數(shù)據(jù)
//子組件通過$emit方法傳遞參數(shù)
<template>
<div v-on:click="events"></div>
</template>
<script>
//引入子組件
import Main form "./main"
exprot default{
methods:{
events:function(params){
console.log(params)
}
}
}
</script>
<template>
<div v-on:click="emitEvent">{{data}}</div>
</template>
<script>
exprot default{
name:"son",
//接受父組件傳值
props:["data"],
methods: {
emitEvent() {
this.$emit('event', params) // 派發(fā)函數(shù),并傳遞值,params是你自己想傳的值
}
}
}
</script>
默認顯示子路由:
routes: [
{path: '/',
name: 'home',
component: home,
children: [{ path: '/echarts', name: 'echarts', component: echarts },
{ path: '/index', name: 'index',component: index}],redirect:'/index' }]
}] //通過redirect:'/index' 默認顯示index
Vue中使用echarts:
<template>
<!-- 定義一個承載容器 -->
<div id="chartshow" style=" height:500px;"></div>
</template>
<script>
import echarts from "echarts"; //引入echarts
//此外在main.js中還需要再引入echarts ,并按照官方的方式Vue.prototype.$echarts = echarts 使用.
export default {
data() {
return {
chartshow: null
};
},
methods: {
drawshowChart() {
this.chartshow = echarts.init(document.getElementById("chartshow"));
this.chartshow.setOption({
//以下是echarts的數(shù)據(jù)
tooltip: {
trigger: "item",
formatter: "{a} <br/>: {c} (u0z1t8os%)"
},
legend: {
orient: "vertical",
x: "left",
data: [
"直達",
"營銷廣告",
"搜索引擎",
"郵件營銷",
"聯(lián)盟廣告",
"視頻廣告",
"百度",
"谷歌",
"必應(yīng)",
"其他"
]
},
series: [
{
name: "訪問來源",
type: "pie",
selectedMode: "single",
radius: [0, "30%"],
label: {
normal: {
position: "inner"
}
},
labelLine: {
normal: {
show: false
}
},
data: [
{ value: 335, name: "直達", selected: true },
{ value: 679, name: "營銷廣告" },
{ value: 1548, name: "搜索引擎" }
]
},
{
name: "訪問來源",
type: "pie",
radius: ["40%", "55%"],
label: {
normal: {
formatter: "{a|{a}}{abg|}\n{hr|}\n {b|:}{c} {per|u0z1t8os%} ",
backgroundColor: "#eee",
borderColor: "#aaa",
borderWidth: 1,
borderRadius: 4,
rich: {
a: {
color: "#999",
lineHeight: 22,
align: "center"
},
hr: {
borderColor: "#aaa",
width: "100%",
borderWidth: 0.5,
height: 0
},
b: {
fontSize: 16,
lineHeight: 33
},
per: {
color: "#eee",
backgroundColor: "#334455",
padding: [2, 4],
borderRadius: 2
}
}
}
},
data: [
{ value: 335, name: "直達" },
{ value: 310, name: "郵件營銷" },
{ value: 234, name: "聯(lián)盟廣告" },
{ value: 135, name: "視頻廣告" },
{ value: 1048, name: "百度" },
{ value: 251, name: "谷歌" },
{ value: 147, name: "必應(yīng)" },
{ value: 102, name: "其他" }
]
}
]
});
}, //數(shù)據(jù)結(jié)束
drawCharts() {
this.drawshowChart();
}
}, //methods結(jié)束
mounted: function() {
this.drawCharts();
},
updated: function() {
this.drawCharts();
}
};
</script>