你不知道的Vue技巧之--開發(fā)一個可以通過方法調(diào)用的組件(推薦)
Vue作為最近最炙手可熱的前端框架,其簡單的入門方式和功能強(qiáng)大的API是其優(yōu)點(diǎn)。而同時(shí)因?yàn)槠銩PI的多樣性和豐富性,所以他的很多開發(fā)方式就和一切基于組件的React不同,如果沒有對Vue的API(有一些甚至文檔都沒提到)有一個全面的了解,那么在開發(fā)和設(shè)計(jì)一個組件的時(shí)候有可能就會繞一個大圈子,所以我非常推薦各位在學(xué)習(xí)Vue的時(shí)候先要對Vue核心的所有API都有一個了解。
舉個例子,通知組件notification基本是現(xiàn)代web開發(fā)標(biāo)配,在很多地方都能用到。而在以Vue作為核心框架的前端項(xiàng)目中,因?yàn)閂ue本身是一個組件化和虛擬Dom的框架,要實(shí)現(xiàn)一個通知組件的展示當(dāng)然是非常簡單的。但因?yàn)橥ㄖM件的使用特性,直接在模板當(dāng)中書寫組件并通過v-show或者props控制通知組件的顯示顯然是非常不方便的,而且如果要在action或者其他非組件場景中要用到通知,那么純組件模式的用法也無法實(shí)現(xiàn)。那么有沒有辦法即用到Vue組件化特性方便得實(shí)現(xiàn)一個通知組件的展現(xiàn),又能夠通過一個簡單的方法調(diào)用就能顯示通知呢?本文就是來講述這個實(shí)現(xiàn)方法的。
目標(biāo)
實(shí)現(xiàn)一個Vue的通知組件,可以直接在組件內(nèi)調(diào)用
通過方法調(diào)用,比如Vue.$notify({...options})來調(diào)用通知組件
結(jié)合上述兩種方式,復(fù)用代碼
實(shí)現(xiàn)通知組件
這一步非常的簡單,我相信做過一點(diǎn)Vue開發(fā)的同學(xué)都能寫出一個像模像樣的通知組件,在這里就不贅述,直接上代碼
<template>
<transition name="fade" @after-leave="afterLeave" @after-enter="setHeight">
<div
v-show="visible"
:class="['notification']"
:style="style"
@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)容都是空的,雖然在模板上有用到,但是似乎沒什么意義,在后面我們要擴(kuò)展組件的時(shí)候我會講到為什么要這么做。
創(chuàng)建完這個組件之后,我們就可以在模板中使用了<notification btn="xxx" content="xxx" />
實(shí)現(xiàn)通過方法調(diào)用該通知組件
繼承組件
在實(shí)現(xiàn)通過方法調(diào)用之前,我們需要擴(kuò)展一下這個組件,因?yàn)閮H僅這些屬性,并不夠我們使用。在使用方法調(diào)用的時(shí)候,我們需要考慮一下幾個問題:
- 顯示通知的定位
- 組件的出現(xiàn)和自動消失控制
- 連續(xù)多次調(diào)用通知方法,如何排版多個通知
在這個前提下,我們需要擴(kuò)展該組件,但是擴(kuò)展的這些屬性不能直接放在原組件內(nèi),因?yàn)檫@些可能會影響組件在模板內(nèi)的使用,那怎么辦呢?這時(shí)候我們就要用到Vue里面非常好用的一個API,extend,通過他去繼承原組件的屬性并擴(kuò)展他。
我們先來看代碼,創(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
}
}
}
我們可以看到之前空實(shí)現(xiàn)的幾個方法在這里被實(shí)現(xiàn)了,那么為什么要在原組件上面加上那些方法的定義呢?因?yàn)樾枰谀0迳辖壎ǎ0迨菬o法extend的,只能覆蓋,如果要覆蓋重新實(shí)現(xiàn),那擴(kuò)展的意義就不是很大了。當(dāng)然同學(xué)們可以自己抉擇。
在使用extend的時(shí)候注意以下兩個點(diǎn):
- 方法和屬性的定義是直接覆蓋的
- 生命周期方法類似余mixin,會合并,也就是原組件和繼承之后的組件都會被調(diào)用,原組件先調(diào)用
通過方法調(diào)用該組件
最后我們需要做的就是通過方法調(diào)用這個已經(jīng)繼承過的組件了,我們先來看一下源碼的實(shí)現(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的實(shí)例了,同時(shí)通過該方式創(chuàng)建的實(shí)例,是有組件定義里面的所有屬性的。
在創(chuàng)建實(shí)例之后,可以通過instance.$mount()手動將組件掛載到DOM上面,這樣我們可以不依賴Vue組件樹來輸出DOM片段,達(dá)到自由顯示通知的效果。
這中間的實(shí)現(xiàn)主要就是維護(hù)一個通知數(shù)組,在創(chuàng)建時(shí)推入,在消失時(shí)刪除,這個過程并沒有規(guī)定一定要如此實(shí)現(xiàn),我就不贅述,以免限制大家的思路,大家可以根據(jù)自己的想法去實(shí)現(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
}
然后在項(xiàng)目內(nèi),我們可以通過:
import notify from '/path/to/notification/module' Vue.use(notify)
這樣之后,在組件內(nèi)就可以直接通過this.$notify({...options})來調(diào)用通知了,同時(shí)還可以通過Vue.notify({...options})在其他環(huán)境下調(diào)用,大家可以在自己的項(xiàng)目中嘗試一下。
總結(jié)
到這里,關(guān)于如何實(shí)現(xiàn)通過方法調(diào)用一個Vue組件內(nèi)容就差不多了。在這里我們涉及到的Vue技術(shù)點(diǎn)有如下幾點(diǎn):
- 通過extend配置進(jìn)行組件的擴(kuò)展
- 通過Vue.extend創(chuàng)建一個Vue的子類,用來動態(tài)創(chuàng)建Vue實(shí)例
- 通過Vue實(shí)例主動將組件內(nèi)容掛載到DOM
Vue擁有非常多的API,如果在使用Vue之前沒有系統(tǒng)的學(xué)習(xí)過Vue的核心知識和API,你可能壓根就不知道有這樣的實(shí)現(xiàn)方式,所以想要學(xué)好Vue,系統(tǒng)得對Vue的核心進(jìn)行學(xué)習(xí)是非常重要的一個環(huán)節(jié)。
以上所述是小編給大家介紹的你不知道的Vue技巧之--開發(fā)一個可以通過方法調(diào)用的組件詳解整合,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時(shí)回復(fù)大家的。在此也非常感謝大家對腳本之家網(wǎng)站的支持!
相關(guān)文章
建立和維護(hù)大型 Vue.js 項(xiàng)目的 10 個最佳實(shí)踐
這篇文章小編要與大家分享的是建立和維護(hù)大型 Vue.js 項(xiàng)目的 10 個最佳實(shí)踐,需要的小伙伴請和小編一起學(xué)習(xí)下面文章的具體內(nèi)容吧2021-09-09
vue-router清除url地址欄路由參數(shù)的操作代碼
這篇文章主要介紹了vue-router清除url地址欄路由參數(shù),本文給大家介紹的非常詳細(xì),需要的朋友可以參考下2015-11-11
Vue 實(shí)現(xiàn)v-for循環(huán)的時(shí)候更改 class的樣式名稱
這篇文章主要介紹了Vue 實(shí)現(xiàn)v-for循環(huán)的時(shí)候更改 class的樣式名稱,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-07-07
vue element-ui實(shí)現(xiàn)el-table表格多選以及回顯方式
這篇文章主要介紹了vue element-ui實(shí)現(xiàn)el-table表格多選以及回顯方式,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-07-07
在vue項(xiàng)目創(chuàng)建的后初始化首次使用stylus安裝方法分享
下面小編就為大家分享一篇在vue項(xiàng)目創(chuàng)建的后初始化首次使用stylus安裝方法,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-01-01

