message
在main.js中引入message.js
import { createMessage } from '@/components/message',然后绑定到原型上Vue.prototype.$message = createMessage
// message.js
import Vue from 'vue'
import Message from './message.vue'
const instances = []
let seed = 1
export function createMessage ({ msg = '', type = '' }) {
const MessageConstructor = Vue.extend(Message)
const MessageInstance = new MessageConstructor({
propsData: {
msg,
type
}
})
let top = 20
instances.forEach(item => {
top += item.$el.offsetHeight + 16
})
MessageInstance.topStyle = top
MessageInstance.id = ++seed
MessageInstance.onClose = () => {
createMessage.close(MessageInstance.id)
}
MessageInstance.visible = true
MessageInstance.$mount()
document.body.appendChild(MessageInstance.$el)
instances.push(MessageInstance)
return MessageInstance
}
['success', 'error', 'info', 'warning'].forEach(type => {
createMessage[type] = function (msg) {
createMessage({ msg, type })
}
})
createMessage.close = function (id) {
let index = null
let offsetHeight = null
instances.forEach((item, i) => {
if (item.id === id) {
index = i
offsetHeight = item.$el.offsetHeight
}
})
instances.splice(index, 1)
instances.forEach((item, i) => {
console.log(i, index, i >= index)
if (i >= index) {
item.topStyle = item.topStyle - 16 - offsetHeight
}
})
}
Message组件
<template>
<div
class="message"
:class="[type]"
:style="{top: topStyle + 'px'}"
v-show="visible"
@mouseenter="endTime"
@mouseleave="startTime"
>
{{msg}}
<span class="close-button" @click="handleClose">x</span>
</div>
</template>
<script>
export default {
props: {
msg: {
type: String,
default: ''
},
type: {
type: String,
default: ''
}
},
data () {
return {
id: 0,
topStyle: 20,
visible: false,
timer: null,
onClose: null
}
},
mounted () {
this.startTime()
},
methods: {
handleClose () {
if (this.$el && this.$el.parentNode) {
this.onClose && this.onClose()
this.$destroy()
this.$el.parentNode.removeChild(this.$el)
}
},
startTime () {
this.timer = setTimeout(() => {
this.handleClose()
}, 1000)
},
endTime () {
clearTimeout(this.timer)
this.timer = null
}
}
}
</script>
<style lang="less" scoped>
.message {
min-width: 200px;
height: 30px;
position: fixed;
z-index: 999;
left: 50%;
transform: translateX(-50%);
padding: 0 20px;
line-height: 30px;
border-radius: 5px;
border: 1px solid #ccc;
&.success {
background: yellowgreen;
color: #fff;
border: 0 none;
}
&.error {
background: red;
color: #fff;
border: 0 none;
}
&.info {
background: gray;
color: #fff;
border: 0 none;
}
&.warning {
background: yellow;
color: #fff;
border: 0 none;
}
}
.close-button {
position: absolute;
right: 20px;
cursor: pointer;
}
</style>
使用
<template>
<div class="hello">
<button @click="handleClick">点击</button>
<button @click="successClick">success</button>
<button @click="failClick">fail</button>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
methods: {
handleClick () {
this.$message({
msg: '空白',
type: ''
})
},
successClick () {
this.$message.success('成功')
},
failClick () {
this.$message.error('失败')
}
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped lang="less">
button + button {
margin-left: 20px;
}
</style>
dialog
dialog组件
//dialog.vue
<template>
<div class="mask" @click="handleClose" v-if="dialogVisible">
<div class="dialog" @click.stop.prevent>
<div class="title">
<slot name="title"></slot>
</div>
<div class="content">
<slot></slot>
</div>
<div class="footer">
<slot name="footer"></slot>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'Dialog',
props: {
visible: Boolean,
appendToBody: {
type: Boolean,
default: true
}
},
data () {
return {
dialogVisible: false
}
},
watch: {
visible (value) {
if (value) {
if (this.appendToBody) {
this.dialogVisible = value
document.body.append(this.$el)
} else {
this.dialogVisible = value
}
} else {
this.dialogVisible = value
}
}
},
methods: {
handleClose () {
this.$emit('update:visible', false)
}
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped lang="less">
.mask {
position: fixed;
left: 0;
top: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.2);
overflow: auto;
.dialog {
min-width: 500px;
min-height: 100px;
background: #fff;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
display: flex;
flex-direction: column;
.title {
height: 50px;
line-height: 50px;
text-align: left;
border-bottom: 1px solid #ccc;
padding-left: 20px;
}
.footer {
height: 50px;
text-align: right;
border-top: 1px solid #ccc;
padding: 10px;
box-sizing: border-box;
button + button {
margin-left: 20px;
}
}
.content {
overflow: auto;
// max-height: 700px;
flex: 1;
}
}
}
</style>
使用
<template>
<div class="hello">
<button @click="handleClick">点击</button>
<my-dialog :visible.sync="visible">
<template v-slot:title>
<div>
标题
</div>
</template>
内容
<template v-slot:footer>
<button @click="handleCancel">取消</button>
<button @click="handleCancel">确定</button>
</template>
</my-dialog>
</div>
</template>
<script>
import myDialog from './dialog.vue'
export default {
name: 'HelloWorld',
components: {
myDialog
},
data () {
return {
visible: false
}
},
methods: {
handleClick () {
this.visible = !this.visible
},
handleCancel () {
this.visible = false
}
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped lang="less">
button + button {
margin-left: 20px;
}
</style>