首頁

淘寶、拼多多為什么要讓你玩游戲?

前端達人

從支付寶螞蟻森林開始,游戲化產(chǎn)品開始回歸移動互聯(lián)網(wǎng)領域。拼多多上線“多多果園”后,通過玩游戲免費領水果的玩法,引發(fā)了電商游戲化產(chǎn)品的風潮。淘寶、天貓、京東、蘇寧等互聯(lián)網(wǎng)平臺紛紛推出了自己的游戲產(chǎn)品。那么游戲化到底能夠為產(chǎn)品帶來什么呢?
一、什么是游戲化
游戲化(Gamification)是指將游戲元素和游戲設計技術應用于非游戲場景,用游戲化機制創(chuàng)造樂趣來更好地實現(xiàn)目標。也就是說,通過游戲的方式,為非游戲化的場景或產(chǎn)品賦能,讓用戶在使用產(chǎn)品過程中獲得更多的樂趣,創(chuàng)造更大的產(chǎn)品價值。



1.png


隨著移動互聯(lián)網(wǎng)的快速發(fā)展,人口紅利逐漸消失,電商領域開始從增量市場進入存量市場。當用戶數(shù)量無法持續(xù)有效增長時,就需要深挖存量用戶的價值,通過精細化運營,提高DAU(用戶日活)來獲取更大的用戶價值。
2016年8月27日,支付寶上線螞蟻森林。2017年數(shù)據(jù)顯示,由于螞蟻森林擁有遠超平常應用的用戶黏性,產(chǎn)品已擁有超過2億用戶,帶來的日活不可小覷。
2017年8月6日,支付寶又上線了螞蟻莊園。2019年11月20日,螞蟻莊園官方微博對外發(fā)布了運營大數(shù)據(jù)。該數(shù)據(jù)顯示,螞蟻莊園上線至今,全國約4億網(wǎng)友捐了150億個雞蛋。
這兩款游戲化產(chǎn)品引爆了用戶的熱情,為傳統(tǒng)的支付工具添加了游戲化屬性,開創(chuàng)了移動互聯(lián)網(wǎng)時代“種樹養(yǎng)雞”的娛樂化模式。


2.png


隨后,2018年4月,拼多多上線了“多多果園”,在電商領域率先開啟了游戲化模式。于是游戲化產(chǎn)品在電商平臺上開始生根發(fā)芽。
2018年11月,京東上線了“種豆得豆”;
2019年1月,淘寶上線了“金幣莊園”;
2019年5月,蘇寧易購上線了“云鉆魔法獅”;

據(jù)不完全統(tǒng)計,主流電商都推出了多款游戲化產(chǎn)品。清單如下:


3.png


二、游戲化產(chǎn)品的價值
目前在電商領域,游戲化產(chǎn)品主要是作為流量產(chǎn)品存在的,核心目標是為了增強平臺的用戶粘性,盤活現(xiàn)有的存量用戶,提高用戶活躍度。

4.png


在游戲化產(chǎn)品未出現(xiàn)前,各大電商基本采用的是“簽到”送獎勵的形式,提升用戶活躍度。從短期效果上,簽到同樣可以帶給用戶強烈的激勵。然而虛擬幣在購物過程中才能形成價值感知,所以單純虛擬幣總量的積累無法形成持續(xù)性的激勵,用戶容易產(chǎn)生厭倦心理。
同時為了平衡商業(yè)價值,虛擬幣必然帶有一定的使用門檻,因此簽到價值與用戶的購買鏈路無法即時匹配。用戶在購物過程中,無法使用虛擬幣時,必然會產(chǎn)生一定的負面情緒。
5.png



為了彌補簽到行為中情感體驗的缺失,電商平臺開始通過游戲化對“簽到”產(chǎn)品進行了包裝升級。相比較傳統(tǒng)的簽到產(chǎn)品,游戲化產(chǎn)品的優(yōu)勢在哪里呢?
我認為有以下幾個方面:
6.png


1、形成內(nèi)部觸發(fā)
根據(jù)上癮模型理論,用戶上癮需要有一個“觸發(fā)”。而內(nèi)部觸發(fā)是產(chǎn)品在用戶內(nèi)心、情感層面上建立的一種潛意識的認知,是產(chǎn)品和用戶之間最有力的紐帶。
基于游戲“八角行為激勵模型”,在產(chǎn)品設計中,可以通過多種手段不斷激勵用戶參與到游戲中(具體內(nèi)容參見下一篇文章)。用戶進入了游戲后,無論是激勵體系、游戲玩法,還是視覺設計,都可以更好的觸發(fā)用戶的情感體驗點。
同時成長體系、成就體系、好友排名等激勵,為用戶設定了更加豐富和明確目標,讓用戶更持久的投入到游戲的玩法中,并逐步在用戶意識中形成內(nèi)部觸發(fā),讓產(chǎn)品具有更高的用戶粘性。


7.png


例如螞蟻森林對于用戶不僅僅是每日7點左右收取能量,更多的是在拿起手機不由自主的打開支付寶,查看有沒有能量可以收取。
2、深度激活用戶
傳統(tǒng)的簽到為每日活動,用戶更傾向于完成即走,用戶鏈路短,無法挖掘用戶的潛在價值。
而游戲玩法豐富,增強了用戶鏈路,同時將玩法細化到小時級的顆粒度,激活用戶的活躍度。例如在金幣莊園中植物在4個小時內(nèi)即可成熟采摘,促使用戶多次打開產(chǎn)品收取果實。
游戲的任務也更加靈活,通過頻次可以滿足不同的用戶的需要。深度玩家可以反復多次完成任務,普通玩家可以靈活參與,因此對用戶的覆蓋更廣,也有利于普通用戶升級為深度玩家。多次和定時的任務,用戶需要頻繁的進出游戲來獲取獎勵,從而極大的提高了用戶的活躍度,逐漸培養(yǎng)用戶玩游戲的習慣。


8.png


3、增加用戶停留、提高用戶轉化
用戶的停留時長其實是一種零和博弈,面對激烈的市場競爭,用戶在一個平臺的停留時長增加,必然會導致另一個平臺停留時長的下降。因此大電商在關注用戶活躍度的同時,也開始爭奪用戶停留時長。
游戲化產(chǎn)品擁有更加細化的游戲玩法和任務,無形之中增加了用戶的停留時長。同時也為產(chǎn)品提供了更多的機會,埋下各種用戶轉化觸點,提高用戶的轉化率。例如在游戲任務中,用戶需要瀏覽店鋪和商品獲得收益。或者在游戲過程中會推送各種優(yōu)惠券,激勵用戶轉化。
9.png


那么游戲鏈路和玩法復雜后,會帶給用戶壓力和困擾嗎?答案是肯定的。但是由于人們普遍都是“逐利”心理,當面對利益時,用戶很容易忽視時間成本和操作成本。
因此游戲中的各種任務多而繁雜,頻繁出現(xiàn)的彈窗帶來了不好的用戶體驗。但是對于用戶而言,細化的任務體系和營銷彈窗更多的是收益,因此用戶不會產(chǎn)生大的心理壓力和操作負擔,反而樂于接受,完成率也更高。于是用戶在無意識中會頻繁的接觸店鋪和商品,讓轉化也變得更加的流暢和自然。
4、減少用戶流失
一旦參與到游戲中,用戶不僅僅收獲了各種虛擬幣,還投入了自己的時間和情感,這就是用戶的沉沒成本。隨著時間增加,產(chǎn)品的粘性越強,用戶流失幾率也就越低。

三、游戲化產(chǎn)品分類

根據(jù)電商平臺現(xiàn)有的游戲化產(chǎn)品,我們從游戲模式上大致可以分為4大類。


10.png


1、購物抵現(xiàn)類
仿照線下的代金券,電商推出了平臺內(nèi)的代金幣。一方面可以吸引用戶參加各種運營活動,同時也可以占領用戶心智。當出現(xiàn)購物需求時,用戶會優(yōu)先考慮消費代金幣完成交易。
淘寶“金幣莊園”、京東“種豆得豆”、蘇寧“云鉆魔法獅”都是這類產(chǎn)品。而深諳游戲玩法的拼多多,則是直接推出了“現(xiàn)金簽到”的方式,現(xiàn)金的認知相對于代金幣更加強烈,消費方式也更加靈活,可以提現(xiàn)或購物,增強了玩法的價值感和吸引力。


11.png


2、實物領取類
這類游戲以拼多多“多多果園”最為典型,用戶只要給選擇的果樹澆水和施肥,長成后即可獲得一份實物水果。
相對于代金幣的購物抵現(xiàn)金。實物兌換的目標性更強,而且擺脫了購買交易的概念,讓用戶感覺自己沒有付出任何成本,卻得到了一份水果,用戶的獲得感更強;
3、商品兌換類
用戶通過游戲獲得獎勵,可以兌換相應的商品。例如拼多多“多多賺大錢”、“多多牧場”等。商品兌換模式,跟實物領取方式類似,給用戶樹立了更加明確的目標,讓用戶持續(xù)的投入精力。而成功兌換后,會帶給用戶更強的獲得感,激勵用戶繼續(xù)玩下去。
4、公益捐獻類

以螞蟻森林和螞蟻莊園為典型代表,而淘寶里的“野生小伙伴”、天貓里的“童話鎮(zhèn)”也是此類題材。這類游戲更多是通過公益捐獻的形式賦予用戶更多的使命感,吸引用戶參與,但是帶來的用戶商業(yè)價值不高。目前“野生小伙伴”已經(jīng)下架,“童話鎮(zhèn)”在天貓平臺的露出并不明顯,用戶的感知較弱。

四、總結

愛玩是人類的天性。因此游戲以及游戲化的產(chǎn)品,天然具有高用戶粘度和用戶活躍度的特質。但是市場上有無數(shù)的游戲化產(chǎn)品,為什么有的異常火爆,有的無人問津呢?

在產(chǎn)品設計時需要注意以下幾點:

1、游戲化產(chǎn)品之所以受到用戶的喜愛,利益點僅僅是表層驅動,游戲的玩法才是產(chǎn)品真正的核心。因此需要通過建立完善的游戲化體系,提升產(chǎn)品的競爭力;

2、游戲化產(chǎn)品競爭激烈,需要不斷的進行玩法創(chuàng)新,才能帶給用戶差異化體驗。例如拼多多系列產(chǎn)品,通過實物領取和兌換,帶給了用戶全新的體驗感受,對用戶的吸引力也更強;

3、游戲化產(chǎn)品需要賦能商業(yè)目標,在實現(xiàn)了用戶活躍的基礎上,還需要提升用戶轉化;


作者:子牧先生 

轉自 :子牧設計筆談

640.png

640.png

640.png

640.png

640.png

通過JavaScript制作table表格隔行變色

seo達人

<!DOCTYPE html>

<html>

<head>

<meta charset="UTF-8">

<title>隔行變色</title>

</head>

<body>

<table id="mytable" align="center" width="80%" border="1">

<tr bgcolor="#cccccc">

<td>aaa</td>

<td>aaa</td>

<td>aaa</td>

</tr>

<tr>

<td>bbb</td>

<td>bbb</td>

<td>bbb</td>

</tr>

<tr>

<td>ccc</td>

<td>ccc</td>

<td>ccc</td>

</tr>

</table>

<script type="text/javascript">

window.onload=function(){

//獲取mytable中標簽名為tr的字節(jié)點

mytable=document.getElementById("mytable");

trs=mytable.getElementsByTagName("tr");

len=trs.length;

flag=true;

for(i=0;i<len;i++){

if(flag){

//每隔一行設置背景色

var tr=document.getElementsByTagName("tr")[i].setAttribute("bgcolor","#cccccc");

flag=false;

}else{

flag=true;

}

}

}

</script>

</body>

</html>


js_判斷瀏覽器內(nèi)核與修改元素樣式

前端達人

/Safari/.test(navigator.userAgent) && !/Chrome/.test(navigator.userAgent);



<script type="text/javascript">
var Sys = {};
var ua = navigator.userAgent.toLowerCase();
var s;
(s = ua.match(/msie ([\d.]+)/)) ? Sys.ie = s[1] :
(s = ua.match(/firefox\/([\d.]+)/)) ? Sys.firefox = s[1] :
(s = ua.match(/chrome\/([\d.]+)/)) ? Sys.chrome = s[1] :
(s = ua.match(/opera.([\d.]+)/)) ? Sys.opera = s[1] :
(s = ua.match(/version\/([\d.]+).*safari/)) ? Sys.safari = s[1] : 0;
//以下進行測試
if (Sys.ie) document.write('IE: ' + Sys.ie);
if (Sys.firefox) document.write('Firefox: ' + Sys.firefox);
if (Sys.chrome) document.write('Chrome: ' + Sys.chrome);
if (Sys.opera) document.write('Opera: ' + Sys.opera);
if (Sys.safari) document.write('Safari: ' + Sys.safari);
</script>


PC端只有Chrome有Safari字段嗎?為什么不需要判斷其他瀏覽器?
其實360,QQ等瀏覽器的userAgent字段也會帶有Safari字段,但是由于他們基于Chrome二次開發(fā)的,所有也會攜帶有Chrome字段。
所以「匹配規(guī)則:擁有Safari字段,并且沒有Chrome字段」就可以了。


接下來是修改元素樣式





<html>
<head>
    <style>
     #a{
        width:700px;
        height:300px;
        font-size:50px;
        color:red;
        background-color:grey;
        z-index:2;
        position:absolute;
        top:1300px;
        left:200px;
        display:none;
    } 
    </style>
</head>
<body>
    <div id="a"></div>
</body>
<script type="text/javascript">
    //假設想修改display為block
    function modify(){
        //1.原生Js法
        var a= document.getElementById("a");
        a.style.display="block";
        //2.用JQuery的css方法
        var a =$("#a");
        a.css("display","block");
        //3.用JQuery的attr方法
        var a =$("#a");
        a.attr("style","display:block");
    }
</script>
</html>


這樣就可以根據(jù)不同瀏覽器寫出不同的樣式適配啦



JS中數(shù)據(jù)類型轉換

seo達人

JS中數(shù)據(jù)類型轉換

目前為止,我了解到的JavaScript中共有6種類型。通過typeof關鍵字可以查看類型名稱。



數(shù)據(jù)的類型:

字符串:若值為字符串,則顯示為String。字符串使用單引號或雙引號括起來。在控制臺顯示為黑色。

數(shù)字:若值為數(shù)字,則顯示為Number。在控制臺顯示為藍色。

布爾值:若值為布爾值,則顯示為Boolean。它的值只有”true”和”false”。

對象:若值為對象,則顯示為Object。

未定義:若值未定義,也就是僅僅聲明,但未進行賦值,則顯示為Undefined。

空值:若值為指向不引用對象的指針,則顯示為Null,它與Undefined不同,以后慢慢深入了解。



以下表格詳細寫出了各種情況下相互轉換的結果,可作為輔助記憶。



轉換為字符串 轉換為數(shù)字 轉換為布爾值 轉換為對象

undefined “undefined” NaN false throw TypeError

null “null” 0 false throw TypeError

true “true” 1 new Boolean(“true”)

false “false” 0 new Boolean(“false”)

“” 0 false new String("")

“1.2” 1.2 true new String(“1.2”)

“1.2a” NaN true new String(“1.2a”)

“aaa” NaN true new String(“aaa”)

0 “0” false new Number(0)

1 “1” true new Number(1)

NaN “NaN” false new Number(NaN)

Infinity “Infinity” true new Number(Infinity)

[] “” 0 true

[9] “9” 9 true

[“a”“b”] “a,b” NaN true

在Js中,數(shù)據(jù)類型可以相互轉換,轉換的方式有兩種,隱式轉換和強制轉換,首先來說一些隱式轉換。在進行代碼書寫時,要經(jīng)常提醒自己所使用的元素是什么數(shù)據(jù)類型,在進行某些操作后是否會導致數(shù)據(jù)類型的變化,原因就是Js會對數(shù)據(jù)進行類型的隱式轉換。



隱式轉換舉例:

(+)加法運算的隱式轉換:加號兩邊只要出先了字符串,就自動將兩者均轉化為字符串,使兩個字符串發(fā)生“拼接”,最后生成的結果也是一個字符串;如果前后都不是字符串,則轉化為數(shù)字類型進行計算。



(-、*、/、%)其他算數(shù)運算的隱式轉換:前后都轉化為數(shù)字類型進行計算。



(?。┻壿嫹堑碾[式轉換:他會將他后面的變量或表達式轉換為布爾值。



(<,>)比較運算符的轉換:如果前后存在一個數(shù)字,會對另一個轉化為數(shù)字進行比較;如果前后均為字符串,會依次比較對應字符的編碼大小,老大比老大,老二比老二,依次進行。



(&&,||)邏輯運算符的轉換:先將前后都轉化為布爾值再進行判斷,要記住的是,只有undefined,null,0,””,NaN會轉化成為false,其他都是true。



(== 、===)這里作為補充說明,null與Undefined相等但不全等,NaN與任何都不相等。



強制轉換的方式:

1.轉化為字符串

String(里面寫待轉化的內(nèi)容):沒什么好解釋的,就是強制將你所看到的轉化為你所看到的。

toString(里面寫目標數(shù)字是幾進制),寫法為:待轉化內(nèi)容.toString(目標內(nèi)容是幾進制)。括號內(nèi)不寫時默認為10。

toFixed(保留小數(shù)的位數(shù)),寫法為待轉化內(nèi)容.toFixed(保留小數(shù)的位數(shù)),存在精度誤差。



2.轉化為數(shù)字

Number(),只有所轉化內(nèi)容在肉眼看到的全是數(shù)字,才會正常轉化;false會轉化為0,true會轉化為1;null會轉化為0;undefined會轉化為NaN;其他情況均為NaN。

parseInt(待轉化內(nèi)容,待轉化內(nèi)容的進制方式),與toString互為逆運算,不寫的話默認為10。如果待轉化內(nèi)容為字符串,若以數(shù)字開頭,可以從開始轉換到字符前為止變成數(shù)值。布爾值,undefined,null經(jīng)過轉化均為NaN。

ParseFloat(),與上面一致,不贅述。



3.轉化為布爾值

書寫方式為Boolean(),如果上面的隱式轉換你有好好看,這里很得不需要再寫了。


密碼驗證 : 密碼強度驗證

前端達人

密碼強度驗證

需求

首先我們需要知道需求是什么? 這很重要!



要知道 我們寫的一切邏輯都是建立在需求之上



當輸入框聚焦時提示密碼要求



當密碼符合要求時 隱藏提示 并給予反饋



密碼等級低時 提示密碼等級為低



密碼等級一般時 提示密碼等級為中



密碼等級高時 提示密碼等級為高



當密碼不符合要求時 重新打開提示



思考如何構建函數(shù)
通過上面的需求 你能想到的函數(shù)時什么?你能想到的邏輯又是什么?

首先 提示的顯示隱藏我們可以用事件綁定或者事件監(jiān)聽來做

其次 我們需要利用正則來判斷密碼等級

當密碼等級為低時 顯示紅色

當密碼等級為中時 顯示黃色

當密碼等級為高時 顯示綠色

最后 根據(jù)密碼等級來渲染頁面 也就是反饋給用戶的樣式

建議 :

在這里 盡量把每個函數(shù)的功能區(qū)分好 構思好

不僅要讓自己能看懂 還要讓別人能看懂

這樣的代碼才是好的代碼 可讀性更好 可維護性更高


實現(xiàn)功能 實現(xiàn)需求

HTML結構

在提示盒子的內(nèi)部寫3個div 不同等級給予不同顏色不同數(shù)量的提示

 密碼 : <input type="text" id="ipt">
    <p id="p">請輸入6-20位的帶有數(shù)字字母或者特殊符號的密碼</p>
    <div class="box">
        <span></span>
        <div></div>
        <div></div>
        <div></div>
    </div>


點擊查看原圖



不管樣式行為再怎么花里胡哨 也一定要先把結構里要出現(xiàn)的元素寫出來



CSS樣式

由于考慮到等級分為三種 所以給提示盒子分3中不同的class類名

每一個類名對應的子元素的樣式也不同

到js部分我們只需要操作class類名就可以了

   <style>
        *{
            margin : 0 ;
            padding : 0 ;
        }
        //提示盒子
        .box{
            position : absolute;
            top : 2px;
            left : 200px;
        }
        .box div,
        .box span{
            margin-right : 5px;
            width : 20px;
            height : 20px;
            float : left;
        }
        //低等級
        .box.low :nth-child(2){
            background : red;
        }
        //中等級
        .box.middle div{
            background : yellow;
        }
        .box.middle :last-child{
            background: #fff;
        }
        //高等級
        .box.high div{
            background : green;
        }
        //提示文字默認隱藏
        p{
            display : none;
        }
    </style>



20200315203557273.png

JS行為

 <script>
        //獲取需要操作的元素
        let ipt = document.getElementById('ipt');
        let p = document.getElementById('p');
        let div = document.getElementsByClassName('box')[0];
        var tip = false; //聚焦顯示提示的開關
        //添加聚焦事件
        ipt.addEventListener('focus' , () => {
            //由于存在用戶輸入正確的密碼失焦再操作的可能 所以需要驗證開關
            if(!tip) {
                p.style.display = 'block';
            }
            //默認選中文字 提升用戶體驗
            ipt.select();
        })
        //添加輸入時的事件
        ipt.addEventListener('input' , () => {
            //拿到用戶輸入的密碼字符串
            let str = ipt.value;
            //當密碼不符合要求時 要及時給予反饋 及時清除樣式
            if(str.length < 6 ||str.length > 20 || /[^(\da-zA-Z\_\#\@\$\^\%\*\&\!\~\+\-)]/.test(str) || str === "") {
                p.style.display = 'block';
                removeClass(div);
                div.children[0].innerHTML = "";
                tip = true;
                //如果不符合要求 就沒必要判斷等級了 直接結束判斷
                return false;
            }else{
                p.style.display = 'none';
            }
            //判斷密碼等級
            let res = level(str);
            //根據(jù)等級添加樣式
            randerLevel(res);
        })
        //判斷密碼等級函數(shù)
        function level (str) {
            let level = 0;
            //當用戶輸入的字符串符合一定規(guī)則 讓等級+1
            if(/\d+/.test(str)) {
                level ++;
            }
            if(/[a-zA-Z]+/.test(str)) {
                level ++;
            }
            if(/[\_\#\@\$\^\%\*\&\!\~\+\-]+/.test(str)) {
                level ++;
            }
            return level;
        }
        //添加樣式函數(shù)
        function randerLevel (level) {
            //在添加樣式前先清空樣式
            removeClass(div);
            div.children[0].innerHTML = "";
            //根據(jù)等級添加對應的類名
            switch (level) {
                case 1 :
                    div.children[0].innerHTML = '低';
                    //元素存在不止一個類名 用 += 更好
                    div.className += ' low';
                    break;
                case 2 :
                    div.children[0].innerHTML = '中';
                    div.className += ' middle';
                    break;
                case 3 :
                    div.children[0].innerHTML = '高';
                    div.className += ' high';
                    break;
            }
        }
        //去等級類名函數(shù)
        function removeClass(ele){
            let reg = /low|middle|high/g;
            if(reg.test(ele.className)) {
                //不要忘記把值賦回去 replace返回的是新字符串
                ele.className = ele.className.replace(reg , "");
            }
        }
    </script>

當密碼等級為低時 給予紅色反饋

2020031520385174.png


  • 當密碼等級為中時 給予黃色反饋
    20200315203928450.png
  • 當密碼等級為高時 給予綠色反饋
    20200315203952860.png
  • 當密碼長度太短或太長時 不給予顏色反饋 給予文字反饋
20200315204030964.png


————————————————
版權聲明:本文為CSDN博主「豆?jié){不好喝」的原創(chuàng)文章,遵循 CC 4.0 BY-SA 版權協(xié)議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/weixin_45178648/article/details/104885417

JS設計模式之單例模式、組合模式、觀察者模式、策略模式

前端達人

好,下面我將結合一些實例,說一下我對組合模式以及觀察者模式的了解:



1、組合模式:



組合模式在對象間形成樹形結構;

組合模式中基本對象和組合對象被一致對待;

無須關心對象有多少層, 調(diào)用時只需在根部進行調(diào)用;

將多個對象的功能,組裝起來,實現(xiàn)批量執(zhí)行;

想象我們現(xiàn)在手上有個萬能遙控器, 當我們回家, 按一下開關, 下列事情將被執(zhí)行:



到家了,開門

開電腦

開音樂




// 先準備一些需要批量執(zhí)行的功能
class GoHome{
    init(){
        console.log("到家了,開門");
    }
}
class OpenComputer{
    init(){
        console.log("開電腦");
    }
}
class OpenMusic{
    init(){
        console.log("開音樂");
    }
}

// 組合器,用來組合功能
class Comb{
    constructor(){
        // 準備容器,用來防止將來組合起來的功能
        this.skills = [];
    }
    // 用來組合的功能,接收要組合的對象
    add(task){
        // 向容器中填入,將來準備批量使用的對象
        this.skills.push(task);
    }
    // 用來批量執(zhí)行的功能
    action(){
        // 拿到容器中所有的對象,才能批量執(zhí)行
        this.skills.forEach( val => {
            val.init();
        } );
    }
}

// 創(chuàng)建一個組合器
var c = new Comb();

// 提前將,將來要批量操作的對象,組合起來
c.add( new GoHome() );
c.add( new OpenComputer() );
c.add( new OpenMusic() );

// 等待何時的時機,執(zhí)行組合器的啟動功能
c.action();
    // 在內(nèi)部,會自動執(zhí)行所有已經(jīng)組合起來的對象的功能



由此,我們可以總結一下組合模式的特點


1.批量執(zhí)行
2.啟動一個方法,會遍歷多個方法,同時執(zhí)行,有點類似于遞歸的感覺
3.組合模式略微耗性能,但是執(zhí)行方便
 目前只是一個基礎組合。
 高級組合:
1.組合成樹狀結構,每個對象下,還會有自己的子對象
2.如果執(zhí)行了父對象的某個方法,所有的子對象會跟隨執(zhí)行
3.組合模式一般建議使用在動態(tài)的html結構上,因為組合模式的結構和html的結構,出奇的一致
4.基本對象和組合對象被一致對待, 所以要保證基本對象(葉對象)和組合對象具有一致方法


2、觀察者模式:

觀察者模式也叫也叫Observer模式、訂閱/發(fā)布模式,也是由GoF提出的23種軟件設計模式的一種。
觀察者模式是行為模式之一,它的作用是當一個對象的狀態(tài)發(fā)生變化時,能夠自動通知其他關聯(lián)對象,自動刷新對象狀態(tài),或者說執(zhí)行對應對象的方法(主題數(shù)據(jù)改變,通知其他相關個體,做出相應的數(shù)據(jù)更新)。
這種設計模式可以大大降低程序模塊之間的耦合度,便于更加靈活的擴展和維護。
以觀察的角度,發(fā)現(xiàn)對應的狀況,處理問題。
觀察者模式包含兩種角色:
①觀察者(訂閱者):會隨時更新自身的信息或狀態(tài)(訂閱者可以隨時加入或離開);
②被觀察者(發(fā)布者):接收到發(fā)布者發(fā)布的信息,從而做出對應的改變或執(zhí)行。
很方便的實現(xiàn)簡單的廣播通信,實現(xiàn)一對多的對應關系。
核心思想:觀察者只要訂閱了被觀察者的事件,那么當被觀察者的狀態(tài)改變時,被觀察者會主動去通知觀察者,而無需關心觀察者得到事件后要去做什么,實際程序中可能是執(zhí)行訂閱者的回調(diào)函數(shù)。
Javascript中實現(xiàn)一個例子:


HTML 學習總結2 框架 表單

前端達人

這是HTML學習總結系列的第二篇,第一篇在這里:

HTML 學習總結1入門 基本概念、格式 文字標簽 圖片標簽 鏈接標簽 表格標簽 注釋

這次的學習內(nèi)容相較第一次分類少,但是比較雜。



框架集標簽

框架標簽是將網(wǎng)頁設置成網(wǎng)頁框架的一種雙標簽,被設計成框架的網(wǎng)頁被切分成若干區(qū)域,沒有實際的內(nèi)容,只當做框架用于鑲嵌其它的網(wǎng)頁。

那么,這個標簽是:

<frameset></frameset>

框架集標簽的屬性

使用的時候需要將HTML文件中的body標簽部分替換為框架標簽,寫成這樣:



<html>
    <head></head>
    <frameset rows="500,*" border="3" noresize="noresize">
    </frame>
</html>

看上面的代碼,用frameset替換掉body不難理解,畢竟我們約定做框架的網(wǎng)頁不具有實體內(nèi)容
接著,這里提到了框架標簽的三個屬性,分別為:

rows/cols 框架的分行或分列
border 分隔框的寬度
noresize 大小是否可調(diào)
現(xiàn)在來分別解釋一下

第一個,rows 或cols 屬性,代表了框架的分行或分列的情況,在引號內(nèi)書寫該屬性的值的時候,不需要指明分成幾欄,只需要指明每一欄占據(jù)的寬度或高度(單位為像素)并使用逗號隔開。瀏覽器在解析的時候會計算到底分成了幾欄。另外,不指定寬度而使其占據(jù)剩余位置時,可以使用通配符 “ * ”。

第二個,border 屬性,代表了分隔框的寬度,這是屬性的數(shù)值單位是像素。所以如果你不想加入邊框,則可以將它設置為零。

第三個,noresize 屬性,表示我們的框架的大小是否可調(diào),frameset標簽默認為大小可調(diào),當用戶鼠標移動到邊框上時,他可以拖拽改變大小。所以如果不想讓用戶隨意改變框架大小,那么可以選擇使用這個屬性 (當然,也可以選擇把邊框的寬度設為零,讓他找不到)。 這個屬性的值同屬性名稱一樣。

最后還需要說明的是:框架集標簽是可以進行嵌套的,也就是說,在已經(jīng)分出來的框架中,我們可以借著分欄。

在框架內(nèi)鑲嵌網(wǎng)頁
剛剛我們使用 frameset 標簽將網(wǎng)頁變成框架并劃分成了若干區(qū)域,每一個區(qū)域都是一個單獨的可顯示頁面的子網(wǎng)頁(筆者起的名)。現(xiàn)在,我們需要在這些區(qū)域內(nèi)為它鑲嵌上一個網(wǎng)頁,這需要用到frame這個單標簽在框架下添加網(wǎng)頁,它的寫法如下:

<frame src="...." name="...." />
1
這里可以看到 frame 標簽的兩個屬性; src 和 name 。它們分別代表著添置連接(這是一個超鏈接,網(wǎng)頁,HTML文件,圖片等都是可以的。有關超鏈接的信息,可參照上一篇學習總結或者問問度娘 ),以及框架名稱。

框架的命名,很主要的一個原因在于可以重復利用一個框架,即在其他標簽使用時,可以在某個框架上顯示相應內(nèi)容。還記得上一篇中,我們提到的鏈接標簽 target 屬性中的 “某框架名稱” 這個值嗎?在為框架命名后,就可以使用上述的 target 用法,將打開的網(wǎng)頁放在某個框架中了。

綜上,舉個例子:

先來創(chuàng)造一個帶有嵌套的框架
<!--frame-->
<html>
    <head></head>
    <frameset rows="200,*" border="5" noresize="noresize">
        <frame src="title.html" name="title" />
        <frameset cols="200,*">
            <frame src="selection_bar.html" />
            <frame name="output_page" />
        </frameset>
    </frameset>
</html>



<!--title-->
<html>
    <head></head>
    <body>
        <font size="7" color="blue">
            The test page
        </font>
    </body>
</html>



<!--selection_bar-->
<html>
    <head></head>
    <body>
        <font size="5" color="red">
            Please select websites.
        </font>
        <br /><br />
        <a  target="output_page"/>百度一下<br /><br />
        <a  target="output_page"/>CSDN <br /><br />
    </body>
</html>

最后來看下結果:

點擊查看原圖


點擊查看原圖點擊查看原圖




vue父組件向子組件傳值

前端達人

非常簡單,相信大家一看就懂

復制到瀏覽器即可使用,注意別忘了引入vue哦


<div id="app">
    <div>{{pmsg}}</div>
    <menu-item :title='ptitle' :content='ptitle'></menu-item>
</div>
<script type="text/javascript" src="vue.js"></script>
<script type="text/javascript">
    //父組件向子組件傳值-基本使用
    Vue.component('menu-item', {
        props: ['title', 'content'],
        data: function() {
            return {
                msg: '子組件本身的數(shù)據(jù)'
            }
        },
        template: `<div>
      <p>{{msg}}</p>
      <p>{{title}}</p>
      <p>{{content}}</p>
      </div>`
    });
    var vm = new Vue({
        el: '#app',
        data: {
            pmsg: '父組件中內(nèi)容',
            ptitle: '動態(tài)綁定屬性'
        }
    });
</script>
————————————————
版權聲明:本文為CSDN博主「溫柔的堅持」的原創(chuàng)文章,遵循 CC 4.0 BY-SA 版權協(xié)議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/weixin_43745003/article/details/104908639

JS的原型介紹及原型的繼承

前端達人

前言

在學習JS中的原型,原型鏈,繼承這些知識之前,我們先學習下基礎知識:函數(shù)和對象的關系。

我們一直都知道,函數(shù)也是對象的一種,因為通過instanceof就可以判斷出來。但是函數(shù)和對象的關系并不是簡單的包含和被包含的關系,這兩者之間的關系還是有點復雜的。接下來我們就來捋一捋。



首先,闡述一點,對象都是通過函數(shù)創(chuàng)建的

對于下面這種類型的代碼,一般叫做“語法糖”

var obj = {a:10,b:20};
var arr = [5, 'x', true];



但是,其實上面這段代碼的實質是下面這樣的:


//var obj = { a: 10, b: 20 };
//var arr = [5, 'x', true];

 var obj = new Object();
 obj.a = 10;
 obj.b = 20;

 var arr = new Array();
 arr[0] = 5;
 arr[1] = 'x';
 arr[2] = true;



而Object和Array都是函數(shù),可以自己用typeof函數(shù)進行驗證。
所以,可以得出:對象都是通過函數(shù)創(chuàng)建的

正文
說完了前言,接下來我們進入正題。

原型prototype
在前言中,我們說了函數(shù)也是一種對象,所以函數(shù)也是屬性的集合,同時,也可以對函數(shù)進行自定義屬性。
每個函數(shù)都有一個屬性——prototype。這個prototype的屬性值是一個對象(屬性的集合),默認只有一個叫做constructor的屬性,指向這個函數(shù)本身.

“隱式原型”proto
我們先看一段非常常見的代碼:
function Fn() { }
   Fn.prototype.name = '張三';
    Fn.prototype.getAge = function () {
       return 12;
};
   var fn = new Fn();
   console.log(fn.name);
   console.log(fn.getAge ());

即,F(xiàn)n是一個函數(shù),fn對象是從Fn函數(shù)new出來的,這樣fn對象就可以調(diào)用Fn.prototype中的屬性。

但是,因為每個對象都有一個隱藏的屬性——“proto”,這個屬性引用了創(chuàng)建這個對象的函數(shù)的prototype。即:fn.proto === Fn.prototype
那么,這里的_proto_到底是什么呢?

其實,這個__proto__是一個隱藏的屬性,javascript不希望開發(fā)者用到這個屬性值,有的低版本瀏覽器甚至不支持這個屬性值。

var obj = {};
console.log(obj.__proto__);

每個對象都有一個_proto_屬性,指向創(chuàng)建該對象的函數(shù)的prototype。

構造函數(shù)、原型、實例之間的關系
實例,原型對象,構造函數(shù),三者之間的關系:

(1) 實例有__proto__屬性指向原型對象

(2) 原型對象有constructor指針指向構造函數(shù)

(3)構造函數(shù)又有prototype屬性指向原型對象
點擊查看原圖


實例和原型關系檢測

isPrototypeOf()函數(shù),用于檢測兩個對象之間似乎否存在原型關系,使用方法如下:

  // 查看 Fn 的 prototype 對象,是否是 f 原型
  Fn.prototype.isPrototypeOf(f);   



 //// 查看 f 對象是否是構造函數(shù) Fn 的實例
 //console.log(f instanceof Fn); 
 //// 查看 f 對象是否是構造函數(shù) Fn 的實例    
 //console.log(f instanceof Object); 

    function Fn(){}
    function Fun(){}
    var f = new Fn();
    console.log( f.__proto__ === Fn.prototype );            // t

    console.log( Fn.prototype.isPrototypeOf(f) );           // t
    console.log( Fun.prototype.isPrototypeOf(f) );          // f
    console.log( Object.prototype.isPrototypeOf(f) );       // t

    console.log( f instanceof Fn );         // t
    console.log( f instanceof Fun );        // f
    console.log( f instanceof Object );     // t
//兩種使用,如果是返回ture,如果不是返回false;
//注意:instanceof運算符右側為構造函數(shù),并且js中所有原型都來自Object構造函數(shù)。

JS解析器訪問屬性順序
當訪問實例 f 的屬性或方法時,會先在當前實例對象 f 中查找,如果沒有,則沿著__proto__繼續(xù)向上尋找,如果找到最頂頭的Object還是找不到,則會拋出undefined。如果在實例中找到,或某層原型中找到,就會讀取并使用,同時停止向上找尋。
由此可見,解析器的解析順序遵循就近原則,如果在最近的位置發(fā)現(xiàn)屬性存在,便不會繼續(xù)向上找尋。

原型的應用
數(shù)組去重:

Array.prototype.noRepeat = function(){
    var m = [];
    for(var i=0;i<this.length;i++){
        if(m.indexOf(this[i]) == -1){
            m.push(this[i]);
        }
    }
    return m;
}
var arr = [3,4,5,6,7,6,5,4,3,2,1];
var res = arr.noRepeat();
console.log(res);

var arr1 = ["a","b","c","b","a"];
var res1 = arr1.noRepeat();
console.log(res1);



function Parent(){

}
Parent.prototype.show = function(){
    console.log("哈哈哈");
}

function Child(){

}
for(var i in Parent.prototype){
    Child.prototype[i] = Parent.prototype[i];
}
Child.prototype.show = function(){
    console.log("hello");
}

var p = new Parent();
p.show();
console.log(p.name);

var c = new Child();
c.show();
console.log(c.name);



————————————————
版權聲明:本文為CSDN博主「zyfacd」的原創(chuàng)文章,遵循 CC 4.0 BY-SA 版權協(xié)議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/zyfacd/article/details/104909948

vue非父子組件間的傳值

前端達人

vue非父子組件傳值的基本語法

創(chuàng)建一個新的vue對象
var newvue = new Vue()
    
觸發(fā)事件
newvue.$emit('自定義事件名', 參數(shù))
    
監(jiān)聽事件
newvue.on('自定義事件名', 觸發(fā)方法名)
    
銷毀事件
newvue.off('自定義事件名')

案例

放在html頁面上即可顯示,注意要引入vue

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Document</title>
</head>
<body>
  <div id="app">
    <div>父組件</div>
    <div>
      <button @click='handle'>銷毀事件</button>
    </div>
    <test-tom></test-tom>
    <test-jerry></test-jerry>
  </div>
  <script type="text/javascript" src="js/vue.js"></script>
  <script type="text/javascript">
    /*
      兄弟組件之間數(shù)據(jù)傳遞
    */
    // 提供事件中心
    var hub = new Vue();

    Vue.component('test-tom', {
      data: function(){
        return {
          num: 0
        }
      },
      template: `
        <div>
          <div>TOM:{{num}}</div>
          <div>
            <button @click='handle'>點擊</button>
          </div>
        </div>
      `,
      methods: {
        handle: function(){
          hub.$emit('jerry-event', 2);
        }
      },
      mounted: function() {
        // 監(jiān)聽事件
        hub.$on('tom-event', (val) => {
          this.num += val;
        });
      }
    });
    Vue.component('test-jerry', {
      data: function(){
        return {
          num: 0
        }
      },
      template: `
        <div>
          <div>JERRY:{{num}}</div>
          <div>
            <button @click='handle'>點擊</button>
          </div>
        </div>
      `,
      methods: {
        handle: function(){
          // 觸發(fā)兄弟組件的事件
          hub.$emit('tom-event', 1);
        }
      },
      mounted: function() {
        // 監(jiān)聽事件
        hub.$on('jerry-event', (val) => {
          this.num += val;
        });
      }
    });
    var vm = new Vue({
      el: '#app',
      data: {

      },
      methods: {
        handle: function(){
          hub.$off('tom-event');
          hub.$off('jerry-event');
        }
      }
    });
  </script>
</body>
</html>
————————————————
版權聲明:本文為CSDN博主「溫柔的堅持」的原創(chuàng)文章,遵循 CC 4.0 BY-SA 版權協(xié)議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/weixin_43745003/article/details/104919633



日歷

鏈接

個人資料

藍藍設計的小編 http://sillybuy.com

存檔