怎样封装一个 notify 命令式组件的
想成为一个vue框架中高级的coder,不会点组件封装是不行的。vue中注册组件的方式主要有三种,全局注册(Vue.component),局部注册(components:{componentsA}),还有就是命令式的插件形式,其调用形式一般是this.$Message({...}),
前面两种相对简单,今天我们就来封装一个命令式组件。
效果就是我点击中间的按钮,弹出右下角的提示,然后几秒后消息

1.首先我们要有一个模板文件,这里我就命名为 notification.vue
<template>
<transition name="fade" @after-leave="afterLeave" @after-enter="afterEnter">
<div class="notification" :style="style" v-show="visible">
<span class="content" mouseenter="clearTimer" mouseout="createTime">
{{content}}
</span>
<a class="btn" @click="handleClick">
{{btn}}
</a>
</div>
</transition>
</template>
<script>
export default {
name: 'Notification',
props: {
content: {
type: String,
required: true
},
btn: {
type: String,
default: "关闭"
}
},
mounted () {
},
computed: {
style () {
return {}
}
},
data () {
return {
visible: true
}
},
methods: {
handleClick (e) {
e.preventDefault();
this.$emit('close')
},
afterLeave () {
this.$emit('closed')
},
afterEnter () {
this.height = this.$el.offsetHeight
},
clearTimer () {
},
createTime () { }
},
}
</script>
<style lang="scss" scoped>
.notification {
display: flex;
background: #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);
flex-wrap: wrap;
transition: all 0.2s;
border-radius: 10px;
.content {
padding: 0;
}
.btn {
color: #ff4081;
padding-left: 24px;
margin-left: auto;
cursor: pointer;
}
}
</style>
2.继承上一步封装的模板文件,添加我们定制的数据,命名为 func-notification.js
import Notification from './notification.vue'
export default {
extends: Notification,
computed: {
style() {
return {
position: 'fixed',
right: '20px',
bottom: `${this.verticleOffset}px`
}
}
},
mounted() {
this.createTimer()
},
methods: {
createTimer() {
if (this.autoClose) {
this.timer = setTimeout(() => {
this.visible = false
}, this.autoClose)
}
},
clearTimer() {
if (this.timer) {
clearTimeout(this.timer)
}
}
},
destroyed() {
this.clearTimer()
},
data() {
return {
verticleOffset: 0,
autoClose: 3000,
height: 0,
visible: false
}
}
}
3.新建 functions.js 文件,引入上面两个文件然后再扩展其功能
import Vue from 'vue'
import Comp from './func-notification'
const NotificationConstructor = Vue.extend(Comp)
const instances = []
let seed = 1
const removeInstance = instance => {
if (!instance) return
const len = instances.length
const index = instances.findIndex(inst => instance.id == inst.id)
instances.splice(index, 1)
if (len < 1) return
const removeHeight = instance.height
for (var i = index; i < len - 1; i++) {
instances[i].verticleOffset =
parseInt(instances[i].verticleOffset) - removeHeight - 16
}
}
const notify = options => {
if (Vue.prototype.$isServer) {
return
}
const { autoClose, ...rest } = options
const instance = new NotificationConstructor({
propsData: {
...rest
},
data() {
return {
autoClose: autoClose === undefined ? 3000 : autoClose
}
}
})
const id = `notification_${seed++}`
instance.id = id
instance.$mount()
document.body.appendChild(instance.$el)
instance.visible = true
let verticleOffset = 0
instances.forEach(item => {
verticleOffset += item.$el.offsetHeight + 16
})
verticleOffset += 16
instance.verticleOffset = verticleOffset
/* */
console.log(instance)
instances.push(instance)
instance.$on('closed', () => {
removeInstance(instance)
document.body.removeChild(instance.$el)
instance.$destroy()
})
instance.$on('close', () => {
instance.visible = false
})
}
export default notify
4.新建 index.js 作为整个组件的入口文件
import Notification from './notification.vue'
import notify from './functions'
export default Vue => {
Vue.component(Notification.name, Notification)
Vue.prototype.$notify = notify
}
5.在 main.js 里面导入组件,并进行注册,这样就可以在全局进行命令式调用了
...
import Notification from './component/notification'
...
Vue.use(Notification)
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')