1. 基础组件编写
1.1 组件目录结构
1.2 组件文件代码
<template>
<transition name="fade">
<div :style="style">
<span>{{content}}</span>
<a @click="handleClose">{{btn}}</a>
</div>
</transition>
</template>
<script>
export default {
name: 'Notification',
props: {
content: {
type: String,
required: true
},
btn: {
type: String,
default: '关闭'
}
},
computed: {
style () {
return {}
}
},
methods: {
handleClose (e) {
e.preventDefault()
this.$emit('close')
}
}
}
</script>
<style 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.8)
flex-wrap wrap
transition all .3s
.content
padding 0
.btn
color #ff4081
padding-left 24px
margin-left auto
cursor pointer
</style>
1.3 组件使用的过渡效果样式代码
html, body{
margin: 0
padding: 0
width: 100%
height: 100%
}
body{
background-image: url(../images/beijing.jpg)
background-size: cover
background-position: center
font: 14px/1.5 tahoma,arial,'Hiragino Sans GB','\5b8b\4f53',sans-serif
color: #4d4d4d
-webkit-font-smoothing: antialiased // 这个属性可以使页面上的字体抗锯齿,使用后字体看起来会更清晰舒服
font-weight: 300
}
.fade-enter-active, .fade-leave-active{
transition: opacity .5s
}
.fade-enter, .fade-leave-to{
opacity: 0
}
1.4 如果我们直接使用这个编写好的组件,只能是我们在编写一个Vue组件的时候引用这个Notification的组件把它写在模版里面,把它去显示出来,我们这里作为一个全局通用型组件,而且我们可以把它发布到第三方去使用的组件,所以我们这里会为其提供一个类似于Vue插件的使用方法。
友情提醒:我们在定义组件的时候最好都给组件定义一个name,因为我们去编写一个组件库,我们会有非常多的组件要注册到全局的Vue的组件里面,这个时候如果没有一个name,那么每个组件注册的时候都需要用字符串去写name,这个维护性是非常不好的,如果你在组件内部就把组件的name定义好,那就可以很方便的把组件一个个定义过去就OK了。
1.5 入口文件引入组件,然后将其定义为插件即可再全局使用该组件了
1.6 在app组件中使用我们自定义的通知组件,直接使用即可无需再次注册
1.7 打开浏览器查看显示效果
1.8 总结
现在看我们这个组件的静态展示效果已经出现了,基本也就是这个样子,我们使用组件的时候需要在模版里面去定义,而且它还没有变成全局性的那种提示要从右下角弹出来,我们如果要在模版里进行这种效果控制还需要给组件添加属性visible用来控制组件的显示隐藏,然后在我们自己的逻辑中判断什么时候该显示什么时候该消失,整个逻辑就会变得很复杂,那我们用起来非常的困难,因为这种是临时性的组件,等到某个特殊的情况才需要我们去Notification一下,那么如果我们写在模版里,则一开始就需要定义好这个组件而且需要控制这个组件是不显示的,这种用法明显感觉是很奇怪的。所以,后面我们就要去改进它,让我们自定义的这个组件可以通过Vue的一些功能去实现我们可以通过API的方式去调用它。用起来就会变得非常方便了~
2. 通过API方式调用组件
2.1 扩展Notification组件,因为只有上面定义的两个属性是不够使用的,所以我们使用Vue.extends去扩展这个组件,为什么我们不在原来的组件是直接进行修改呢?因为那些属性添加上之后,如果我们在app.vue组件中在模版中使用这个组件的时候就会变得不好用,因此我们选择去扩展组件,而不是去修改原来的组件。这样既可以复用原来组件的代码,然后又可以达到我们扩展功能的目的。那么我们如何去扩展我们原来的组件呢?需要新创建一个文件,专门用来做API调用时使用的。
代码:
import Notification from './notification.vue'
export default {
extends: Notification,
data () {
return {
verticalOffset: 0
}
},
computed: {
style () {
return {
position: 'fixed',
right: '20px',
bottom: `${this.verticalOffset}px`
}
}
}
}
2.2 编写API调用逻辑处理文件
代码:
import Vue from 'vue'
import Component from './func-notification'
/**
* 思考:我们为什么要这么去做呢?因为我们这里是一个方法,我们要通过JS的方法调用去创建一个Vue的组件,这个组件我们怎么去创建最方便呢?
* 我们肯定是通过去new的方式,我们可以直接通过new Vue去创建一个组件,那么我们同样可以通过Vue.extend返回的方法,我们去创建一个组件。
*/
const NotificationConstructor = Vue.extend(Component)
const instances = [] // 存储通知组件实例列表
let seed = 1 // 用来生成组件的id
const notify = (options) => {
if (Vue.prototype.$isServer) return
const instance = new NotificationConstructor({
propsData: options
})
instance.id = `notification_${seed++}` // 生成唯一id,用来做删除时使用
// 通过$mount()不传节点的时候,只是生成了一个$el的对象,但是这个时候还没有真正的插入到DOM节点里面去,此时标签节点已经生成好了
instance.vm = instance.$mount()
document.body.appendChild(instance.vm.$el)
// 计算高度
let verticalOffset = 0
instances.forEach((item) => {
verticalOffset += item.$el.offsetHeight + 16 // 每个组件高度间隔16px
})
verticalOffset += 16 // 最下面的组件底部距离最底部也有16px的间隙
instance.verticalOffset = verticalOffset
instances.push(instance)
return instance.vm
}
export default notify
2.3 将编写的API调用方法挂载到Vue.prototype原型对象上,这样在Vue的实例中就可以直接使用this.$xxx方法了
代码:
import Notification from './notification.vue'
import notify from './function'
export default (Vue) => {
Vue.component(Notification.name, Notification)
Vue.prototype.$notify = notify
}
2.4 在app.vue组件中使用该API来生成通知
代码:
<template>
<div>
<notification content="测试通知组件模版使用" />
</div>
</template>
<script>
export default {
data () {
return {}
},
mounted () {
this.$notify({
content: '测试通知组件API使用!!!',
btn: 'close'
})
}
}
</script>
<style>
</style>
2.5 打开浏览器查看效果,通过API调用方式成功生成我们想要的组件效果!!!
3. 点击发送通知
3.1 接下来我们实现每次点击按钮发送通知
3.2 改造代码实现点击按钮发送通知
代码:
<template>
<div>
<!-- <notification content="测试通知组件模版使用" /> -->
<button @click="notify">发送通知</button>
</div>
</template>
<script>
export default {
data () {
return {}
},
mounted () {
},
methods: {
notify () {
this.$notify({
content: '测试通知组件API使用!!!',
btn: 'close'
})
}
}
}
</script>
<style>
</style>
3.3 添加通知自动关闭功能
代码:
import Notification from './notification.vue'
export default {
extends: Notification,
data () {
return {
verticalOffset: 0,
autoClose: 3000
}
},
computed: {
style () {
return {
position: 'fixed',
right: '20px',
bottom: `${this.verticalOffset}px`
}
}
},
mounted () {
this.createTimer()
},
beforeDestory () {
this.clearTimer()
},
methods: {
createTimer () {
if (this.autoClose) {
this.timer = setTimeout(() => {
/**
* 思考:这里我们需要把我们的组件隐藏掉,如果直接将组件删除掉效果会比较差,所以我们也要通过transition去做,
* 通过transition去做,我们就需要通过某个属性去控制我们组件的显示与否,所以我们在我们的组件上面去添加一个visible属性,
* 该属性用来控制组件的显示与隐藏。在默认组件内部该属性值是true,也就是说默认是显示的。
*/
this.visible = false
}, this.autoClose)
}
},
clearTimer () {
if (this.timer) {
clearTimeout(this.timer)
}
}
}
}
调用API修改
代码:
import Vue from 'vue'
import Component from './func-notification'
/**
* 思考:我们为什么要这么去做呢?因为我们这里是一个方法,我们要通过JS的方法调用去创建一个Vue的组件,这个组件我们怎么去创建最方便呢?
* 我们肯定是通过去new的方式,我们可以直接通过new Vue去创建一个组件,那么我们同样可以通过Vue.extend返回的方法,我们去创建一个组件。
*/
const NotificationConstructor = Vue.extend(Component)
const instances = [] // 存储通知组件实例列表
let seed = 1 // 用来生成组件的id
const notify = (options) => {
if (Vue.prototype.$isServer) return
/**
* 我们希望我们的func-notification组件中的autoClose属性是通过options传入的,但是又不希望它是通过props传入而是作为data使用的,
* 那么我们如何处理呢?我们可以拿到options形式传入的autoClose参数,然后以data的形式传给组件,其余的数据以props形式传递给组件
*
*/
const {
autoClose,
...rest
} = options
const instance = new NotificationConstructor({
propsData: {
...rest
},
data: {
autoClose: autoClose === undefined ? 3000 : autoClose
}
})
instance.id = `notification_${seed++}` // 生成唯一id,用来做删除时使用
// 通过$mount()不传节点的时候,只是生成了一个$el的对象,但是这个时候还没有真正的插入到DOM节点里面去,此时标签节点已经生成好了
instance.vm = instance.$mount()
document.body.appendChild(instance.vm.$el)
// 计算高度
let verticalOffset = 0
instances.forEach((item) => {
verticalOffset += item.$el.offsetHeight + 16 // 每个组件高度间隔16px
})
verticalOffset += 16 // 最下面的组件底部距离最底部也有16px的间隙
instance.verticalOffset = verticalOffset
instances.push(instance)
return instance.vm
}
export default notify
友情提示:使用扩展运算符,需要做如下配置:
安装依赖包
➜ vue-demo npm install babel-preset-stage-2
npm WARN vue-demo@1.0.0 No repository field.
+ babel-preset-stage-2@6.24.1
added 13 packages from 1 contributor and audited 8458 packages in 6.963s
found 5 vulnerabilities (2 low, 1 moderate, 2 high)
run `npm audit fix` to fix them, or `npm audit` for details
➜ vue-demo npm run dev
配置.babelrc文件
{
"presets": [
"env",
"stage-2"
],
"plugins": [
"transform-vue-jsx"
]
}
修改webpack.config.js配置
3.4 点击发送通知按钮后查看效果
3秒后的效果,通知消失了