发布网友 发布时间:2024-10-05 06:58
共1个回答
热心网友 时间:2024-12-14 19:06
前言实现过一个vue2+ts下的全局的Message提示框。闲暇之余想在vue3+ts的框架下也实现此功能。
技术思路install函数是把编写的Message组件实例化并渲染到页面的关键。其中的步骤:
根据Message组件实例化一个Message
在document.body上appendChild实例
同时返回一个destory函数用于手动销毁实例
倒计时时间到销毁实例
编写Message组件代码//Mssage.vue<template><transitionname="slide"><div:class="[type,center?'text-center':'']":style="{...style}"v-if="visible"><divv-if="messageArr.length"><divv-for="(item,index)inmessageArr":key="index">{{item}}</div></div><divv-else>{{message}}</div></div></transition></template><script>import{defineComponent}from'vue';exportdefaultdefineComponent({props:{message:{type:String,default:'',},type:{type:String,default:'success',},ration:{type:Number,default:2000,},},data(){constmessageArr:Array<string>=[];conststyle={};return{messageArr,visible:true,center:false,style,};},created():void{constarr=this.message.split('\n');if(arr.length>1){this.messageArr=arr;}},mounted():void{this.startTimer();},methods:{startTimer():void{const{ration}=this;consttimer=setTimeout(()=>{this.visible=false;clearTimeout(timer);},ration);},},});</script>编写install函数并挂载到vue全局//index.tsimport{App,render,createVNode}from'vue';importMessagefrom'./Message.vue';constdefaultOpt={//创建默认参数ration:2000,type:'success',};//消息数组conststack:Array<HTMLDivElement>=[];/***@description:销毁body上的Message实例*@param{HTMLDivElement}ele*@return{*}*/constremoveContainer=(ele:HTMLDivElement):void=>{constindex=stack.findIndex((item)=>item===ele);if(~index){stack.splice(index,1);setStyle();}};/***@description:把实例加到实例队列stack中,并设置队列中搜有实例的style*@param{HTMLDivElement}ele*@return{*}*/constaddContainer=(ele:HTMLDivElement):void=>{stack.push(ele);setStyle();};/***@description:设置stack中所有实例的style*@param{*}*@return{*}*/constsetStyle=()=>{stack.forEach((item,index)=>{if(item?.getElementsByClassName('message-wrap')?.[0]){lettop=0;if(index>0){top+=(stack[index-1].getElementsByClassName('message-wrap')[0]asHTMLElement)?.getBoundingClientRect()?.bottom||0;}//eslint-disable-next-line(item.getElementsByClassName('message-wrap')[0]asHTMLElement).style.marginTop=`${top}px`;}});};//创建挂载实例//eslint-disable-next-lineconstcreateMount=(opts:{[key:string]:any})=>{const{ration}=opts;//创建一个div容器constcontainer=document.createElement('div');//创建Message实例,createVNode的性能比h更好constvm=createVNode(Message,opts);//把实例render到容器上render(vm,container);addContainer(container);//把容器渲染到body上document.body.appendChild(container);constdestory=()=>{consttimer=setTimeout(()=>{render(null,container);removeContainer(container);document.body.removeChild(container);clearTimeout(timer);},500);//500为动画结束时间,根据情况修改};consttimer=setTimeout(()=>{destory();clearTimeout(timer);},ration||defaultOpt.ration);return{destory};};functionToast(options:{message:string;ration?:number}|string):{destory:()=>void;}{if(typeofoptions==='string'){//eslint-disable-next-lineoptions={...defaultOpt,message:options||'',};}else{//eslint-disable-next-lineoptions={...defaultOpt,...options,};}returncreateMount(options);}Toast.install=(app:App<Element>)=>{app.component('toast',Message);app.provide('Toast',Toast);//挂载Toast为全局方法$toast//eslint-disable-next-lineapp.config.globalProperties.$toast=Toast;};exportdefaultToast;use为全局组件;增加$toast声明,消除使用时的ts报错import{createApp}from'vue';importToastfrom'@/components/toast';constapp=createApp(App);app.use(Toast);app.mount('#app');//定义了全局方法之后需要扩充类型declaremole'@vue/runtime-core'{interfaceComponentCustomProperties{$toast:typeofToast;}}使用this.$toast('message');this.$toast({message:'message',tation:5000,})和vue2上的对比vue2vue3创建方式1.先创建构造函数constMessageBox=Vue.extend(MessageComp);2.通过构造函数实例化对象constinstance:any=newMessageBox({data:options,}).$mount();1.先创建一个div容器constcontainer=document.createElement('div');2.createVNode创建组件实例constvm=createVNode(Message,opts);3.把实例render到容器上render(vm,container);tipsvue2版本?:https://juejin.cn/post/7015199722805657631