您好,登錄后才能下訂單哦!
Vue作為最近最炙手可熱的前端框架,其簡單的入門方式和功能強大的API是其優(yōu)點。而同時因為其API的多樣性和豐富性,所以他的很多開發(fā)方式就和一切基于組件的React不同,如果沒有對Vue的API(有一些甚至文檔都沒提到)有一個全面的了解,那么在開發(fā)和設(shè)計一個組件的時候有可能就會繞一個大圈子,所以我非常推薦各位在學(xué)習(xí)Vue的時候先要對Vue核心的所有API都有一個了解。
舉個例子,通知組件notification基本是現(xiàn)代web開發(fā)標(biāo)配,在很多地方都能用到。而在以Vue作為核心框架的前端項目中,因為Vue本身是一個組件化和虛擬Dom的框架,要實現(xiàn)一個通知組件的展示當(dāng)然是非常簡單的。但因為通知組件的使用特性,直接在模板當(dāng)中書寫組件并通過v-show或者props控制通知組件的顯示顯然是非常不方便的,而且如果要在action或者其他非組件場景中要用到通知,那么純組件模式的用法也無法實現(xiàn)。那么有沒有辦法即用到Vue組件化特性方便得實現(xiàn)一個通知組件的展現(xiàn),又能夠通過一個簡單的方法調(diào)用就能顯示通知呢?本文就是來講述這個實現(xiàn)方法的。
目標(biāo)
實現(xiàn)一個Vue的通知組件,可以直接在組件內(nèi)調(diào)用
通過方法調(diào)用,比如Vue.$notify({...options})來調(diào)用通知組件
結(jié)合上述兩種方式,復(fù)用代碼
實現(xiàn)通知組件
這一步非常的簡單,我相信做過一點Vue開發(fā)的同學(xué)都能寫出一個像模像樣的通知組件,在這里就不贅述,直接上代碼
<template> <transition name="fade" @after-leave="afterLeave" @after-enter="setHeight"> <div v-show="visible" :class="['notification']" : @mouseenter="clearTimer" @mouseleave="createTimer" > <span class="content">{{content}}</span> <a class="btn" @click="handleClose">{{btn || '關(guān)閉'}}</a> </div> </transition> </template> <script> export default { name: 'Notification', props: { content: { type: String, default: '' }, btn: { type: String, default: '' } }, data () { return { visible: true } }, computed: { style () { return {} } }, methods: { handleClose (e) { e.preventDefault() this.doClose() }, doClose () { this.visible = false this.$emit('close') }, afterLeave () { this.$emit('closed') }, clearTimer () {}, createTimer () {}, setHeight () {} } } </script>
<style lang="stylus" scoped> .notification display: flex background-color #303030 color rgba(255, 255, 255, 1) align-items center padding 20px position fixed min-width 280px box-shadow 0px 3px 5px -1px rgba(0, 0, 0, 0.2), 0px 6px 10px 0px rgba(0, 0, 0, 0.14), 0px 1px 18px 0px rgba(0, 0, 0, 0.12) flex-wrap wrap transition all .3s .content padding 0 .btn color #ff4081 padding-left 24px margin-left auto cursor pointer </style>
在這里需要注意,我們定義了一個叫做style的computed屬性,三個方法clearTimer,createTimer,setHeight,但他們的內(nèi)容都是空的,雖然在模板上有用到,但是似乎沒什么意義,在后面我們要擴展組件的時候我會講到為什么要這么做。
創(chuàng)建完這個組件之后,我們就可以在模板中使用了<notification btn="xxx" content="xxx" />
實現(xiàn)通過方法調(diào)用該通知組件
繼承組件
在實現(xiàn)通過方法調(diào)用之前,我們需要擴展一下這個組件,因為僅僅這些屬性,并不夠我們使用。在使用方法調(diào)用的時候,我們需要考慮一下幾個問題:
在這個前提下,我們需要擴展該組件,但是擴展的這些屬性不能直接放在原組件內(nèi),因為這些可能會影響組件在模板內(nèi)的使用,那怎么辦呢?這時候我們就要用到Vue里面非常好用的一個API,extend,通過他去繼承原組件的屬性并擴展他。
我們先來看代碼,創(chuàng)建一個叫做fun-notification.js的文件,內(nèi)容如下:
import Notification from './notification.vue' export default { extends: Notification, computed: { style () { return { position: 'fixed', right: '20px', bottom: `${this.verticalOffset + 20}px` } } }, data () { return { verticalOffset: 0, visible: false, height: 0, autoClose: 3000 } }, mounted () { this.createTimer() }, methods: { createTimer () { if (this.autoClose) { this.timer = setTimeout(() => { this.doClose() }, this.autoClose) } }, clearTimer () { if (this.timer) { clearTimeout(this.timer) } }, setHeight () { this.height = this.$el.offsetHeight } } }
我們可以看到之前空實現(xiàn)的幾個方法在這里被實現(xiàn)了,那么為什么要在原組件上面加上那些方法的定義呢?因為需要在模板上綁定,而模板是無法extend的,只能覆蓋,如果要覆蓋重新實現(xiàn),那擴展的意義就不是很大了。當(dāng)然同學(xué)們可以自己抉擇。
在使用extend的時候注意以下兩個點:
通過方法調(diào)用該組件
最后我們需要做的就是通過方法調(diào)用這個已經(jīng)繼承過的組件了,我們先來看一下源碼的實現(xiàn):
// function-component.js import Vue from 'vue' import Component from './fun-component' const NotificationConstructor = Vue.extend(Component) const instances = [] let seed = 1 const removeInstance = (instance) => { const len = instances.length if (!instance) return const index = instances.findIndex(inst => instance.id === inst.id) instances.splice(index, 1) if (len <= 1) return const removedHeight = instance.vm.height for (let i = index; i < len - 1; i++) { instances[i].verticalOffset = parseInt(instances[i].verticalOffset) - removedHeight - 16 } } const notify = function (options) { const { onClose, ...rest } = options if (Vue.prototype.$isServer) return options = options || {} const id = `notification_${seed++}` const instance = new NotificationConstructor({ propsData: { ...rest } }) instance.id = id instance.vm = instance.$mount() document.body.appendChild(instance.vm.$el) instance.vm.visible = true let verticalOffset = 0 instances.forEach(item => { verticalOffset += item.$el.offsetHeight + 16 }) verticalOffset += 16 instance.verticalOffset = verticalOffset instances.push(instance) instance.vm.$on('closed', () => { if (typeof onClose === 'function') { onClose(instance) } removeInstance(instance) instance.vm.$destroy() }) return instance.vm } export default notify
首先通過const NotificationConstructor = Vue.extend(Component),我們得到了一個類似于Vue的子類,我們就可以通過new NotificationConstructor({...options})的方式去創(chuàng)建Vue的實例了,同時通過該方式創(chuàng)建的實例,是有組件定義里面的所有屬性的。
在創(chuàng)建實例之后,可以通過instance.$mount()手動將組件掛載到DOM上面,這樣我們可以不依賴Vue組件樹來輸出DOM片段,達到自由顯示通知的效果。
這中間的實現(xiàn)主要就是維護一個通知數(shù)組,在創(chuàng)建時推入,在消失時刪除,這個過程并沒有規(guī)定一定要如此實現(xiàn),我就不贅述,以免限制大家的思路,大家可以根據(jù)自己的想法去實現(xiàn)。
使用該方法
要使用這個通知方法非常簡單,我們可以直接import這個文件來使用,比如:
import notify from './function-component.js' notify({ content: 'xxx', btn: 'xxx' })
當(dāng)然我們很多場景是在組件內(nèi)部調(diào)用,為了方便在組件內(nèi)使用,不需要每次都import,我們可以把這個方法包裝成一個Vue的插件。我們創(chuàng)建一個index.js,內(nèi)容如下:
import Notification from './notification.vue' import notify from './function' export default (Vue) => { Vue.component(Notification.name, Notification) Vue.prototype.$notify = notify Vue.notify = notify }
然后在項目內(nèi),我們可以通過:
import notify from '/path/to/notification/module' Vue.use(notify)
這樣之后,在組件內(nèi)就可以直接通過this.$notify({...options})來調(diào)用通知了,同時還可以通過Vue.notify({...options})在其他環(huán)境下調(diào)用,大家可以在自己的項目中嘗試一下。
總結(jié)
到這里,關(guān)于如何實現(xiàn)通過方法調(diào)用一個Vue組件內(nèi)容就差不多了。在這里我們涉及到的Vue技術(shù)點有如下幾點:
Vue擁有非常多的API,如果在使用Vue之前沒有系統(tǒng)的學(xué)習(xí)過Vue的核心知識和API,你可能壓根就不知道有這樣的實現(xiàn)方式,所以想要學(xué)好Vue,系統(tǒng)得對Vue的核心進行學(xué)習(xí)是非常重要的一個環(huán)節(jié)。
以上所述是小編給大家介紹的你不知道的Vue技巧之--開發(fā)一個可以通過方法調(diào)用的組件詳解整合,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復(fù)大家的。在此也非常感謝大家對億速云網(wǎng)站的支持!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。