整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

vue2组件系列第九节:Toast 轻提示

vue2组件系列第九节:Toast 轻提示

oast轻提示是一个很轻的组件,不会像弹出层或者是弹出框兴师动众地展示出来有一种笨重地压迫感,它是在一个操作后的一个轻反馈,显示后会自动消失,不用人为去操作关闭,很是方便。

准备工作:

  1. 创建一个页面: Toast.vue
  2. 在router.js里配置 Toast页面的路由
{
 path: '/toast',
 name: 'toast',
 component: ()=> import('./views/Toast.vue')
 }
  1. 在index.vue里添加一项
<a href="javascript:void(0)" @click="$router.push('/toast')">
 <van-col span="6" class="marb20">
 <van-icon name="pending-deliver" />
 <div>Toast 轻提示</div>
 </van-col>
</a>

至今为止呢,我们的首页显示的样式子是这样滴?不知道不觉间我们已经学完了7个组件了!哇噢,为自己欢呼一下吧!如果想看更多的内容,欢迎关注我,每天都有更新哈。

代码演示Toast轻提示:

经常用的方法:

Toast: 展示提示;vue里为:

this.$toast("hello")

Toast.loading: 展示加载提示;

Toast.success:展示成功提示;vue里写为:

this.$toast.success("成功")

Toast.fail:展示失败提示;vue里写为:

this.$toast.fail("失败")

Toast.clear:关闭提示。

我们在这一季的一开始就将vant的所有组件引入了,Toast组件被引入之后,会自动将$toast方法挂载到Vue的prototype上,所以我们在调用的时候直接使用this.$toast...即可。

还需要说明的一点是,官网上说除了clear方法外,其它的方法都可以使用options设置,但经过本人测试后,虽然都不报错,但呈现最好的是loading方法。所以,如果想添加更多的设置的话,直接在Toast.loading方法上写。

上文有提到Options,这个Options是什么呢?是对展示的一些预设。主要包括以下几种预设:

type:提示的类型,主要有4个值:loading, success, fail, html(这个不知道有啥用意);

position:在垂直方向的展示位置,有三个值:top, middle, bottom;

message:提示的内容;

mask:是否显示蒙层,一般无用,加了感觉很重;

forbidClick:是否禁止点击背景;

loadingType:值为spinner,加载图标类型。如果前面有设置type值,这块不起效果。

duration:停留的时间长短。为0里,则永不消失。

下面主要演示一下$toast.loading({options}):

需求:点击按钮后展示toast,toast里会有倒计时,到0秒时,toast消失。如图:

我们先在DOM里创建一个触发按钮:

<van-button type="primary" @click="onClick">轻提示</van-button>

根据需求,我们需要改变message的内容,所以需要将loadding方法赋值给一个常量toast。

const toast=this.$toast.loading({
 duration: 0,
 position: 'middle',
 message: '倒计时3秒',
 forbidClick: true,
 loadingType: 'spinner'
})

如果有倒计时,我们肯定马上会想到setInterval(),开始喽!

let seconds=3;
var timer=setInterval(()=> { //定义计时器
 seconds--;
 if(seconds) { //seconds>0时
 toast.message="倒计时" + seconds + "秒" //注意这里
 } else { //seconds <=0时
 clearInterval(timer) //删除计时器
 this.$toast.clear() //消除提示
 } 
},1000)

这两段都是写在methods里的onClick里的哈?

到目前为止呢,Toast就演示完了!庆祝一下我们又学完一个组件啦!

今天就到这里啦。休息休息一会儿吧?明天继续加油噢!加油

最近需要做一个关于自动解析矢量瓦片链接地址的内部Demo,这个demo比较简单,所以没有准备引入任何的第三方UI库,所以遇到了一个小问题,toast提示怎么做?

如果像往常一样,我肯定直接用 alert 了,但是一是 alert 会中断体验,不够友好,二是不适用于多个提示共同出现,三是无法区分提示类型,所以我就想着找一个体积小的三方库来实现,但是找来找去,发现没有一个库能入我法眼。

在网上搜索,好像独立的 toast 插件停留在了 jq 时代,靠前的 toast 库居然是 bootstrap 的。所以我决定自己写一个,又小巧,又易用的 toast 插件。

纯 JS 实现

延续 autofit.js 的传统,我依然准备用纯 js 实现,以达到极致的体积、极致的兼容性。此外,还编写了d.ts,支持TS。

autolog.js 诞生了。

js部分(v2.0.0)

const cssStr=`#autolog{display:flex;flex-direction:column;align-items:center;justify-content:flex-start;pointer-events:none;width:100vw;height:100vh;position:fixed;left:0;top:0;z-index:9999999;cursor:pointer;transition:0.2s}#autolog span{pointer-events:auto;width:max-content;animation:fadein 0.4s;animation-delay:0s;border-radius:6px;padding:10px 20px;box-shadow:0 0 10px 6px rgba(0,0,0,0.1);margin:4px;transition:0.2s;z-index:9999999;font-size:14px;display:flex;align-items:center;justify-content:center;gap:4px;height:max-content}#autolog span.hide{opacity:0;pointer-events:none;transform:translateY(-10px);height:0;padding:0;margin:0}.autolog-warn{background-color:#fffaec;color:#e29505}.autolog-error{background-color:#fde7e7;color:#d93025}.autolog-info{background-color:#e6f7ff;color:#0e6eb8}.autolog-success{background-color:#e9f7e7;color:#1a9e2c}.autolog-{background-color:#fafafa;color:#333}@keyframes fadein{0%{opacity:0;transform:translateY(-10px)}100%{opacity:1;transform:translateY(0)}}`;
const svgIcons={
  warn: `<svg t="1713405237257" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2387" xmlns:xlink="http://www.w3.org/1999/xlink" width="16" height="16"><path d="M934.4 770.133333L605.866667 181.333333C586.666667 147.2 550.4 128 512 128c-38.4 0-74.666667 21.333333-93.866667 53.333333L89.6 770.133333c-19.2 34.133333-19.2 76.8 0 110.933334S145.066667 938.666667 183.466667 938.666667h657.066666c38.4 0 74.666667-21.333333 93.866667-57.6 19.2-34.133333 19.2-76.8 0-110.933334z m-55.466667 81.066667c-8.533333 14.933333-23.466667 23.466667-38.4 23.466667H183.466667c-14.933333 0-29.866667-8.533333-38.4-23.466667-8.533333-14.933333-8.533333-34.133333 0-49.066667L473.6 213.333333c8.533333-12.8 23.466667-21.333333 38.4-21.333333s29.866667 8.533333 38.4 21.333333l328.533333 588.8c8.533333 14.933333 8.533333 32 0 49.066667z" fill="#e29505" p-id="2388"></path><path d="M512 746.666667m-42.666667 0a42.666667 42.666667 0 1 0 85.333334 0 42.666667 42.666667 0 1 0-85.333334 0Z" fill="#e29505" p-id="2389"></path><path d="M512 629.333333c17.066667 0 32-14.933333 32-32v-192c0-17.066667-14.933333-32-32-32s-32 14.933333-32 32v192c0 17.066667 14.933333 32 32 32z" fill="#e29505" p-id="2390"></path></svg>`,
  error: `<svg t="1713405212725" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1744" xmlns:xlink="http://www.w3.org/1999/xlink" width="16" height="16"><path d="M512 74.666667C270.933333 74.666667 74.666667 270.933333 74.666667 512S270.933333 949.333333 512 949.333333 949.333333 753.066667 949.333333 512 753.066667 74.666667 512 74.666667z m0 810.666666c-204.8 0-373.333333-168.533333-373.333333-373.333333S307.2 138.666667 512 138.666667 885.333333 307.2 885.333333 512 716.8 885.333333 512 885.333333z" fill="#d93025" p-id="1745"></path><path d="M657.066667 360.533333c-12.8-12.8-32-12.8-44.8 0l-102.4 102.4-102.4-102.4c-12.8-12.8-32-12.8-44.8 0-12.8 12.8-12.8 32 0 44.8l102.4 102.4-102.4 102.4c-12.8 12.8-12.8 32 0 44.8 6.4 6.4 14.933333 8.533333 23.466666 8.533334s17.066667-2.133333 23.466667-8.533334l102.4-102.4 102.4 102.4c6.4 6.4 14.933333 8.533333 23.466667 8.533334s17.066667-2.133333 23.466666-8.533334c12.8-12.8 12.8-32 0-44.8l-106.666666-100.266666 102.4-102.4c12.8-12.8 12.8-34.133333 0-46.933334z" fill="#d93025" p-id="1746"></path></svg>`,
  info: `<svg t="1713405208589" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1582" xmlns:xlink="http://www.w3.org/1999/xlink" width="16" height="16"><path d="M853.333333 138.666667H170.666667c-40.533333 0-74.666667 34.133333-74.666667 74.666666v512c0 40.533333 34.133333 74.666667 74.666667 74.666667h151.466666V917.333333c0 12.8 8.533333 25.6 19.2 29.866667 4.266667 2.133333 8.533333 2.133333 12.8 2.133333 8.533333 0 17.066667-4.266667 23.466667-10.666666l136.533333-138.666667H853.333333c40.533333 0 74.666667-34.133333 74.666667-74.666667V213.333333c0-40.533333-34.133333-74.666667-74.666667-74.666666z m10.666667 586.666666c0 6.4-4.266667 10.666667-10.666667 10.666667H501.333333c-8.533333 0-17.066667 4.266667-23.466666 10.666667l-89.6 93.866666V768c0-17.066667-14.933333-32-32-32H170.666667c-6.4 0-10.666667-4.266667-10.666667-10.666667V213.333333c0-6.4 4.266667-10.666667 10.666667-10.666666h682.666666c6.4 0 10.666667 4.266667 10.666667 10.666666v512z" fill="#0e6eb8" p-id="1583"></path><path d="M512 490.666667H298.666667c-17.066667 0-32 14.933333-32 32S281.6 554.666667 298.666667 554.666667h213.333333c17.066667 0 32-14.933333 32-32S529.066667 490.666667 512 490.666667zM672 341.333333H298.666667c-17.066667 0-32 14.933333-32 32S281.6 405.333333 298.666667 405.333333h373.333333c17.066667 0 32-14.933333 32-32s-14.933333-32-32-32z" fill="#0e6eb8" p-id="1584"></path></svg>`,
  success: `<svg t="1713405224326" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2225" xmlns:xlink="http://www.w3.org/1999/xlink" width="16" height="16"><path d="M512 74.666667C270.933333 74.666667 74.666667 270.933333 74.666667 512S270.933333 949.333333 512 949.333333 949.333333 753.066667 949.333333 512 753.066667 74.666667 512 74.666667z m0 810.666666c-204.8 0-373.333333-168.533333-373.333333-373.333333S307.2 138.666667 512 138.666667 885.333333 307.2 885.333333 512 716.8 885.333333 512 885.333333z" fill="#1a9e2c" p-id="2226"></path><path d="M701.866667 381.866667L448 637.866667 322.133333 512c-12.8-12.8-32-12.8-44.8 0-12.8 12.8-12.8 32 0 44.8l149.333334 149.333333c6.4 6.4 14.933333 8.533333 23.466666 8.533334s17.066667-2.133333 23.466667-8.533334l277.333333-277.333333c12.8-12.8 12.8-32 0-44.8-14.933333-12.8-36.266667-12.8-49.066666-2.133333z" fill="#1a9e2c" p-id="2227"></path></svg>`,
};
const autolog={
  log(text, type="", time=2500) {
    if (typeof type==="number") {
      time=type;
      type="";
    }
    let mainEl=getMainElement();
    let el=document.createElement("span");
    el.className=`autolog-${type}`;
    el.innerHTML=svgIcons[type] + text;
    mainEl.appendChild(el);
    setTimeout(()=> {
      el.classList.add("hide");
    }, time - 500);
    setTimeout(()=> {
      mainEl.removeChild(el);
      el=null;
    }, time);
  },
};
function getMainElement() {
  let mainEl=document.querySelector("#autolog");
  if (!mainEl) {
    mainEl=document.createElement("div");
    mainEl.id="autolog";
    document.body.appendChild(mainEl);
    let style=document.createElement("style");
    style.innerHTML=cssStr;
    document.head.insertBefore(style, document.head.firstChild);
  }
  return mainEl;
}
export default autolog;

以上是 autolog.js的全部 js 代码。可以看到只导出了一个 log 方法,而调用此方法,也只需要必填一个参数。

我来讲一下这段代码干了一件什么事

  1. 因为有两个可选参数,所以第一步判断一下传了哪个可选参数,这可以在使用时,只传time或者type。
  2. 获取主容器,getMainElement 方法返回一个主容器,若主容器不存在,就创建它,这省去了用户手动创建主容器的过程,一般的插件会导出一个 init 方法初始化,这一步可以省去 init 操作。
  3. 创建一个 span 标签用于展示 log 内容。
  4. 两个定时器,第一个在清除元素的前 0.5 秒为其添加退场动画,第二个清除元素,el=null 可以保证断开引用,防止产生游离dom,防止内存泄漏。

最重要的在于css部分,css承载了最重要的显示逻辑。

css部分

没有什么巧妙的设计,也没有什么精致的构思,朴实无华的一百多行代码而已,希望这些代码可以帮到各位。

安装和使用

使用也非常简单,只需引入 两个文件 一个文件。

安装

import aotolog from "autolog.js";

autolog.log("Hi,this is a normal tip");
autolog.log("Hello World", "success", 2500);
// 其中 "success" 和 2500 都是可选项

#### 引入css(引入一次即可)

在js中引入

在css中引入

v2.0.0以上无需引入css

使用

js

效果图



原文链接:https://juejin.cn/post/7358598695267008527

想要写好代码,设计模式(Design Pattern)是必不可少的基本功,设计模式是对面向对象设计(Object Oriented Design)中反复出现的问题的解决方案,本篇从最简单的单例模式(Singleton Pattern)开讲。


单例模式属于创建型模式(Builder Pattern),意图在于保证一个类仅有一个实例,并提供一个访问它的全局访问点。单例模式在内存中仅创建一次对象,即使多次实例化该类,也只返回第一次实例化后的实例对象,不仅能减少不必要的内存开销,并且在减少全局的函数和变量也具有重要的意义。


实现方式上,主要有懒汉式(Lazy Singleton)、饿汉式(Eager Singleton),多线程场景下需要注意线程安全。


场景上,最常用于全局配置管理,其次在IO操作、前端交互等需要保证对象唯一的场景,也可以使用。


01

单例模式的实现方式


在golang中单例模式的实现方式有多种,这里介绍下使用init和sync.Once方式实现线程安全的单例。


其中init函数是在文件包首次被加载的时候执行并且只执行一次(Eager Singleton,饿汉模式),sync.Once是在代码运行需要的时候执行且只执行一次(Lazy Singleton,懒汉模式)。init函数方式直接创建好对象,不需要判断对象是否为空并持续占有在内存中,sync.Once是Go语言实现的一种对象,其相对高效且并发安全的实现原理主要是依赖于sync/atomic包的原子操作,在sync.Once的底层实现中,使用一个变量done来记录函数的执行状态,使用sync.Mutex和sync.atomic来保证线程安全的读取done,以保证某种行为只会被执行一次。需要注意的是once.Do(f func()) 方法不能嵌套,若f在执行过程中也会调用once.Do,会导致死锁。


在golang一些server业务场景应用中,通常会用到一些resource,如常用的:DB、Redis、Logger等,这些资源的实例化对象会在每个请求中频繁的使用,如果在每个请求的处理进程中频繁创建和释放这些资源对象,则会造成较大的系统资源开销,但如果使用单例的方式创建这些资源对象则能避免这些问题,通常实际使用场景中会在main主进程中的HTTPServer携程启动前,通过init或sync.One的方式创建单例对象提供各HTTPServer携程使用,从而保证各个请求处理进程中使用同一个实例对象。

  • ......var ( oResource sync.Once
    initFuncList=[]initFunc{ mustInitLoggers, // 初始化Log mustInitServicer, // 初始化servicer以及ral mustInitGorm, // 初始化mysql gorm mustInitRedis, // 初始化redis mustInitOther, // 初始化other })
    type initFunc func(context.Context) func() error
    // MustInit 按顺序初始化app所需的各种资源func MustInit(ctx context.Context) (f func() error) { oResource.Do(func() { callbackList :=make([]func() error, 0, len(initFuncList)) for _, f :=range initFuncList { callbackList=append(callbackList, f(ctx)) }
    f=func() (err error) { for i :=len(callbackList) - 1; i >=0; i-- { if callbackList[i] !=nil { e :=callbackList[i]() if err==nil { err=e } } } return } })
    return}
    ......


    02

    单例模式在配置管理中的应用


    在Python中,一个很普遍的应用场景就是利用单例模式来实现全局的配置管理。对于大部分的系统,通常都会有一个或者多个配置文件用于存放系统运行时所依赖的各种配置信息,在系统运行的过程中通过代码读取并解析配置文件从而获得对应的配置信息,而且在运行过程中当配置文件发生变更以后还需要实时更新对应的配置信息。


    在这个场景里面,如果每次使用重新读取和加载配置,会有以下问题:

    • 增加耗时:带来额外的时间开销,额外的开销时间和读取次数成正比。

    • 增加内存:带来额外的内存开销,额外的内存占用和对象的实例个数成正比。


    在这个场景里面,有一个典型的特征:需要反复获相同配置文件的内容,配置文件的内容可能会发生变更,所以这个场景就比较合适通过单例模式来实现。即在系统初始化或者首次使用配置的时候加载文件并解析生成一个配置类对象,同时这个对象会实时监听文件内容变更并更新对象的对应属性,后续每次都直接使用这个对象获取文件内容即可。这样即可解决反复读取文件初始化对象以及监听文件变更所来的额外时间和空间开销。


    以下为基于Python实现的Demo:

    • # runtime_conf.py
      class RuntimeConf(object): """ 单例模式实现的运行时全局配置类 1、用于解析配置文件并封装成对象属性方便使用 2、持续监听配置文件,发生变更后自动更新实例对象属性 """
      def __new__(cls): if not hasattr(cls, '_instance'): # 1、初始化实例对象 cls._instance=super(RuntimeConf, cls).__new__(cls)
      # 2、加载配置文件 cls._instance.load_config()
      # 3、持续开启一个新线程持续监听文件变化,文件发生变更以后更新实例属性 cls._instance.__watch_async()
      return cls._instance
      def __watch_async(self): """ 私有的监听配置文件方法,如果配置文件发生变更,重新读取配置文件并加载到 self.__data 属性 :return: """ # 以下仅为示例思路,具体实现文件监听可复用第三方框架,例如 pyinotify changed=False
      # ......
      # 如果文件发生变更,重新加载 if changed: self.__load_config()
      def __load_config(self): """ 私有读取配置文件并加载到对象属性中 :return: """ # 读取配置文件并存储到self.__data属性 self.__data={ "key1": 1, "key2": 2 } print("load config success")
      def get(self, key): """ 读取配置 :param key: :return: """ return self.__data.get(key, None)

      if __name__=='__main__': # 初始化两个对象,输出对象的内存地址,可以发现两个变量都是指向同一个内存地址,即是同一个对象 conf_1=RuntimeConf() conf_2=RuntimeConf() print(conf_1) print(conf_2) print(conf_1.get("key1")) print(conf_2.get("key2"))

      03

      单例模式在IO操作的应用


      在PHP中,单例模式一个典型的应用场景,就是IO操作,典型的有数据库、文件操作等,作用在于维护一个全局变量,去管理连接实例。


      以典型的PHP站点为例,在标准的MVC结构下,单次网络请求相应过程中,会涉及到多个不同Model的实例化,而每个Model实例又需要进行数据库操作,这里就需要维护全局唯一的数据库连接实例,一般用单例模式进行维护。如果每个Model在实例化时,都建立新的连接,显然是不合理的,会有以下问题:

      • 资源浪费:频繁建立连接,增加网络耗时、CPU&内存开销。

      • 无法提交事务:多条SQL语句,不是一个连接提交,无法完整的提交数据库事务。

      在这个场景下,我们可以用单例模式解决,单例类可以具备私有的构造函数,并且提供静态方法供外界获取它的实例,外部首次获取时,每次获取到的是同一个对象,由这个对象维护数据库连接。

      以下为基于PHP实现的Demo:

      • class DBHandler { private static $instance=; //私有实例 public $conn; //数据库连接
        //私有构造函数 private function __construct() { $this->conn=new PDO('hostname', 'account', 'password'); }
        //静态方法,用于获取私有实例 public static function getInstance() { if (self::$instance==) { self::$instance=new DBHandler(); } return self::$instance; } public function fetch() {...}}
        class ModelA { private $dbHandler; public function __construct() { $this->dbHandler=DBHandler->getInstance(); } public function getA() { return $this->dbHandler->fetch($sql); }}
        class ModelB { private $dbHandler; public function __construct() { $this->dbHandler=DBHandler->getInstance(); } public function getB() { return $this->dbHandler->fetch($sql); }}
        $modelA=new ModelA();$modelB=new ModelB();$modelA->getA();$modelB->getB();


        04

        单例模式在前端交互的应用


        在前端开发中,单例模式的使用十分常见,很多第三方库和框架都应用了单例模式。比如最常用的 js 库 jQuery,它暴露了一个 jQuery 实例,多次引用都只会使用该实例对象。这样的模式,减少了全局变量的创建,并且能够避免变量冲突。


        实现单例模式常见的方式有:首先创建一个类,这个类包含一个静态方法,用于创建这个类的实例对象;还存在一个标记,标识实例对象是否已经创建过,如果没有,则创建实例对象并返回;如果创建过,就直接返回首次创建的实例化对象的引用。


        在实际应用中,我们常使用单例模式来管理页面中的弹窗,避免页面中同时展现多个互相重叠的弹窗:可以创建一个 Toast 弹窗类,并初始化弹窗节点。这个类提供一个静态方法 getInstance 来创建并返回实例对象,这样业务在创建弹窗时就不需要再进行实例化的操作。业务可以通过 show 和 hide 方法来控制弹窗的展现和隐藏,但即使执行多次 show 方法,也只会展现一个弹窗,因为业务使用的是同一个实例对象。这个类在页面运行时会一直存在,除非没有了对这个类的引用,它则会被垃圾回收。


        以下为基于JavaScript实现的Demo:

        • // 弹窗组件 toast.jsclass Toast { constructor() { this._init(); } // 私有方法,业务不允许直接调用该方法来创建弹窗 _init(){ const toast=document.createElement('div'); toast.classList.add('toast'); toast.innerHTML='这是一个弹窗'; document.body.append(toast); } show() { document.querySelector('.toast').style.display='block'; } hide() { document.querySelector('.toast').style.display='none'; } // 静态方法,业务操作弹窗时不需要再实例化 static getInstance() { if(!this.instance) { this.instance=new Toast(); } return this.instance; }}// 在组件中把对唯一的实例对象 loginToast 的引用暴露出去const toast=Toast.getInstance();export default toast;
          // 业务调用import toast from './xxx/toast';toast.show();


          本文由高可用架构转载。技术原创及架构实践文章,欢迎通过公众号菜单「联系我们」进行投稿。


          高可用架构
          改变互联网的构建方式