Vue使用的擴展
1、事件總線(Bus)實現非父子組件通信
Vue2.0提供了Vuex進行非父子組件之間的通信,但在簡單的場景下,可以使用一個空的Vue實例作為中央事件總線。
實現代碼示例:
<div id="app"> <c1></c1> <c2></c2> </div>
var Bus = new Vue(); //為了方便將Bus(空vue)定義在一個組件中,在實際的運用中一般會新建一Bus.js Vue.component('c1',{ //這里以全局組件為例,同樣,單文件組件和局部組件也同樣適用 template:'<div>{{msg}}</div>', data: () => ({ msg: 'Hello World!' }), created() { Bus.$on('setMsg', content => { //監聽Vue示例 Bus 的某一個事件 this.msg = content; }); } }); Vue.component('c2',{ template: '<button @click="sendEvent">Say Hi</button>', methods: { sendEvent() { Bus.$emit('setMsg', 'Hi Vue!'); //觸發vue示例 bus 的某一個事件,并且將參數作為數據傳過去 } } }); var app= new Vue({ el:'#app' })
在實際運用中,一般將Bus抽離出來:
// Bus.js import Vue from 'vue' const Bus = new Vue() export default Bus
組件調用時先引入
// 組件1 import Bus from './Bus' export default { data() { return { ......... } }, methods: { .... Bus.$emit('log', 120) }, }
// 組件2 import Bus from './Bus' export default { data() { return { ......... } }, mounted () { Bus.$on('log', content => { console.log(content) }); } }
但這種引入方式,經過webpack打包后可能會出現Bus局部作用域的情況,即引用的是兩個不同的Bus,導致不能正常通信
1.1、推薦使用Bus的方式
(1)直接將Bus注入到Vue根對象中
import Vue from 'vue' const Bus = new Vue() var app= new Vue({ el:'#app', data:{ Bus } })
在子組件中通過this.$root.Bus.$on()、this.$root.Bus.$emit()來調用
(2)或者也可以通過將Bus放在vue示例的原型對象中使用
Vue.prototype.bus = new Vue();
每個組件都是一個Vue示例,所以每個組件都會有bus屬性,在組件中可以通過 this.bus.$emit、this.bus.$on 來調用
Vue.component('c2',{
template: '<button @click="sendEvent">Say Hi</button>',
methods: {
sendEvent() {
this.bus.$emit('setMsg', 'Hi Vue!');
}
}
});
參考:http://www.rzrgm.cn/fanlinqiang/p/7756566.html
2、Vue 動態插入組件
代碼示例:
<div id="app">
<p>{{ message }}</p >
<button @click="add('a-component', '我是A')">添加A組件</button>
<button @click="add('b-component', '我是B')">添加B組件</button>
<component :is="item.component" :text="item.text" v-for="item in items"></component>
</div>
js:
<script>
const aComponent = Vue.extend({
props: ['text'],
template: '<li>A Component: {{ text }}</li>'
})
const bComponent = Vue.extend({
props: ['text'],
template: '<li>B Component: {{ text }}</li>'
})
new Vue({
el: '#app',
data () {
return {
message: 'Hello Vue.js!',
items: []
}
},
methods: {
add (name, text) {
this.items.push({
component: name,
text: text
})
}
},
components: {
aComponent,
bComponent
}
})
</script>
Vue.extend 是構造一個組件的語法器。你給它參數它給你一個組件,然后這個組件你可以作用到Vue.component 這個全局注冊方法里, 也可以在任意vue模板里使用<apple>組件
var apple = Vue.extend({ .... }) Vue.component('apple',apple)
也可以作用到vue實例或者某個組件中的components屬性中并在內部使用apple組件
new Vue({ components:{ apple:apple } })
5、 語法糖
語法糖是指用另一種語法替換原先的比較復雜的語法,但實現的功能一樣,這種比較簡單清晰的語法被稱為語法糖。
vue 中的語法糖有:
- v-bind 的語法糖是:":"
- v-on 的語法糖是:"@"
- v-model 也是一個語法糖,v-model = "test" 的實際寫法可以寫成 :value = "test" @input = " test = $event.target.value "
- v-slot 的語法糖是:"#",該縮寫只有在有參數時才能用,比如具名插槽:<template #header> </template>
6、組件中的 name 屬性的作用
組件中是有 name 屬性的,組件的 name 屬性主要有以下幾個作用:
6.1、允許組件遞歸地引用本身
在自身組件調用自身的時候,可以通過定義name的值進行遞歸調用
<div>
<div v-for="(item,index) of list" :key="index">
<detail-list></detail-list>
</div>
</div>
export default {
name: 'DetailList', //組件可以利用 name 屬性遞歸地調用本身
props: {
list: [1,2,3]
}
}
6.2、使用 keep-alive 緩存組件
<!-- 失活的組件將會被緩存!--> // 下面的 is 后面的名字應該是組件的 name 屬性值 <keep-alive> <component v-bind:is="currentTabComponent"></component> </keep-alive>
組件在全局用 Vue.component() 注冊時,全局 ID 自動作為組件的 name。
<keep-alive> 要求被切換到的組件都有自己的名字,不論是通過組件的 name選項還是局部/全局注冊。
6.3、報錯警告信息明確,使用 vue-devtools 開發更易于調試
指定 name 選項的另一個好處是便于調試,有名字的組件有更友好的警告信息。
另外,當在有 vue-devtools,未命名組件將顯示成 <AnonymousComponent>,這很沒有語義。如果組件有 name 屬性,那在 vue-devtools 中顯示的將是 name 的值,組件樹更有語義。
8、關于父子組件props傳值的響應式修改問題
父子組件之間可以通過 props 進行傳值,在父組件中修改傳過去的值時,在子組件中接收到的 props 值都會隨之發生改變。但是如果把 props 的值賦值給 data 中的數據時,data 中的數據不一定會隨之改變。
當 props 值不是對象時,直接賦值給 data 屬性,data 屬性不會發生響應式改變。比如當 props 值是對象時,如果直接賦值給 data 屬性,data 屬性會發生響應式改變,如果將對象的某個屬性或者直接將某個基本類型值賦值給 data 屬性,此時子組件中該 data 屬性不會發生響應式改變。
總而言之,將對象賦值給 data 屬性會隨之發生改變,將基本類型值賦值給 data 屬性則不會發生響應式改變。
//父組件 parent.vue
<button @click="editName">點擊修改數據</button>
<item01 :name-prop="name" :human-prop="human" />
data() {
return {
name: 'wen',
human: {name: '人類'}
}
},
methods: {
editName () { //點擊修改傳過去的 props 值
this.name = 'hai'
this.human.name = '動物'
}
}
//子組件 child.vue
props: ['nameProp','humanProp'], //props值會響應式地發生改變
data() {
return {
myName: this.nameProp, //不是對象的值直接賦值給 data 屬性,此時不會發生響應式改變
myHuman: this.humanProp //對象直接賦值給 data 屬性,會發生響應式改變
myHumanName: this.humanProp.name //對象屬性賦值給 data 屬性,也不會發生響應式改變
}
}
{{nameProp}} -- {{humanProp}} //props值 都會響應式地發生改變
{{myName}} //data屬性 此時不會改變
{{myHuman.name}} //這里會改變
{{myHumanName}} //這里不會改變
請注意:是子組件中的 data 屬性的數據不會發生響應式改變,但 props 屬性的值都是會響應式改變的。所以如果你不需要修改傳過來的值的話,你也可以直接用 props 屬性的值,而不用賦值給 data 中的屬性值。
8.1、如何解決子組件接收的基本值類型的數據時不會發生響應式改變的問題
上面說到如果將值類型的 props 值賦值給 data 屬性時,data 屬性不會隨著父組件的數據的改變而發生改變,要想解決這個問題,可以通過監聽 props 的值,當 props 的某個值發生改變時,再將其賦值給 data 屬性。
//子組件 child.vue
{{myName}} //此時會發生響應式改變
props: ['name','human'], //props值會響應式地發生改變
data() {
return {
myName: this.name, //不是對象的值直接賦值給 data 屬性,此時不會發生響應式改變
}
},
watch: {
name (newVal, oldVal) { //通過監聽將新的props值賦值給data屬性
this.myName = newVal; //或者: this.myName = this.name
}
}
當然,如果不需要修改傳遞過來的值時,你也可以直接使用接收的 prop 的值進行操作,而無需賦值給組件的 data,這樣就不用監聽改變了。

浙公網安備 33010602011771號