1 props emit
Vue組件間的響應式通信方式之一,數據通過props以單向數據流的形式從父組件流動到子組件中。
單向流動性會防止子組件意外改變父級組件的狀態,避免應用的數據流向難以理解。
不能處理非父子組件通信的情況
父傳子 props
通過bind指令,父組件數據單向下行流向子組件的props
子傳父 $emit
子組件拋發事件a並傳入數據作為形參,在父組件掛載結點的子組件標簽中監聽a事件.
由於父級模板里的所有內容都是在父級作用域中編譯的,因此a事件的回調函數寫在父組件的methods里面.
methods中拿到形參后用this設置給data數據,這樣就完成子組件到父組件的傳遞
<div id="app">
<h1>{{username}}</h1>
<myinput :value="username" @myinput="inputHandler"></myinput>
</div>
<script>
const myinput = ('my-input', {
props:['username'],
template: `<input type='text' :value='username' @input="myemit">`,
methods:{
myemit(){
console.log(this.$el.value);
this.$emit("myinput",this.$el.value);
}
}
});
var vm = new Vue({
el: "#app",
data: {
username: 'aaa'
},
methods: {
inputHandler(val) {
this.username = val;
}
},
components: {
myinput
}
});
</script>
2 邊界條件
邊界條件主要通過vue的三個實例屬性實現根組件,父組件,子組件之間的數據傳遞
vm.$parent:當前組件的父實例.
vm.$root:組件樹的根實例,如果沒有父實例,vm.$root指向自己.
vm.$refs:注冊過 ref 特性 的所有 DOM 元素和組件實例.
ref 與 $ref
ref用於給子元素或子組件注冊引用信息
$ref
是非響應式的,在組件渲染完成之后生效,只能用於父組件拿到子組件實例,不能跨級
任意設置了ref屬性的子組件標簽,都可以在其父組件中通過this.$refs.refvalue
拿到對應的實例
<body>
<div id="app">
<son ref="getSon"></son>
</div>
<script>
const son = {
template: `
<h1>
parent-----{{this.$parent.print}}
<br>
root-------{{this.$root.print}}
</h1>
`,
data() {
return {
print: "this is son"
}
},
}
var vm = new Vue({
el: "#app",
data: {
print: 'this is root'
},
components: {
son
},
mounted() {
console.log(this.$refs.getSon.print);
}
});
</script>
</body>
3 依賴注入
作為組件數據傳遞的一種方式,依賴注入允許我們提供給任何后代組件的數據。
只需要在父組件中通過provide函數返回一個數據對象,就可以在后代組件中使用inject注入provide提供的數據,實現組件數據的通信。
依賴注入的特點在於,不局限於父子組件,不論多深的嵌套關系,都可以用它實現組件數據之間的通信。
還有一點值得注意,依賴注入是非響應式的。
<body>
<div id="app">
<son></son>
</div>
<script>
const grandson = {
inject: ['getApple'],
template: `
<h2>get -{{getApple}}- from grandfather</h2>
`
}
const son = {
template: `
<h1>
<grandson></grandson>
</h1>
`,
components: {
grandson
}
}
var vm = new Vue({
el: "#app",
data: {
apple: 'a fresh apple'
},
provide: function () {
return {
getApple: this.apple
}
},
components: {
son
}
});
</script>
</body>
4 eventbus 事件總線
使用一個全局的vue實例作為載體,通過這個載體去監聽和拋發事件
將需要傳遞的數據放入$emit函數的參數列表,只要在某一組件中監聽了此事件,就可以通過回調函數拿到此數據。
基於此,通過事件總線,可以實現非父子組件之間的數據通信,如兄弟級、跨級組件通信。
<body>
<div id="app">
<son ></son>
<button @click="giveFoodHandler">拋發事件</button>
</div>
<script>
var eventbus = new Vue();
const grandson = {
template: `
<h2 >get -{{getApple}}- from grandfather</h2>
`,
data() {
return {
getApple: ""
}
},
created(){
eventbus.$on("getFood",(apple)=>{
this.getApple = apple;
})
}
}
const son = {
template: `
<h1>
<grandson></grandson>
</h1>
`,
components: {
grandson
}
}
var vm = new Vue({
el: "#app",
data: {
apple: 'a fresh apple'
},
components: {
son
},
methods: {
giveFoodHandler() {
eventbus.$emit("getFood", this.apple);
}
}
});
</script>
</body>
5 vuex 狀態管理
vuex是vue的狀態管理模式,它的核心是store倉庫對象,它主要用於存放應用的狀態.
在Vuex中,更改狀態的唯一方式是mutation,mutation是同步的,
異步邏輯需要放在action中,但它最后也需要commit到mutation中實現狀態的更改,
使用store的commit與dispatch來進行組件之間的響應式數據狀態管理.
<body>
<div id="app">
<counter-btn type="decrement"></counter-btn>
<counter-span></counter-span>
<counter-btn type="increment"></counter-btn>
</div>
<script>
Vue.component('counter-btn', {
props: ['type'],
template: `
<button @click='handleClick' >{{btntext}}</button>
`,
computed: {
btntext() {
return this.type === 'decrement' ? '-' : '+';
}
},
methods: {
handleClick() {
if (this.type === 'decrement') {
store.commit('decrement', { num: 1 });
return;
}
this.$store.dispatch('increment', { num: 1 });
}
}
});
Vue.component('counter-span', {
template: `<span>{{$store.state.count}}</span>`,
});
var store = new Vuex.Store({
state: {
count: 0
},
//同步
mutations: {
increment(state, obj) {
state.count += obj.num;
},
decrement(state, obj) {
state.count -= obj.num;
}
},
// 異步
actions: {
increment(state, obj) {
setTimeout(() => store.commit('increment', obj), 0);
}
}
});
var vm = new Vue({
el: "#app",
store
});
</script>
</body>
總結
pros emit:
優點:
響應式
單向數據流防止子組件意外改變父級組件的狀態,常用於父子組件通信
缺點:
但是單行向下的bind+props在父子嵌套過多的場景下顯得過於繁瑣。
無法運用在非父子組件通信的場景中
邊界條件
優點:
使用起來較為方便,在子組件標簽上增加ref屬性即可使用
缺點:
在組件渲染完成之后生效
非響應式
依賴注入
優點:
不像props emit用起來那么繁瑣
祖先組件不需要知道那些后代組件使用它提供的屬性,后代組件也不需要知道被注入的屬性來自哪里。
不局限於父子組件,不論多深的嵌套關系,都可以用它實現組件數據之間的通信。
缺點:
但這樣的方式也有一個明顯的缺陷,那就是不支持響應式
事件總線
優點:
eventbus是全局的,意味着可以在任意兩個組件中通過事件的拋發和監聽來傳遞數據。
缺陷:
不支持響應式
vuex
優點:
通過store狀態管理,可以靈活的在父子/非父子/兄弟組件之間進行響應式數據傳遞
缺點
刷新瀏覽器會使得vuex中的state置為初始狀態,考慮結合本地存儲如localstorage進行使用
如果數據不存在跨組件共享,那么也不建議使用vuex
vuex不適合小型項目