使用
// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
import App from './App'
Vue.config.productionTip = false
import router from '../router/index'
import store from './vuex'
import Message from '../src/components/message/index'
import Notice from "../src/components/notice/index"
Vue.prototype.$Message=Message
Vue.prototype.$Notice=Notice
/* eslint-disable no-new */
new Vue({
el: '#app',
components: { App },
template: '<App/>',
router,
store,
})
代码
import Notification from '../base/index'
let prefixCls='li-message-notification'
const iconPrefixCls = 'li-icon';
const prefixKey = 'li-message-key-';
const iconTypes = {
'info': 'ios-information-circle',
'success': 'ios-checkmark-circle',
'warning': 'ios-alert',
'error': 'ios-close-circle',
'loading': 'ios-loading'
};
const defaults = {
top: 24,
duration: 1.5
}
let messageInstance;
function getMessageInstance () {
messageInstance = messageInstance || Notification.newInstance({
prefixCls: prefixCls,
styles: {
top: `${defaults.top}px`
},
pre:'li-message'
});
return messageInstance;
}
function notice (content = '', duration = defaults.duration, type, onClose = function () {}, closable = false,colorStyles) {
const iconType = iconTypes[type];
// if loading
const loadCls = type === 'loading' ? ' ivu-load-loop' : '';
let instance = getMessageInstance();
instance.notice({
name: `${prefixKey}${name}`,
duration: duration,
styles: {},
// transitionName: 'move-up',
// 这里专门加了message进入和离开需要的渐变特效
content: content,
onClose: onClose,
closable: closable,
type: 'message',
msgType: type,
prefixCls:'li-message',
colorStyles:colorStyles,
// 这里要把里面的样式参数传进去
// 这里也进行了参数赋值
});
// 用于手动消除
return (function () {
let target = name++;
return function () {
instance.remove(`${prefixKey}${target}`);
};
})();
}
export default{
name:"li-message",
components:{Notification},
info(options){
return this.message('info',options)
},
success(options){
return this.message('success',options)
},
warning(options){
return this.message('warning',options)
},
error(options){
return this.message('error',options)
},
loading(options){
return this.message("loading",options);
},
message(type,options){
if(typeof options=='string'){
//证明用户只是挑简单输入了一个提示语句,别的都使用默认设置
options={
content:options
}
}
return notice(options.content,options.duration,type,options.onClose,options.closable,options.colorStyles)
},
config(options){
// 自定义设置
if(options.top||options.top===0){
defaults.top=option.top
}
if(options.duration||options.duration===0){
defaults.duration=options.duration
}
},
destory(){
let instance=getMessageInstance()
messageInstance=null
instance.destory('li-message')
}
}
index.js
// 还是需要一个index.js
import Vue from 'Vue'
import Notification from './notification.vue';
// 这里必须是实例化出来,在操作方法,不能在别的地方直接import,然后绕着那个方法,除非那个数据也是全局的。
// 现在这里面实例化一个组件
Notification.newInstance = properties => {
const _props = properties || {};
const Instance = new Vue({
render (h) {
return h(Notification, {
props: _props
});
}
});
const component = Instance.$mount();
document.body.appendChild(component.$el);
const notification = Instance.$children[0];
return {
// 通过这些暴露的方法来操作内部的数据
// 如果用最最一开始的方法,无法读取到里面的this
notice (noticeProps) {
notification.add(noticeProps);
},
remove (name) {
notification.close(name);
},
component: notification,
destroy (element) {
notification.closeAll();
setTimeout(function() {
document.body.removeChild(document.getElementsByClassName(element)[0]);
}, 500);
}
};
};
export default Notification;
index.less
···
@import '../../assets/gLess.less';
@notice:.li-notice-notification;
@message:.li-message-notification;
// notice外层包裹
@{message}{
font-size: @font-size-base;
position: fixed;
z-index:@zindex-message;
width:100%;
}
@{notice}{
//这里没有使用width:100%。一来是没必要,二来是如果宽度100%,
// 而且还是最上层覆盖,可能会导致想要点击的东西点击不到。
font-size: @font-size-base;
position: fixed;
z-index:@zindex-message;
width:335px;
right:0px;
}
// message外层包裹
// 过渡样式
// message过渡样式
// transition-group样式
.li-message-enter{
opacity: 0;
transform: translateY(-50px);
animation-timing-function: @ease-in-out;
}
.li-message-leave-to{
opacity: 0;
transform: translate(-30px,-50px);
}
.li-message-leave-active {
position: absolute;
animation-timing-function: @ease-in-out;
// 为什么到最后一个的时候,离开的时候加上这个样式就会导致原来的样式崩塌
// 但是这个和示范的样式是一模一样的啊
// 这真是见了鬼了。
}
.li-notice-enter{
opacity: 0;
transform:translateX(100%);
}
.li-notice-leave-to{
opacity: 0;
transform:translateX(100%)
}
.li-notice-leave-active{
position: absolute;
}
@keyframes ivuMoveDownIn {
0% {
transform-origin: 0 0;
transform: translateY(100%);
opacity: 0;
}
100% {
transform-origin: 0 0;
transform: translateY(0%);
opacity: 1;
}
}
@keyframes ivuMoveDownOut {
0% {
transform-origin: 0 0;
transform: translateY(0%);
opacity: 1;
}
100% {
transform-origin: 0 0;
transform: translateY(100%);
opacity: 0;
}
}
@keyframes ivuMoveLeftIn {
0% {
transform-origin: 0 0;
transform: translateX(-100%);
opacity: 0;
}
100% {
transform-origin: 0 0;
transform: translateX(0%);
opacity: 1;
}
}
@keyframes ivuMoveLeftOut {
0% {
transform-origin: 0 0;
transform: translateX(0%);
opacity: 1;
}
100% {
transform-origin: 0 0;
transform: translateX(-100%);
opacity: 0;
}
}
@keyframes ivuMoveRightIn {
0% {
opacity: 0;
transform-origin: 0 0;
transform: translateX(100%);
}
100% {
opacity: 1;
transform-origin: 0 0;
transform: translateX(0%);
}
}
@keyframes ivuMoveRightOut {
0% {
transform-origin: 0 0;
transform: translateX(0%);
opacity: 1;
}
100% {
transform-origin: 0 0;
transform: translateX(100%);
opacity: 0;
}
}
@keyframes ivuMoveUpIn {
0% {
transform-origin: 0 0;
transform: translateY(-100%);
opacity: 0;
}
100% {
transform-origin: 0 0;
transform: translateY(0%);
opacity: 1;
}
}
// 可以发现最明显的例子就是这个里面的移动数据都是百分比,跟我的直接填具体的数值不同
@keyframes ivuMoveUpOut {
0% {
transform-origin: 0 0;
transform: translateY(0%);
opacity: 1;
}
100% {
transform-origin: 0 0;
transform: translateY(-100%);
opacity: 0;
}
}
@keyframes ivuMoveNoticeIn {
0% {
opacity: 0;
transform-origin: 0 0;
transform: translateX(100%);
}
100% {
opacity: 1;
transform-origin: 0 0;
transform: translateX(0%);
}
}
@keyframes ivuMoveNoticeOut {
0% {
transform-origin: 0 0;
transform: translateX(0%);
opacity: 1;
}
70% {
transform-origin: 0 0;
transform: translateX(100%);
height: auto;
opacity: 0;
}
100% {
transform-origin: 0 0;
transform: translateX(100%);
height: 0;
padding: 0;
margin-bottom: 0;
opacity: 0;
}
}
···
Message.less
@import '../../assets/gLess.less';
@name:.li-message;
// 最外层的包裹
.li-message-wrapper{
display: flex;
width: 100%;
transition: all 0.5s;
justify-content: center;
}
@{name}{
margin-top:15px;
padding: 8px 8px;
display:flex;
background-color: #fff;
border-radius: @border-radius-small;
box-shadow: @shadow-base;
border:1px solid #fff;
&-close{
color:#999;
}
&-content{
padding-left:10px;
padding-right:10px;
}
&-icon{
}
&-success &-icon{
color:@success-color;
}
&-error &-icon{
color:@error-color;
}
&-warning &-icon{
color:@warning-color;
}
&-info &-icon{
color:@primary-color;
}
}
notice.less
@import '../../assets/gLess.less';
// notice样式
@notice:.li-notice;
@notice-width:335px;
@notice-padding:16px;
@notice-margin-bottom:10px;
@{notice}{
// 这个左右应该是有宽度大小的,可以上下扩展
width:85%;
margin-bottom:@notice-margin-bottom;
padding: 8px 8px;
display:flex;
background-color: #fff;
border-radius: @border-radius-small;
box-shadow: @shadow-base;
border:1px solid #fff;
flex-direction: column;
&-wrapper{
display: flex;
width:@notice-width;
transition: all 0.5s;
justify-content: center;
// position: relative;
// left:-20px;
// 加上position属性,消失的时候没有使用希望的样式,所以使用transform来移动位置巴
// 子元素里面应该可以加,里面也是不行的
}
&-title{
height:30px;
display: flex;
flex-direction: row;
font-size: @font-size-large;
color:@title-color;
}
&-icon{
width: 30px;
}
&-h{
flex:1;
line-height: 30px;
overflow: hidden;
text-emphasis:ellipsis;
white-space: nowrap;
}
&-close{
width:30px;
}
&-content{
flex:1;
min-height:50px;
font-size: @font-size-base;
color:@text-color;
text-align: justify;
line-height: 1.5;
}
}
// notification样式
Notice.vue
<template>
<!-- 首先所有这种弹出框架都是用的这个基础类型,有共同的父容器。 -->
<div :class="[`${prefixCls}-wrapper`]" @click="close">
<div :class="classes" :style="computedStyles">
<template v-if="type=='notice'">
<div class="li-notice-title">
<div class="li-notice-icon" v-if="withIcon">
X
</div>
<div class="li-notice-h">
{{title}}
</div>
<div class="li-notice-close" v-if="closable">
X
</div>
</div>
<div class="li-notice-content" v-if="content">
{{content}}
</div>
</template>
<template v-if="type=='message'">
<div
v-if="true"
class="li-message-icon"
:style="iconStyles"
>
*
</div>
<div class="li-message-content" @click="close">
{{content}}
</div>
<div
@click="close"
v-if="true"
class="li-message-close">
X
</div>
<!-- 这里还可以直接懒加载一个组件进去,这些就都不用操作了 -->
</template>
</div>
</div>
</template>
<script>
export default {
// 在这里也有自定义设置
props:{
prefixCls:{
type:String,
default:''
},
duration:{
type:Number,
default:1.5,
},
type:{
type:String,
},
content:{
type:String,
default:''
},
withIcon:Boolean,
render:{
type:Function
},
// 这里原本是可以传入一个自定义函数的,但是我们可以传入一个组件的路径,这里显示一个组件
// 功能既全,而且也很简单
conponentSec:{
type:String,
default:"",
},
title:{
type:String,
default:"这是一个没有给名字的标题"
},
styles:{
type:Object,
default:function(){
return {
right:'50%'
}
}
},
closable:{
type:Boolean,
default:false,
},
className:{
type:String,
},
name:{
type:String,
required:true,
},
onClose:{
type:Function,
},
transitionName:{
type:String,
default:'test'
},
msgType:{
type:String,
},
isShow:{
type:Boolean,
default:true,
// required:true,
},
colorStyles:{
type:Object,
default:function(){
return {}
}
},
// content:{
// type:String,
// default:'这是一个没有内容的提醒'
// }
// 这里重复定义的话,会覆盖,并且使用后面的值
},
data(){
return {
withDesc:false,
}
},
methods:{
clearCloseTimer(){
if(this.closeTimer){
clearTimeout(this.closeTimer)
this.closeTimer=null;
}
},
close(){
// this.clearCloseTimer()
console.log('close')
this.onClose()
this.$parent.$parent.close(this.name)
// 第一个parent取到的只是transition-group组件
},
},
computed:{
// class,style一定要写在computed里面
computedStyles(){
let styles={}
styles['background-color']=this.colorStyles['backgroundColor']
styles['border-color']=this.colorStyles['borderColor']
styles['color']=this.colorStyles['color']
return styles
},
classes(){
return [
`${this.prefixCls}`,
{
[`${this.className}`]:!!this.className,
}
]
},
iconStyles(){
let styles={}
if(this.colorStyles['iconColor']){
styles['color']=this.colorStyles['iconColor']
}
return styles
}
},
mounted(){
this.clearCloseTimer()
console.log(this.prefixCls)
// 先清除之前可能有的计时器
// if(this.duration!==0){
// this.closeTimer=setTimeout(()=>{
// this.close()
// },this.duration*1000)
// }
}
}
</script>
<style lang="less" src="./message.less"></style>
<style lang="less" src="./notice.less"></style>
notication.vue
<template>
<transition-group
:name="pre"
tag="div"
:class="classes" :style="wrapStyles"
>
<Notice
v-for="notice in notices"
:key="notice.name"
:prefix-cls="notice.prefixCls"
:styles="notice.styles"
:type="notice.type"
:content="notice.content"
:title="notice.title"
:withIcon="notice.withIcon"
:closable="notice.closable"
:name="notice.name"
:background="notice.background"
:msg-type="notice.msgType"
:on-close="notice.onClose"
:colorStyles="notice.colorStyles"
:duration="notice.duration"
>
</Notice>
</transition-group>
<!-- <div>
{{computedName}}-{{classes}}
</div> -->
</template>
<script>
import Notice from './notice'
let seed=0;
const now=Date.now();
function getUuid(){
return 'li-notification'+now+'-'+(seed++)
}
export default {
components:{
Notice
},
props:{
className:{
type:String,
},
prefixCls: {
type: String,
default: ""
},
pre:{
type:String,
default:''
},
content: {
type: String
},
},
data(){
return {
notices:[],
tIndex:this.handleGetIndex(),
// 测试数据
items: [1,2,3,4,5,6,7,8,9],
nextNum:10,
}
},
computed:{
classes(){
return [
`${this.prefixCls}`,
{[`${this.className}`]:!!this.className}
]
},
wrapStyles(){
let styles=Object.assign({},this.styles)
styles['z-index']=1010+this.tIndex
return styles
},
computedName(){
// 第一时间可能取不到这个值。这里要一定判断,因为我是取的下面的值
// 如果取不到会直接报错的,但是上面的取不到会再次尝试,不会出现报错
// if(this.notices[0]){
// return this.notices[0]['prefixCls']
// }
// 并不能用这个最后一个会有异常
// 还是直接加一个新的props参数吧
// 其实应该把第一个参数减一下,新的参数加起来,但是已经有了很多代码了.
}
},
methods:{
add(notice){
const name=notice.name||getUuid()
const tag=notice.tag||name
// 看传入的数据是否有tag,如果有tag并且和现在已经显示的tag有重合,则不在显示
this.notices.map((e)=>{
if(e.tag===tag){
console.log('已经有了,不在显示相同的数据了')
return
}
})
let _notice=Object.assign({
styles:{
},
content:'',
duration:1.5,
closable:false,
name:name,
tag:tag
// 这里全部设置的默认值
},notice);
this.notices.push(_notice)
},
close(name){
const notices=this.notices;
for(let i=0;i<notices.length;i++){
if(notices[i].name===name){
this.notices.splice(i,1)
break;
}
}
},
closeAll(){
this.notices=[]
},
handleGetIndex(){
// 这个函数不知道是干啥的
return this.seed++
},
},
mounted(){
}
}
</script>
<style lang="less" src="./index.less">
</style>
网友评论