vue自定義組件總結(jié)

組件系統(tǒng)是Vue.js其中一個重要的概念,它提供了一種抽象,讓我們可以使用獨立可復(fù)用的小組件來構(gòu)建大型應(yīng)用,任意類型的應(yīng)用界面都可以抽象為一個組件樹。

一、四個核心組成

1、props 2、自定義事件 event 3、插槽及作用域插槽 slot 4、組件方法 method。
任何組件均離不開以上4點,我們在開發(fā)過程中,以這4點入手,封裝我們想要的組件。

以element-ui table組件為例

Table Attributes 指的是 props
props data 顯示的數(shù)據(jù)

Table Events 指的是 自定義事件
自定義事件 selection-change 當選擇項發(fā)生變化時會觸發(fā)該事件

Table Slot 插槽
append 插入至表格最后一行之后的內(nèi)容,如果需要對表格的內(nèi)容進行無限滾動操作,可能需要用到這個 slot。若表格有合計行,該 slot 會位于合計行之上。

Table-column Scoped Slot 插槽及作用域插槽 slot
Table-column 是 el-table-column組件,有一個默認插槽 自定義列的內(nèi)容,參數(shù)為 { row, column, $index }

我們通常這樣使用

<el-table-column
    fixed="right"
    label="操作"
    width="100">
      <template slot-scope="scope">
        <el-button @click="handleClick(scope.row)" type="text" size="small">查看</el-button>
        <el-button type="text" size="small">編輯</el-button>
      </template>
</el-table-column>

slot-scope="scope" 父組件通過scope訪問子組件作用域。
Table Methods 指的是 組件方法
組件方法 clearSelection 用于多選表格,清空用戶的選擇 。 組件方法是通過 添加ref 索引,獲取組件實例后調(diào)用。this.$refs.組件ref標識.組件方法

以上是組件核心概念。

二、組件注冊

1、組件名
組件名應(yīng)該始終是多個單詞的,根組件 App 除外

這樣做可以避免跟現(xiàn)有的以及未來的 HTML 元素相沖突,因為所有的 HTML 元素名稱都是單個單詞的。

單文件組件的文件名應(yīng)該要么始終是單詞大寫開頭 (PascalCase),要么始終是橫線連接 (kebab-case)

混用文件命名方式有的時候會導(dǎo)致大小寫不敏感的文件系統(tǒng)的問題,這也是橫線連接命名同樣完全可取的原因

使用 kebab-case
當使用 kebab-case (短橫線分隔命名) 定義一個組件時,你也必須在引用這個自定義元素時使用 kebab-case,例如 <my-component-name>

Vue.component('my-component-name', { /* ... */ })

使用 PascalCase
當使用 PascalCase (駝峰式命名) 定義一個組件時,你在引用這個自定義元素時兩種命名法都可以使用。也就是說 <my-component-name> 和 <MyComponentName> 都是可接受的。注意,盡管如此,直接在 DOM (即非字符串的模板) 中使用時只有 kebab-case 是有效的

Vue.component('MyComponentName', { /* ... */ })

2、全局注冊
以上方法都屬于全局注冊, 也就是說它們在注冊之后可以用在任何新創(chuàng)建的 Vue 根實例 (new Vue) 的模板中, 比如

HTML

<div id="app">
  <component-a></component-a>
  <component-b></component-b>
  <component-c></component-c>
</div>

JS

Vue.component('component-a', { /* ... */ })
Vue.component('component-b', { /* ... */ })
Vue.component('component-c', { /* ... */ })
 
 
new Vue({ el: '#app' })

在所有子組件中也是如此,也就是說這三個組件在各自內(nèi)部也都可以相互使用.

3、局部注冊

如果不需要全局注冊,或者是讓組件使用在其它組件內(nèi),可以用選項對象的 components 屬性實現(xiàn)局部注冊, 這里不做詳述。

三、父子組件通信

在vue組件通信中其中最常見通信方式就是父子組件之中的通信,而父子組件的設(shè)定方式在不同情況下又各有不同。最常見的就是父組件為控制組件子組件為視圖組件。父組件傳遞數(shù)據(jù)給子組件使用,遇到業(yè)務(wù)邏輯操作時子組件觸發(fā)父組件的自定義事件。無論哪種組織方式父子組件的通信方式都是大同小異

父組件到子組件通訊

父組件到子組件的通訊主要為:子組件接受使用父組件的數(shù)據(jù),這里的數(shù)據(jù)包括屬性和方法(String, Number, Boolean, Object, Array, Function)。vue提倡單項數(shù)據(jù)流,因此在通常情況下都是父組件傳遞數(shù)據(jù)給子組件使用,子組件觸發(fā)父組件的事件,并傳遞給父組件所需要的參數(shù)

通過 props 傳遞數(shù)據(jù) (推薦)

父子通訊中最常見的數(shù)據(jù)傳遞方式就是通過props傳遞數(shù)據(jù),就好像方法的傳參一樣,父組件調(diào)用子組件并傳入數(shù)據(jù),子組件接受到父組件傳遞的數(shù)據(jù)進行驗證使用

props 可以是數(shù)組或?qū)ο?,用于接收來自父組件的數(shù)據(jù)。props 可以是簡單的數(shù)組,或者使用對象作為替代,對象允許配置高級選項,如類型檢測、自定義校驗和設(shè)置默認值

prop 的定義應(yīng)該盡量詳細,至少需要指定其類型

<!-- 父組件 -->
<template>
    <div>
        <my-child :parentMessage="parentMessage"></my-child>
    </div>
</template>
 
<script>
    import MyChild from '@components/common/MyChild'
 
    export default {
        components: {
            MyChild
        },
        data() {
            return {
                parentMessage: "我是來自父組件的消息"
            }
        }
    }
</script>
 
<!-- 子組件 -->
<template>
    <div>
        <span>{{ parentMessage }}</span>
    </div>
</template>
 
<script>
    export default {
        props: {
            parentMessage: {
                type: String,
                default: '默認顯示的信息'
                // require: true // 必填
            }
        }
    }
</script>
子組件到父組件通訊

子組件到父組件的通訊主要為父組件如何接受子組件之中的數(shù)據(jù)。這里的數(shù)據(jù)包括屬性和方法(String, Number, Boolean, Object, Array, Function)

通過 $emit 傳遞父組件數(shù)據(jù) (推薦)

與父組件到子組件通訊中的$on配套使用,可以向父組件中觸發(fā)的方法傳遞參數(shù)供父組件使用

<!-- 父組件 -->
<template>
    <div>
        <my-child @childEvent="parentMethod"></my-child>
    </div>
</template>
 
<script>
    import MyChild from '@components/common/MyChild'
 
    export default {
        components: {
            MyChild
        },
        data() {
            return {
                parentMessage: '我是來自父組件的消息'
            }
        },
        methods: {
            parentMethod({ name, age }) {
                console.log(this.parentMessage, name, age)
            }
        }
    }
</script>
 
 
<!-- 子組件 -->
<template>
    <div>
        <h3>子組件</h3>
    </div>
</template>
 
<script>
    export default {
        mounted() {
            this.$emit('childEvent', { name: 'zhangsan', age:  10 })
        }
    }
</script>
不推薦的通信方式

this.parent this.children
this.$refs

四、兄弟組件通信

1、vuex
Vuex 是一個專為 Vue.js 應(yīng)用程序開發(fā)的狀態(tài)管理模式。它采用集中式存儲管理應(yīng)用的所有組件的狀態(tài),它是響應(yīng)式的,狀態(tài)發(fā)生變化,組件會更新。

vuex實現(xiàn)兄弟組件通信非常簡單,組件A引用vuex數(shù)據(jù),組件B通過方法改變vuex數(shù)據(jù),vuex狀態(tài)是響應(yīng)式的,數(shù)據(jù)放生變化,組件A會更新。

2、eventBus又稱為事件總線
在vue中可以使用eventBus來作為溝通橋梁, 就像是所有組件共用相同的事件中心,可以向該中心注冊發(fā)送事件或接收事件, 所有組件都可以通知其他組件。

初始化

首先需要創(chuàng)建一個事件總線并將其導(dǎo)出, 以便其他模塊可以使用或者監(jiān)聽它。

我們在src/components/目錄下新建文件bus.js。

import Vue from 'vue'
export default new Vue()

發(fā)送事件

假設(shè)你有兩個兄弟組件: ComA和ComB,ComA發(fā)送消息給ComB。

ComA這樣

<template>
    <div>
        <button @click="sendMsg">給組件B發(fā)送消息</button> 
    </div>
</template>
 
<script>
import bus from './bus'
 
export default {
    name: 'comA',
    data () {
        return {
             
        }
    },
     
    methods: {
        sendMsg() {
            bus.$emit('fromA', {
                phone: 13800138000
            })
        }
    }
}
</script>

很顯然,ComA中使用bus.$emit(事件名,數(shù)據(jù));向事件中心注冊發(fā)送事件。

接收事件

ComB接受ComA發(fā)送過來的消息。

<template>
    <div>
        <p>{{fromA}}</p>
    </div>
</template>
 
<script>
import bus from './bus'
 
export default {
    name: 'comB',
    data () {
        return {
            fromA: '',
        }
    },
    mounted() {
        bus.$on('fromA', param => {
            this.fromA = param.phone;
        })
    }
}
</script>

于是,當ComA發(fā)送了一個手機號碼phone給ComB時,comB就會接收并顯示。

父組件

在父組件中調(diào)用ComA和ComB兩個兄弟組件。

<template>
  <div>
    <comA></comA>
    <comB></comB>
  </div>
</template>
 
<script>
import ComA from './ComA.vue'
import ComB from './ComB.vue'
 
export default {
    components: {
       ComA,
       ComB
    },
}
</script>

五、多層級組件通訊

1、vuex
2、eventBus
3、provide / inject

provide 和 inject 主要在開發(fā)高階插件/組件庫時使用。并不推薦用于普通應(yīng)用程序代碼中。

這對選項需要一起使用,以允許一個祖先組件向其所有子孫后代注入一個依賴,不論組件層次有多深,并在其上下游關(guān)系成立的時間里始終生效。

// 父級組件提供 'foo'
var Provider = {
  provide: {
    foo: 'bar'
  },
  // ...
}
 
// 子組件注入 'foo'
var Child = {
  inject: ['foo'],
  created () {
    console.log(this.foo) // => "bar"
  }
  // ...
}

六、作用域插槽

有時讓插槽內(nèi)容能夠訪問子組件中才有的數(shù)據(jù)是很有用的。例如,設(shè)想一個帶有如下模板的 <current-user> 組件:

<span>
  <slot>{{ user.lastName }}</slot>
</span>

我們可能想換掉備用內(nèi)容,用名而非姓來顯示。如下:

<current-user>
  {{ user.firstName }}
</current-user>

然而上述代碼不會正常工作,因為只有 <current-user> 組件可以訪問到 user 而我們提供的內(nèi)容是在父級渲染的。

為了讓 user 在父級的插槽內(nèi)容中可用,我們可以將 user 作為 <slot> 元素的一個 attribute 綁定上去:

<span>
  <slot v-bind:user="user">
    {{ user.lastName }}
  </slot>
</span>

綁定在 <slot> 元素上的 attribute 被稱為插槽 prop?,F(xiàn)在在父級作用域中,我們可以使用帶值的 v-slot 來定義我們提供的插槽 prop 的名字:

<current-user>
  <template v-slot:default="slotProps">
    {{ slotProps.user.firstName }}
  </template>
</current-user>

在這個例子中,我們選擇將包含所有插槽 prop 的對象命名為 slotProps,但你也可以使用任意你喜歡的名字。

七、組件的方法

組件方法,就是我們寫組件時,在methods選項里邊定義的一些方法,他通常是對數(shù)據(jù)的CURD。
element-ui我們常用的有

this.refs[formName].resetFields(); form表單重置 this.refs.[treeName].getCheckedKeys() tree 返回目前被選中的節(jié)點的 key 所組成的數(shù)組

八、vue 語法糖

1、v-model
v-model可以實現(xiàn)數(shù)據(jù)雙向的綁定,自動為組件添加了props 名為 value 和 自定義事件 名為 input。

<input type="text" v-model="name">

實際上,上面的代碼是下面代碼的語法糖。

<input  v-bind:value="name"  v-on:input="name=$event.target.value"/>

自定義組件的 v-model

一個組件上的 v-model 默認會利用名為 value 的 prop 和名為 input 的事件,但是像單選框、復(fù)選框等類型的輸入控件可能會將 value attribute 用于不同的目的。model 選項可以用來避免這樣的沖突:

Vue.component('base-checkbox', {
  model: {
    prop: 'checked',
    event: 'change'
  },
  props: {
    checked: Boolean
  },
  template: `
    <input
      type="checkbox"
      v-bind:checked="checked"
      v-on:change="$emit('change', $event.target.checked)"
    >
  `
})

現(xiàn)在在這個組件上使用 v-model 的時候:

<base-checkbox v-model="lovingVue"></base-checkbox>

這里的 lovingVue 的值將會傳入這個名為 checked 的 prop。同時當 <base-checkbox> 觸發(fā)一個 change 事件并附帶一個新的值的時候,這個 lovingVue 的 property 將會被更新。
2、.sync 修飾符
在有些情況下,我們可能需要對一個 prop 進行“雙向綁定”。不幸的是,真正的雙向綁定會帶來維護上的問題,因為子組件可以變更父組件,且在父組件和子組件都沒有明顯的變更來源。

這也是為什么我們推薦以 update:myPropName 的模式觸發(fā)事件取而代之。舉個例子,在一個包含 title prop 的假設(shè)的組件中,我們可以用以下方法表達對其賦新值的意圖:

this.$emit('update:title', newTitle)

然后父組件可以監(jiān)聽那個事件并根據(jù)需要更新一個本地的數(shù)據(jù) property。例如:

<text-document
  v-bind:title="doc.title"
  v-on:update:title="doc.title = $event"
></text-document>

為了方便起見,我們?yōu)檫@種模式提供一個縮寫,即 .sync 修飾符:

<text-document v-bind:title.sync="doc.title"></text-document>

九、組件選項推薦順序

<script>
  export default {
    el: '#app', // 只在由 new 創(chuàng)建的實例中遵守。
     
    // 全局感知
    name: 'name', // 組件name
    parent: VueInstance, // 指定父實例
 
    // 組件類型
    functional: false, // 沒有data 實例 沒有上下文
 
    // 模板修改器
    delimiters: ['${', '}'], // 分隔符變成了 ES6 模板字符串的風(fēng)格
    comments: false, // 當設(shè)為 true 時,將會保留且渲染模板中的 HTML 注釋。默認行為是舍棄它們。
 
    // 模板依賴
    components: {}, // 子組件
    directives: {}, // 自定義指令
    filters: {}, // 自定義過濾器
 
    // 組合
    extends: CompA, // 擴展另一個組件 和 mixins 類似
    mixins: [tableEvents], // 混入選項對象, 混入實例對象可以像正常的實例對象一樣
 
    // 接口
    inheritAttrs: true,
    model: { // 自定義組件在使用 v-model 時定制 prop 和 event
      prop: 'checked',
      event: 'change'
    },
    propsData: { // 只用于 new 創(chuàng)建的實例中。   創(chuàng)建實例時傳遞 props。
 
    },
 
    // 本地狀態(tài)
    data: () => ({ // 本地狀態(tài)
 
    }),
    computed: { // 計算屬性
 
    },
 
    // 事件 生命周期鉤子
    watch: {
 
    },
 
    // 生命周期鉤子
    beforeCreate() {
 
    },
    created() {
 
    },
    beforeMount() {
 
    },
    mounted() {
 
    },
    beforeUpdate() {
 
    },
    updated() {
 
    },
    activated() {
 
    },
    deactivated() {
 
    },
    beforeDestroy() {
 
    },
    destroyed() {
 
    },
 
    // 非響應(yīng)式的屬性 (不依賴響應(yīng)系統(tǒng)的實例屬性)
    methods() {
 
    },
 
    // 渲染 (組件輸出的聲明式描述)
    template: '<div>demo</div>', // 渲染模板
    render: function (createElement) {
      return createElement(
        'h' + this.level,   // 標簽名稱
        this.$slots.default // 子節(jié)點數(shù)組
      )
    },
    renderError (h, err) { // 只在開發(fā)者環(huán)境下工作。
      return h('pre', { style: { color: 'red' }}, err.stack)
    }
     
  }
</script>

十、組件樣式推薦使用CSS 作用域

<style scoped>
    
</style>
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容