前言:

  前两天在我的项目中很多场景下都须要用到一个toast弹窗,我的项目应用的是ionic+tialwind_Cssionic也有自带的toast弹窗,尽管大部分场景下间接调用它提供的api曾经能满足需要了,然而它弹窗的高度,(也就是弹窗呈现的地位)并不是高度自定义的,并且弹窗的z-index在咱们我的项目中会和一些组件抵触,然而这个之前始终没有方法解决,所以罗唆本人手写了一个应用办法高度相似ionic_Toast的组件。

这个组件也是我第一次在vue3下实现的,也查阅了很多网上相干的文章,也受到很多启发灵感,所以本人汲取精髓去其糟粕来实现了一版个人感觉应用起来很不便的一个版本,特来记录一下实现的过程,心愿能够帮忙到遇到同样蛊惑的人。

tips:(本篇文章不会上手就教你款式怎么写,代码怎么写,而是会帮你逐步一步步了解相干额定的常识。会以“如果我是一个初学者,如果过后有人这样通知我的话,我就大略能听明确”的角度去解释。所以篇幅较长,如果想间接看组件的实现,可间接跳转到题目三

在这里祝大家中秋节高兴呀~~

上面是注释:


一. 前置工作:JSX和渲染函数的概念

  1. 想要实现这个需要,你须要理解一下题目的那两个概念。官网文档在这里,外面的话语太过于“业余和官网”,导致我刚开始看的时候十分蛊惑,所以在这里我会帮你去了解外面的一些很官网的语言,让你疾速有个认知。

原地址在这里:vue官网文档JSX和渲染函数。

  1. 咱们暂且还不须要去深刻了解渲染机制的整个流程。所以官网上面个链接暂且不要去查阅,会让你越来越头晕。

    但在这里我要阐明一点,接下来讲的内容都是建设在我默认你对虚构DOM的概念有肯定的理解。
  2. 紧接就写到了Vue为咱们提供了一个函数,来创立vnodes。在浏览这个页面的时候,肯定留神官网在每个代码右上角的文件类型。

  1. 这里须要插个必须要理解的题外话,理解React的同学肯定晓得JSX这种写法

VueJSX的概念和ReactJSX的概念是极其类似的。Vue也是借鉴了React的这个思维,这里咱们重点看画线的这句话。(不相熟react的小伙伴也不要放心,本文实现的Toast并没有应用到JSXbabel。)

是不是感觉和刚刚Vue官网写的很类似?

官网在上文也提到了h是什么。如果咱们把h换成createVnode(),是不是就和React.createElement的用法及其类似了呢?

  1. 其实不论是Vue的h(),还是React.createElement() 它们最终要达到的目标只有一个:创立虚构DOM。而这也对应了VuecreateVnodeVnode其实就是virtual node的意思。函数名的间接翻译其实也就是创立虚构节点。而JSX只是创立虚构dom的语法题而已,仅此而已,并没有什么特别之处。

二. createVnode函数的意义

  1. 当初咱们在 .Vue文件写如下代码。

非常简单的构造,一个id是"hanzhenfang"的div标签,标签内容是我的名字。ok,这样写的话,vue就会帮咱们将这个构造转换为虚构dom。
实质上是应用了

h("div",{id:"hanzhenfang"},"韩振方")

h()能够有多个参数,

这段代码是在<template>标签内写的,它底层其实还是应用了h() 函数去实现的。说白了就是,React选用JSX来作为渲染虚构dom函数的语法糖。而<template>标签是Vue采纳的渲染虚构dom的语法糖。

从而能够引出官网的规范解释:

  1. 你可能会疑难了,既然模板能够实现这样的性能,那我间接写模版不就完事了吗?还须要写什么h() 函数呢?因为有的场景的确是模板做不到的。这也就是我为什么会写这篇文章的起因,因为这个toast需要应用的场景很多很多,我总不能在每个中央都引入一个组件通过v-if来管制它的显示和敞开吧?十分繁琐和麻烦。

三. 编写Toast组件(不应用tsx)

  1. 首先创立一个toast.vue文件写出大抵款式。因为是应用tailwindCss,所以款式书写的形式可能和传统的在style标签写款式不太一样,然而原理是一样的,不必放心。实现如下:

  1. toast在绝大场景下都是居中的,并且脱离文档流,位于整个页面的最顶部,所以我这里采纳了传统的相对定位的计划。

  1. 相对定位最简略居中计划不过与设置topleft50%。然而咱们不要疏忽了一点,偏移的时候,咱们还要减去本身宽度和高度的一半,才能够做到齐全居中。然而处于复用性思考,咱们的toast的宽度是不能设置固定宽度的,具体的宽度是由过后文字的大小决定的。

  1. 这时候咱们须要用到offsetWidth

1.额定技能补充 offsetWidth

  1. 先让咱们看看MDN如何解释的。

  1. 具体什么意思呢?咱们顺手写一个很简略的template

咱们当初不加任何Css属性,来查看一下offsetWidth是什么值。

不要把调试工具只当成console.log的中央,肯定利用好这个工具。咱们抉择刚刚写的元素,点击调试工具选项栏的Properties标签。

能够看到offsetWidth目前是20(留神,这是一个十进制的number类型,并不带单位,并且是一个只读属性,无奈间接更改。)
20是怎么来的呢?其实它就是咱们设置的字体大小。

来验证一下猜测,咱们设置一下字体大小为15px

  1. 当初给这个div加上10px宽度的border

别着急看offsetWidth的值,咱们依据它的定义猜测一下。

应该等于15px的字体大小+10px?

确定吗,别忘了border是上下左右都为10px,所以依据猜测
`offsetWidht=15px + 10px + 10px

  1. 如果这个div咱们本人设定宽度呢?咱们来给它设定100px的宽度。

咱们会发现offsetWidth的值变成了100

然而我明明有还有10pxborder啊!哪里去了?

你是否忘了咱们当初大部分状况下应用的都是box-size:border-box呢?设置的宽度是蕴含border的。

验证一下,咱们扭转一下box-size的类型。

能够看进去,offsetWidth就变成了100px+10px+10px

Tips:不过在本文中不会设置定宽去限度

四. Toast居中的思路

1.当初咱们能够不设置Toast的宽度,并且拿到依据文字数量不同所变动的宽度。因为这个属性是组件挂载结束当前才有的属性,那么咱们能够在onMounted里拿到。首先须要拿到元素自身,这里采纳打ref的形式。

具体变量和代码如下:不过多赘述

  1. 而后咱们须要通过一个计算属性动静的计算出该组件的款式;

ok,这样就实现了居中的成果。并且不论咱们如何扭转内容都没关系。居中成果是动静计算取得的,并不是一开始就写死的。

五. Toast三个呈现地位的思路

有些场景下Toast呈现在底部并不是特地适合,所以咱们还要思考呈现地位的问题。这里简略设计另外两个,一个两头,一个偏顶部。实现起来也比较简单。咱们让它toastWrapperStyle计算top的偏移量也是一个动静计算的就能够了。

咱们就能够在前面给这个组件传递参数来管制具体的地位在哪里。
这个目前的代码还动静的展现成果,咱们缓缓在前面体现。

tips:上面的章节是本文全篇重点

六*. h()函数的应用

  1. 咱们创立一个toastCreator.ts的文件,便于函数式调用展现Toast组件。

  1. 筹备如下内容,这里须要用到后面所提到的h(),还有render()render你暂且能够了解为给你返回一个实在的DOM。因为h() 是生成虚构dom的,然而咱们最终展现到页面的是实在dom,咱们之前不必在<template>标签内不必执行render是因为Vue帮你调用了render()。然而咱们在这里相当于手动实现一个Vue的渲染过程,所以咱们也同时须要用到这个函数。

  1. 同时把同文件夹下刚刚写好的Toast.vue引入。class相干的常识不是本文的重点,不理解的须要自行去查阅相干常识,这点很重要。
  2. 减少了一个duration选项,也就是持续时间,成果为Toast,在页面呈现多少秒后主动隐没。
  3. 而后咱们须要编写一个这个类自身的办法,名为present()(这里借鉴了ionicToast组件的调用名称。)
    这一步是重点,也是比拟难了解的一个点。

    1.首先咱们须要本人创立一个Vnode,通过翻阅官网。(留神咱们着重看JS的文件)。

2.咱们得悉,原来h() 函数能够间接接管一个组件模板作为参数。那么咱们能够这样写:

这样变量myToast就是一个Vnode了。

3.而后再调用引入的render() 函数,咱们天然而言的会想到这样写。

然而如同不太对劲啊,怎么报错了呢?看一下报错信息,原来render() 函数须要接管两个参数。第一个参数是Vnode,第二个参数是套在Vnode的实在dom。

让咱们创立并且加上一层外壳containner。其实就是一个一般的div标签。如下:

在这里要强调一下,你创立的虚构节点必须包裹一层实在的DOM作为容器。

这样正好对应,为什么Vue或者React组我的项目的根目录都会有一个.html文件,并且还有一个根div标签的起因。 因为render() 函数须要。(想更深刻理解原理的能够翻看源码,不再过多赘述。)

七. 如何传递props?

  1. Vnode实在DOM都有了,那咱们如何传递props呢?

2.这里不卖官子,先给后果,咱们须要革新一下咱们刚刚写的h() 函数。

这样即可将调用构造函数时传递的参数转换为该组件的props
因为篇幅限度,具体细节大家仔细阅读为下面贴出来的Vue官网文档。

八. 挂载实在DOM到页面上

都是根底的常识,不过多解释了,代码如下:

九. 持续时间的管制

  1. 编写dismiss() 办法。非常简单,间接移除这个节点即可。

  1. 持续时间如何管制呢?
    和工夫挂钩,自然而然能够想到setTimout()。实现原理其实也是非常简单。在特定的工夫,调用dismiss() 办法即可

十. Toast自定义组件的应用办法

  1. 忘了写message属性了,咱们补充一下

  1. 而后在App.vue文件引入

顺手写一个<button>标签。

成果如下:

3.测试一下 position:top

十一. 减少淡出的成果

咱们我的项目不须要淡入,所以我就没做,不过和淡出是一模一样,在这里我讲一下大抵思路。
只需在dismiss() 函数执行前,减少一个通明成果,这里应用的是减少类名,只不过这个动画名称是搭配tailWind来实现的,你也能够应用别的办法,我的办法并不是最好的,原理思路是统一的

  1. tailwind.config.js下设置全局动画款式。

这里须要留神!!你的动画持续时间要和dismiss()函数的setTimeout参数统一,不然会呈现意想不到的成果。动画完结了,后果组件又呈现啦。

2.再调用document.doby.removeChild办法之前,让咱们的组件在0.5s内透明度变为0,而后再移除组件,就完满实现了淡出的成果。

最终成果如下: