組件化是一門藝術,如何用好組件化優雅的實現頁面,是每一個前端開發的必修課,最近學了vue組件化的相關課程,本文就對經常使用的vue組件化技術的進行總結整理。前端
//父組件
<HelloWorld msg="Welcome to Your Vue.js App"/>
//子組件
props: { msg: String }
複製代碼
//父組件
<HelloWorld ref="hw"/>
this.$refs.hw.xx
複製代碼
//子組件
this.$emit('add', good)
//父組件
<Cart @add="cartAdd($event)"></Cart>
複製代碼
經過共同的祖輩組件搭橋,$parent
或$root
。vue
//兄弟組件1
this.$parent.$on('foo', handle)
//兄弟組件2
this.$parent.$emit('foo')
複製代碼
因爲嵌套層數過多,傳遞props不切實際,vue提供了provide / inject API完成該任務。vuex
//祖輩組件
<template>
<div id="app">
<router-view v-if="isRouterAlive" />
</div>
</template>
<script>
export default {
name: 'App',
data () {
return {
isRouterAlive: true
},
// 父組件中返回要傳給下級的數據
provide () {
return {
reload: this.reload
}
},
methods: {
reload () {
this.isRouterAlive = false
this.$nextTick(() => {
this.isRouterAlive = true
})
}
}
}
</script>
複製代碼
//孫組件
<template>
<popup-assign
:id="id"
@success="successHandle"
>
<div class="confirm-d-tit"><span class="gray-small-btn">{{ name }}</span></div>
<strong>將被分配給</strong>
<a
slot="reference"
class="unite-btn"
>
指派
</a>
</popup-assign>
</template>
<script>
import PopupAssign from '../PopupAssign'
export default {
//引用vue reload方法
inject: ['reload'],
components: {
PopupAssign
},
methods: {
async successHandle () {
this.reload()
}
}
}
</script>
複製代碼
provide / inject 的優勢:數組
provide / inject 的缺點:bash
provide 和 inject 主要在開發高階插件/組件庫時使用。並不推薦用於普通應用程序代碼中。app
// 定義一個dispatch方法,指定要派發事件名稱和數據
function dispatch(eventName, data) {
let parent = this.$parent
// 只要還存在父元素就繼續往上查找
while (parent) {
// 父元素用$emit觸發
parent.$emit(eventName,data)
// 遞歸查找父元素
parent = parent.$parent
}
}
// 使用,HelloWorld.vue
<h1 @click="dispatch('hello', 'hello,world')">{{ msg }}</h1>
// App.vue
this.$on('hello', this.sayHello)
複製代碼
建立一個Bus類負責事件派發、監聽和回調管理async
// Bus:事件派發、監聽和回調管理
class Bus{
constructor(){
this.callbacks = {}
}
$on(name, fn){
this.callbacks[name] = this.callbacks[name] || []
this.callbacks[name].push(fn)
}
$emit(name, args){
if(this.callbacks[name]){
this.callbacks[name].forEach(cb => cb(args))
}
}
}
// main.js
Vue.prototype.$bus = new Bus() // child1
this.$bus.$on('foo', handle) // child2
this.$bus.$emit('foo')
複製代碼
建立惟一的全局數據管理者store,經過它管理數據並通知組件狀態變動ide
插槽語法是Vue實現的內容分發API,用於複合組件開發,該技術在通用組件庫開發中有大量應用。函數
Vue 2.6.0以後採用全新v-slot語法取代以前的slot、slot-scope組件化
// comp1
<div>
<slot></slot>
</div>
// parent
<comp>hello</comp>
複製代碼
// comp2
<div>
<slot></slot>
<slot name="content"></slot>
</div>
// parent
<Comp2>
<!-- 默認插槽用default作參數 -->
<template v-slot:default>具名插槽</template>
<!-- 具名插槽用插槽名作參數 -->
<template v-slot:content>內容...</template>
</Comp2>
複製代碼
// comp3
<div>
<slot :foo="foo"></slot>
</div>
// parent
<Comp3>
<!-- 把v-slot的值指定爲做用域上下文對象 -->
<template v-slot:default="ctx">
來自子組件數據:{{ctx.foo}}
</template>
</Comp3>
複製代碼
做用於插槽能夠實現組件和業務的剝離,適合應用於至少包含三級以上的組件層級,是一種優秀的組件化方案。
有一個購物網站,網站裏有諸如 「猜你喜歡」,「每日特價」等商品列表,咱們能夠將這個頁面進行組件化拆分。
當咱們想要實現點擊具體商品跳轉到相應的詳情頁面,並但願該點擊能在ColumnList組件中實現時,傳統作法,會將在Commodity的點擊事件$emit
層層上拋至組件ColumnList,並在ColumnList中進行監聽。但這種方法,使得子組件與業務緊耦合,利用做用域插槽就能夠優雅的解決這個問題。
v-slot
屬性賦值上下文對象//父組件
<my-input type="text" autocomplete placeholder="Please input something"></my-input>
//子組件
<div>
<input v-bind="$attrs" />
</div>
export default {
inheritAttrs: false
}
//渲染結果
<div>
<input type="text" autocomplete placeholder="Please input something" />
</div>
複製代碼
inheritAttrs
:默認狀況下父做用域的不被認做 props 的特性綁定 (attribute bindings) 將會「回退」且做爲普通的 HTML 特性應用在子組件的根元素上。經過設置 inheritAttrs 到 false,這些默認行爲將會被去掉。$attrs
:包含了父做用域中不做爲 prop 被識別 (且獲取) 的特性綁定 (class 和 style 除外)。當一個組件沒有聲明任何 prop 時,這裏會包含全部父做用域的綁定 (class 和 style 除外),而且能夠經過 v-bind="$attrs" 傳入內部組件——在建立高級別的組件時很是有用。針對例如彈窗等短暫出現的組件,能夠經過一個實例建立函數進行調用。 優勢:
import Vue from 'vue';
export default function create(component, props) {
const vm = new Vue({
render(h) {
return h(component, {props});
}
}).$mount();
//vm.$el爲Vue實例使用的根DOM元素
document.body.appendChild(vm.$el);
//vm.$children爲當前實例的直接子組件
const comp = vm.$children[0];
comp.remove = function() {
document.body.removeChild(vm.$el);
vm.$destroy();
}
return comp;
}
複製代碼