vue composition and reusability

組件的組成和重用

Juo Penguin
6 min readAug 12, 2020

索引index

parent/children: 取得組件的上一層或下一層組件

mixins: 重用methods

extends: 擴充組件

provider/inject: context全域變數

slot: 為組件留位子

parent/children

在組件中透過this.$parent取得其父組件,用this.$children則是可以取得子組件

注意:必須謹慎使用,如果直接改變其parent/children的內部狀態,可能會導致無法預期的錯誤,一般仍是使用props/events去進行組件間的溝通

mixins

如果同一個方法會被用到好幾次,那麼這時候就可以考慮將其寫成mixin,讓各個組件都可以使用,如此一來就不必重複寫多次(clean code的不要重複自己原則),以及測試會更加簡單(只要測一次就好)

// 基本用法
const sayHelloMixin = {
mounted() { this.sayHello(); },
methods: {
sayHello() { console.log('Hi!!'); },
},
};
{
// ...
mixins: [
sayHelloMixin,
],
}

以優先順序來說,data優先於mixin中的值,當有一樣的key時,data會取代掉原本的值

// mixin with data
const commonDataMixin = {
data() {
return {
common: 'something from mixin.',
}
},
};
({
// ...
data() {
return {
common: 'something from component.',
}
},
mixins: [
commonDataMixin,
],
created() {
console.log(this.$data.common); // 'something from component.'
}
})

而created(), mounted() …等等 生命週期的方法,則是不會像data同樣的key被取代,而是會被儲存成function[],相關週期被觸發時function會被「依序」呼叫

const saySomethingWhenCreatedMixin = {
created() {
console.log('Hey from mixin!');
},
};
({
// ...
created() {
console.log('Yo from component!');
},
mixins: [
sayHelloMixin,
],
})
// 'Hey from mixin!' <== First, before component's created
// 'Yo from component!'

全域mixin,「所有」(包含引用的library)的組件都會被影響,因此需要非常謹慎使用,通常會使用在自訂option的情況,如以下範例

// global mixinconst globalMixin = {
created() {
const option = this.$options.someOption;
if(option) {
console.log(option);
}
},
};
Vue.mixin({ ...globalMixin, })new Vue({
someOption: 'option from component instance.'
})
// 'option from component instance.'

extends

等同於Vue.extends(),只是更加直接簡單地擴充component

const Text = { //... }const Title = {
extends: Text,
// ...
}

provide/inject

子組件能夠取得父組件provide的值,無論層級多深都可以取得,方便作為某一部份組件的共同狀態管理,類似react的context

provide: object | () => object

inject: string[] | { [key: string]: string | Symbol | object }

// Provider
<template>
<div>
<slot></slot>
</div>
</template>
const Provider = Vue.component({
provide: {
context: 'some value',
},
// ...
})
// inject child componentconst Child = Vue.component({
inject: ['context'],
created() {
console.log(this.context) // 'some value'
}
})
// wrap Child in Provider
<Provider>
<Child />
</Provider>

provide/inject可使用Symbol

const stateKey = Symbol()// provider
{
//...
provider() {
returu {
[stateKey]: 'some foo'
};
},
}
// child
{
inject: { stateKey },
}

可作為props的預設值(適用於2.2.1之後),

// props
{
inject: ['context'],
props: {
inputVal: {
default() { return this.context; },
}
}
}

// data
{
inject: ['context'],
data() {
return {
inputVal: this.context,
}
}
}

inject使用不同的key名字(像是子組件中使用的是a,而Provider中provide的是b)以及設定預設值
(適用於2.5.0之後)

// default value of inject(v2.5.0+){
inject: {
dataFromCtx: {
from: 'context', // Provider provide this
default: 'some default value',
// default: () => []
// if default is not string/number/undefined/null/boolean/Symbol, use a function.
}
}

--

--

Juo Penguin
Juo Penguin

Written by Juo Penguin

不挑食的雜食者,近期的目標是瘦10公斤。

No responses yet