从零开始徒手撸一个 vue 的 toast 弹窗组件 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐关注
Meteor
JSLint - a Javascript code quality tool
jsFiddle
D3.js
WebStorm
推荐书目
Javascript 权威指南第 5 版
Closure: The Definitive Guide
noahlam
V2EX    Javascript

从零开始徒手撸一个 vue 的 toast 弹窗组件

  •  
  •   noahlam 2018-05-11 17:28:55 +08:00 3142 次点击
    这是一个创建于 2714 天前的主题,其中的信息可能已经有所发展或是发生改变。

    相信普通的 vue 组件大家都会写,定义 -> 引入 -> 注册 -> 使用,行云流水,一气呵成,但是如果我们今天是要自定义一个弹窗组件呢?

    首先,我们来分析一下弹窗组件的特性(需求): 0. 轻量 --一个组件小于 1Kib (实际打包完不到 0.8k)

    1. 一般都是多处使用 --需要解决每个页面重复引用+注册
    2. 一般都是跟 js 交互的 --无需 在<template>里面写 <toast :show="true" text="弹窗消息"></toast>

    今天,我们就抱着上面 2 个需求点,来实现一个基于 vue 的 toast 弹窗组件,下图是最终完成的效果图.

    step_3

    一. 先写一个普通的 vue 组件

    文件位置 /src/toast/toast.vue

    <template> <div class="wrap">我是弹窗</div> </template> <style scoped> .wrap{ position: fixed; left: 50%; top:50%; background: rgba(0,0,0,.35); padding: 10px; border-radius: 5px; transform: translate(-50%,-50%); color:#fff; } </style> 

    二. 在我们需要使用的页面引入组件,方便看效果和错误

    <template> <div id="app"> <toast></toast> </div> </template> <script> import toast from './toast/toast' export default { components: {toast}, } </script> 

    step_1

    三. 实现动态加载组件

    可以看到,已经显示出一个静态的弹出层了,接下来我们就来看看如何实现动态弹出.

    我们先在 /src/toast/ 目录下面,新建一个index.js, 然后在 index.js 里面,敲入以下代码(由于该代码耦合比较严重,所以就不拆开一行一行讲解了,改成行内注释)

    文件位置 /src/toast/index.js

    import vue from 'vue' // 这里就是我们刚刚创建的那个静态组件 import toastComponent from './toast.vue' // 返回一个 扩展实例构造器 const ToastCOnstructor= vue.extend(toastComponent) // 定义弹出组件的函数 接收 2 个参数, 要显示的文本 和 显示时间 function showToast(text, duration = 2000) { // 实例化一个 toast.vue const toastDom = new ToastConstructor({ el: document.createElement('div'), data() { return { text:text, show:true } } }) // 把 实例化的 toast.vue 添加到 body 里 document.body.appendChild(toastDom.$el) // 过了 duration 时间后隐藏 setTimeout(() => {toastDom.show = false} ,duration) } // 注册为全局组件的函数 function registryToast() { // 将组件注册到 vue 的 原型链里去, // 这样就可以在所有 vue 的实例里面使用 this.$toast() vue.prototype.$toast = showToast } export default registryToast 

    附一个传送门 vue.extend 官方文档

    四. 试用

    到这里,我们已经初步完成了一个可以全局注册和动态加载的 toast 组件,接下来我们来试用一下看看

    1. 在 vue 的入口文件(脚手架生成的话是./src/main.js) 注册一下组件

    文件位置 /src/main.js

    import toastRegistry from './toast/index' // 这里也可以直接执行 toastRegistry() Vue.use(toastRegistry) 
    1. 我们稍微修改一下使用方式,把第二步 的引用静态组件的代码,改成如下
    <template> <div id="app"> <input type="button" value="显示弹窗" @click="showToast"> </div> </template> <script> export default { methods: { showToast () { this.$toast('我是弹出消息') } } } </script> 

    step_2

    可以看到,我们已经不需要在页面里面引入注册组件,就可以直接使用this.$toast()了.

    五. 优化

    现在我们已经初步实现了一个弹窗.不过离成功还差一点点,缺少一个动画,现在的弹出和隐藏都很生硬.

    我们再对 toast/index.js 里的showToast函数稍微做一下修改(有注释的地方是有改动的)

    文件位置 /src/toast/index.js

    function showToast(text, duration = 2000) { const toastDom = new ToastConstructor({ el: document.createElement('div'), data() { return { text:text, showWrap:true, // 是否显示组件 showContent:true // 作用:在隐藏组件之前,显示隐藏动画 } } }) document.body.appendChild(toastDom.$el) // 提前 250ms 执行淡出动画(因为我们再 css 里面设置的隐藏动画持续是 250ms) setTimeout(() => {toastDom.showCOntent= false} ,duration - 1250) // 过了 duration 时间后隐藏整个组件 setTimeout(() => {toastDom.showWrap = false} ,duration) } 

    然后,再修改一下 toast.vue 的样式

    文件位置 /src/toast/toast.vue

    <template> <div class="wrap" v-if="showWrap" :class="showContent ?'fadein':'fadeout'">{{text}}</div> </template> <style scoped> .wrap{ position: fixed; left: 50%; top:50%; background: rgba(0,0,0,.35); padding: 10px; border-radius: 5px; transform: translate(-50%,-50%); color:#fff; } .fadein { animation: animate_in 0.25s; } .fadeout { animation: animate_out 0.25s; opacity: 0; } @keyframes animate_in { 0% { opacity: 0; } 100%{ opacity: 1; } } @keyframes animate_out { 0% { opacity: 1; } 100%{ opacity: 0; } } </style> 

    大功告成,一个 toast 组件初步完成

    step_3

    总结

    1. vue.extend 函数可以生成一个 组件构造器 可以用这个函数构造出一个 vue 组件实例
    2. 可以用 document.body.appendChild() 动态的把组件加到 body 里面去
    3. vue.prototype.$toast = showToast 可以在全局注册组件
    4. 显示动画比较简单,隐藏动画必须要在隐藏之前预留足够的动画执行时间
    5. 本文源码地址 在这里
    6. 以上都不重要,重要的是 给本文来个star
    目前尚无回复
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     5250 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 24ms UTC 05:46 PVG 13:46 LAX 22:46 JFK 01:46
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86