oast輕提示是一個很輕的組件,不會像彈出層或者是彈出框興師動眾地展示出來有一種笨重地壓迫感,它是在一個操作后的一個輕反饋,顯示后會自動消失,不用人為去操作關閉,很是方便。
準備工作:
{ path: '/toast', name: 'toast', component: ()=> import('./views/Toast.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 插件。
延續 autofit.js 的傳統,我依然準備用純 js 實現,以達到極致的體積、極致的兼容性。此外,還編寫了d.ts,支持TS。
autolog.js 誕生了。
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 方法,而調用此方法,也只需要必填一個參數。
我來講一下這段代碼干了一件什么事
最重要的在于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
在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.js
class 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();
本文由高可用架構轉載。技術原創及架構實踐文章,歡迎通過公眾號菜單「聯系我們」進行投稿。
*請認真填寫需求信息,我們會在24小時內與您取得聯系。