首页

淘宝、拼多多为什么要让你玩游戏?

前端达人

从支付宝蚂蚁森林开始,游戏化产品开始回归移动互联网领域。拼多多上线“多多果园”后,通过玩游戏免费领水果的玩法,引发了电商游戏化产品的风潮。淘宝、天猫、京东、苏宁等互联网平台纷纷推出了自己的游戏产品。那么游戏化到底能够为产品带来什么呢?
一、什么是游戏化
游戏化(Gamification)是指将游戏元素和游戏设计技术应用于非游戏场景,用游戏化机制创造乐趣来更好地实现目标。也就是说,通过游戏的方式,为非游戏化的场景或产品赋能,让用户在使用产品过程中获得更多的乐趣,创造更大的产品价值。



1.png


随着移动互联网的快速发展,人口红利逐渐消失,电商领域开始从增量市场进入存量市场。当用户数量无法持续有效增长时,就需要深挖存量用户的价值,通过精细化运营,提高DAU(用户日活)来获取更大的用户价值。
2016年8月27日,支付宝上线蚂蚁森林。2017年数据显示,由于蚂蚁森林拥有远超平常应用的用户黏性,产品已拥有超过2亿用户,带来的日活不可小觑。
2017年8月6日,支付宝又上线了蚂蚁庄园。2019年11月20日,蚂蚁庄园官方微博对外发布了运营大数据。该数据显示,蚂蚁庄园上线至今,全国约4亿网友捐了150亿个鸡蛋。
这两款游戏化产品引爆了用户的热情,为传统的支付工具添加了游戏化属性,开创了移动互联网时代“种树养鸡”的娱乐化模式。


2.png


随后,2018年4月,拼多多上线了“多多果园”,在电商领域率先开启了游戏化模式。于是游戏化产品在电商平台上开始生根发芽。
2018年11月,京东上线了“种豆得豆”;
2019年1月,淘宝上线了“金币庄园”;
2019年5月,苏宁易购上线了“云钻魔法狮”;

据不完全统计,主流电商都推出了多款游戏化产品。清单如下:


3.png


二、游戏化产品的价值
目前在电商领域,游戏化产品主要是作为流量产品存在的,核心目标是为了增强平台的用户粘性,盘活现有的存量用户,提高用户活跃度。

4.png


在游戏化产品未出现前,各大电商基本采用的是“签到”送奖励的形式,提升用户活跃度。从短期效果上,签到同样可以带给用户强烈的激励。然而虚拟币在购物过程中才能形成价值感知,所以单纯虚拟币总量的积累无法形成持续性的激励,用户容易产生厌倦心理。
同时为了平衡商业价值,虚拟币必然带有一定的使用门槛,因此签到价值与用户的购买链路无法即时匹配。用户在购物过程中,无法使用虚拟币时,必然会产生一定的负面情绪。
5.png



为了弥补签到行为中情感体验的缺失,电商平台开始通过游戏化对“签到”产品进行了包装升级。相比较传统的签到产品,游戏化产品的优势在哪里呢?
我认为有以下几个方面:
6.png


1、形成内部触发
根据上瘾模型理论,用户上瘾需要有一个“触发”。而内部触发是产品在用户内心、情感层面上建立的一种潜意识的认知,是产品和用户之间最有力的纽带。
基于游戏“八角行为激励模型”,在产品设计中,可以通过多种手段不断激励用户参与到游戏中(具体内容参见下一篇文章)。用户进入了游戏后,无论是激励体系、游戏玩法,还是视觉设计,都可以更好的触发用户的情感体验点。
同时成长体系、成就体系、好友排名等激励,为用户设定了更加丰富和明确目标,让用户更持久的投入到游戏的玩法中,并逐步在用户意识中形成内部触发,让产品具有更高的用户粘性。


7.png


例如蚂蚁森林对于用户不仅仅是每日7点左右收取能量,更多的是在拿起手机不由自主的打开支付宝,查看有没有能量可以收取。
2、深度激活用户
传统的签到为每日活动,用户更倾向于完成即走,用户链路短,无法挖掘用户的潜在价值。
而游戏玩法丰富,增强了用户链路,同时将玩法细化到小时级的颗粒度,激活用户的活跃度。例如在金币庄园中植物在4个小时内即可成熟采摘,促使用户多次打开产品收取果实。
游戏的任务也更加灵活,通过频次可以满足不同的用户的需要。深度玩家可以反复多次完成任务,普通玩家可以灵活参与,因此对用户的覆盖更广,也有利于普通用户升级为深度玩家。多次和定时的任务,用户需要频繁的进出游戏来获取奖励,从而极大的提高了用户的活跃度,逐渐培养用户玩游戏的习惯。


8.png


3、增加用户停留、提高用户转化
用户的停留时长其实是一种零和博弈,面对激烈的市场竞争,用户在一个平台的停留时长增加,必然会导致另一个平台停留时长的下降。因此大电商在关注用户活跃度的同时,也开始争夺用户停留时长。
游戏化产品拥有更加细化的游戏玩法和任务,无形之中增加了用户的停留时长。同时也为产品提供了更多的机会,埋下各种用户转化触点,提高用户的转化率。例如在游戏任务中,用户需要浏览店铺和商品获得收益。或者在游戏过程中会推送各种优惠券,激励用户转化。
9.png


那么游戏链路和玩法复杂后,会带给用户压力和困扰吗?答案是肯定的。但是由于人们普遍都是“逐利”心理,当面对利益时,用户很容易忽视时间成本和操作成本。
因此游戏中的各种任务多而繁杂,频繁出现的弹窗带来了不好的用户体验。但是对于用户而言,细化的任务体系和营销弹窗更多的是收益,因此用户不会产生大的心理压力和操作负担,反而乐于接受,完成率也更高。于是用户在无意识中会频繁的接触店铺和商品,让转化也变得更加的流畅和自然。
4、减少用户流失
一旦参与到游戏中,用户不仅仅收获了各种虚拟币,还投入了自己的时间和情感,这就是用户的沉没成本。随着时间增加,产品的粘性越强,用户流失几率也就越低。

三、游戏化产品分类

根据电商平台现有的游戏化产品,我们从游戏模式上大致可以分为4大类。


10.png


1、购物抵现类
仿照线下的代金券,电商推出了平台内的代金币。一方面可以吸引用户参加各种运营活动,同时也可以占领用户心智。当出现购物需求时,用户会优先考虑消费代金币完成交易。
淘宝“金币庄园”、京东“种豆得豆”、苏宁“云钻魔法狮”都是这类产品。而深谙游戏玩法的拼多多,则是直接推出了“现金签到”的方式,现金的认知相对于代金币更加强烈,消费方式也更加灵活,可以提现或购物,增强了玩法的价值感和吸引力。


11.png


2、实物领取类
这类游戏以拼多多“多多果园”最为典型,用户只要给选择的果树浇水和施肥,长成后即可获得一份实物水果。
相对于代金币的购物抵现金。实物兑换的目标性更强,而且摆脱了购买交易的概念,让用户感觉自己没有付出任何成本,却得到了一份水果,用户的获得感更强;
3、商品兑换类
用户通过游戏获得奖励,可以兑换相应的商品。例如拼多多“多多赚大钱”、“多多牧场”等。商品兑换模式,跟实物领取方式类似,给用户树立了更加明确的目标,让用户持续的投入精力。而成功兑换后,会带给用户更强的获得感,激励用户继续玩下去。
4、公益捐献类

以蚂蚁森林和蚂蚁庄园为典型代表,而淘宝里的“野生小伙伴”、天猫里的“童话镇”也是此类题材。这类游戏更多是通过公益捐献的形式赋予用户更多的使命感,吸引用户参与,但是带来的用户商业价值不高。目前“野生小伙伴”已经下架,“童话镇”在天猫平台的露出并不明显,用户的感知较弱。

四、总结

爱玩是人类的天性。因此游戏以及游戏化的产品,天然具有高用户粘度和用户活跃度的特质。但是市场上有无数的游戏化产品,为什么有的异常火爆,有的无人问津呢?

在产品设计时需要注意以下几点:

1、游戏化产品之所以受到用户的喜爱,利益点仅仅是表层驱动,游戏的玩法才是产品真正的核心。因此需要通过建立完善的游戏化体系,提升产品的竞争力;

2、游戏化产品竞争激烈,需要不断的进行玩法创新,才能带给用户差异化体验。例如拼多多系列产品,通过实物领取和兑换,带给了用户全新的体验感受,对用户的吸引力也更强;

3、游戏化产品需要赋能商业目标,在实现了用户活跃的基础上,还需要提升用户转化;


作者:子牧先生 

转自 :子牧设计笔谈

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的字节点

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_判断浏览器内核与修改元素样式

前端达人

/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二次开发的,所有也会携带有Chrome字段。
所以「匹配规则:拥有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>


这样就可以根据不同浏览器写出不同的样式适配啦



JS中数据类型转换

seo达人

JS中数据类型转换

目前为止,我了解到的JavaScript中共有6种类型。通过typeof关键字可以查看类型名称。



数据的类型:

字符串:若值为字符串,则显示为String。字符串使用单引号或双引号括起来。在控制台显示为黑色。

数字:若值为数字,则显示为Number。在控制台显示为蓝色。

布尔值:若值为布尔值,则显示为Boolean。它的值只有”true”和”false”。

对象:若值为对象,则显示为Object。

未定义:若值未定义,也就是仅仅声明,但未进行赋值,则显示为Undefined。

空值:若值为指向不引用对象的指针,则显示为Null,它与Undefined不同,以后慢慢深入了解。



以下表格详细写出了各种情况下相互转换的结果,可作为辅助记忆。



转换为字符串 转换为数字 转换为布尔值 转换为对象

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中,数据类型可以相互转换,转换的方式有两种,隐式转换和强制转换,首先来说一些隐式转换。在进行代码书写时,要经常提醒自己所使用的元素是什么数据类型,在进行某些操作后是否会导致数据类型的变化,原因就是Js会对数据进行类型的隐式转换。



隐式转换举例:

(+)加法运算的隐式转换:加号两边只要出先了字符串,就自动将两者均转化为字符串,使两个字符串发生“拼接”,最后生成的结果也是一个字符串;如果前后都不是字符串,则转化为数字类型进行计算。



(-、*、/、%)其他算数运算的隐式转换:前后都转化为数字类型进行计算。



(!)逻辑非的隐式转换:他会将他后面的变量或表达式转换为布尔值。



(<,>)比较运算符的转换:如果前后存在一个数字,会对另一个转化为数字进行比较;如果前后均为字符串,会依次比较对应字符的编码大小,老大比老大,老二比老二,依次进行。



(&&,||)逻辑运算符的转换:先将前后都转化为布尔值再进行判断,要记住的是,只有undefined,null,0,””,NaN会转化成为false,其他都是true。



(== 、===)这里作为补充说明,null与Undefined相等但不全等,NaN与任何都不相等。



强制转换的方式:

1.转化为字符串

String(里面写待转化的内容):没什么好解释的,就是强制将你所看到的转化为你所看到的。

toString(里面写目标数字是几进制),写法为:待转化内容.toString(目标内容是几进制)。括号内不写时默认为10。

toFixed(保留小数的位数),写法为待转化内容.toFixed(保留小数的位数),存在精度误差。



2.转化为数字

Number(),只有所转化内容在肉眼看到的全是数字,才会正常转化;false会转化为0,true会转化为1;null会转化为0;undefined会转化为NaN;其他情况均为NaN。

parseInt(待转化内容,待转化内容的进制方式),与toString互为逆运算,不写的话默认为10。如果待转化内容为字符串,若以数字开头,可以从开始转换到字符前为止变成数值。布尔值,undefined,null经过转化均为NaN。

ParseFloat(),与上面一致,不赘述。



3.转化为布尔值

书写方式为Boolean(),如果上面的隐式转换你有好好看,这里很得不需要再写了。


密码验证 : 密码强度验证

前端达人

密码强度验证

需求

首先我们需要知道需求是什么? 这很重要!



要知道 我们写的一切逻辑都是建立在需求之上



当输入框聚焦时提示密码要求



当密码符合要求时 隐藏提示 并给予反馈



密码等级低时 提示密码等级为低



密码等级一般时 提示密码等级为中



密码等级高时 提示密码等级为高



当密码不符合要求时 重新打开提示



思考如何构建函数
通过上面的需求 你能想到的函数时什么?你能想到的逻辑又是什么?

首先 提示的显示隐藏我们可以用事件绑定或者事件监听来做

其次 我们需要利用正则来判断密码等级

当密码等级为低时 显示红色

当密码等级为中时 显示黄色

当密码等级为高时 显示绿色

最后 根据密码等级来渲染页面 也就是反馈给用户的样式

建议 :

在这里 尽量把每个函数的功能区分好 构思好

不仅要让自己能看懂 还要让别人能看懂

这样的代码才是好的代码 可读性更好 可维护性更高


实现功能 实现需求

HTML结构

在提示盒子的内部写3个div 不同等级给予不同颜色不同数量的提示

 密码 : <input type="text" id="ipt">
    <p id="p">请输入6-20位的带有数字字母或者特殊符号的密码</p>
    <div class="box">
        <span></span>
        <div></div>
        <div></div>
        <div></div>
    </div>


点击查看原图



不管样式行为再怎么花里胡哨 也一定要先把结构里要出现的元素写出来



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);
            //根据等级添加样式
            randerLevel(res);
        })
        //判断密码等级函数
        function level (str) {
            let level = 0;
            //当用户输入的字符串符合一定规则 让等级+1
            if(/\d+/.test(str)) {
                level ++;
            }
            if(/[a-zA-Z]+/.test(str)) {
                level ++;
            }
            if(/[\_\#\@\$\^\%\*\&\!\~\+\-]+/.test(str)) {
                level ++;
            }
            return level;
        }
        //添加样式函数
        function randerLevel (level) {
            //在添加样式前先清空样式
            removeClass(div);
            div.children[0].innerHTML = "";
            //根据等级添加对应的类名
            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;
            }
        }
        //去等级类名函数
        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博主「豆浆不好喝」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_45178648/article/details/104885417

JS设计模式之单例模式、组合模式、观察者模式、策略模式

前端达人

好,下面我将结合一些实例,说一下我对组合模式以及观察者模式的了解:



1、组合模式:



组合模式在对象间形成树形结构;

组合模式中基本对象和组合对象被一致对待;

无须关心对象有多少层, 调用时只需在根部进行调用;

将多个对象的功能,组装起来,实现批量执行;

想象我们现在手上有个万能遥控器, 当我们回家, 按一下开关, 下列事情将被执行:



到家了,开门

开电脑

开音乐




// 先准备一些需要批量执行的功能
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);
    }
    // 用来批量执行的功能
    action(){
        // 拿到容器中所有的对象,才能批量执行
        this.skills.forEach( val => {
            val.init();
        } );
    }
}

// 创建一个组合器
var c = new Comb();

// 提前将,将来要批量操作的对象,组合起来
c.add( new GoHome() );
c.add( new OpenComputer() );
c.add( new OpenMusic() );

// 等待何时的时机,执行组合器的启动功能
c.action();
    // 在内部,会自动执行所有已经组合起来的对象的功能



由此,我们可以总结一下组合模式的特点


1.批量执行
2.启动一个方法,会遍历多个方法,同时执行,有点类似于递归的感觉
3.组合模式略微耗性能,但是执行方便
 目前只是一个基础组合。
 高级组合:
1.组合成树状结构,每个对象下,还会有自己的子对象
2.如果执行了父对象的某个方法,所有的子对象会跟随执行
3.组合模式一般建议使用在动态的html结构上,因为组合模式的结构和html的结构,出奇的一致
4.基本对象和组合对象被一致对待, 所以要保证基本对象(叶对象)和组合对象具有一致方法


2、观察者模式:

观察者模式也叫也叫Observer模式、订阅/发布模式,也是由GoF提出的23种软件设计模式的一种。
观察者模式是行为模式之一,它的作用是当一个对象的状态发生变化时,能够自动通知其他关联对象,自动刷新对象状态,或者说执行对应对象的方法(主题数据改变,通知其他相关个体,做出相应的数据更新)。
这种设计模式可以大大降低程序模块之间的耦合度,便于更加灵活的扩展和维护。
以观察的角度,发现对应的状况,处理问题。
观察者模式包含两种角色:
①观察者(订阅者):会随时更新自身的信息或状态(订阅者可以随时加入或离开);
②被观察者(发布者):接收到发布者发布的信息,从而做出对应的改变或执行。
很方便的实现简单的广播通信,实现一对多的对应关系。
核心思想:观察者只要订阅了被观察者的事件,那么当被观察者的状态改变时,被观察者会主动去通知观察者,而无需关心观察者得到事件后要去做什么,实际程序中可能是执行订阅者的回调函数。
Javascript中实现一个例子:


HTML 学习总结2 框架 表单

前端达人

这是HTML学习总结系列的第二篇,第一篇在这里:

HTML 学习总结1入门 基本概念、格式 文字标签 图片标签 链接标签 表格标签 注释

这次的学习内容相较第一次分类少,但是比较杂。



框架集标签

框架标签是将网页设置成网页框架的一种双标签,被设计成框架的网页被切分成若干区域,没有实际的内容,只当做框架用于镶嵌其它的网页。

那么,这个标签是:

<frameset></frameset>

框架集标签的属性

使用的时候需要将HTML文件中的body标签部分替换为框架标签,写成这样:



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

看上面的代码,用frameset替换掉body不难理解,毕竟我们约定做框架的网页不具有实体内容
接着,这里提到了框架标签的三个属性,分别为:

rows/cols 框架的分行或分列
border 分隔框的宽度
noresize 大小是否可调
现在来分别解释一下

第一个,rows 或cols 属性,代表了框架的分行或分列的情况,在引号内书写该属性的值的时候,不需要指明分成几栏,只需要指明每一栏占据的宽度或高度(单位为像素)并使用逗号隔开。浏览器在解析的时候会计算到底分成了几栏。另外,不指定宽度而使其占据剩余位置时,可以使用通配符 “ * ”。

第二个,border 属性,代表了分隔框的宽度,这是属性的数值单位是像素。所以如果你不想加入边框,则可以将它设置为零。

第三个,noresize 属性,表示我们的框架的大小是否可调,frameset标签默认为大小可调,当用户鼠标移动到边框上时,他可以拖拽改变大小。所以如果不想让用户随意改变框架大小,那么可以选择使用这个属性 (当然,也可以选择把边框的宽度设为零,让他找不到)。 这个属性的值同属性名称一样。

最后还需要说明的是:框架集标签是可以进行嵌套的,也就是说,在已经分出来的框架中,我们可以借着分栏。

在框架内镶嵌网页
刚刚我们使用 frameset 标签将网页变成框架并划分成了若干区域,每一个区域都是一个单独的可显示页面的子网页(笔者起的名)。现在,我们需要在这些区域内为它镶嵌上一个网页,这需要用到frame这个单标签在框架下添加网页,它的写法如下:

<frame src="...." name="...." />
1
这里可以看到 frame 标签的两个属性; src 和 name 。它们分别代表着添置连接(这是一个超链接,网页,HTML文件,图片等都是可以的。有关超链接的信息,可参照上一篇学习总结或者问问度娘 ),以及框架名称。

框架的命名,很主要的一个原因在于可以重复利用一个框架,即在其他标签使用时,可以在某个框架上显示相应内容。还记得上一篇中,我们提到的链接标签 target 属性中的 “某框架名称” 这个值吗?在为框架命名后,就可以使用上述的 target 用法,将打开的网页放在某个框架中了。

综上,举个例子:

先来创造一个带有嵌套的框架
<!--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 href="http://www.baidu.com" target="output_page"/>百度一下<br /><br />
        <a href="https://www.csdn.net" 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: '子组件本身的数据'
            }
        },
        template: `<div>
      <p>{{msg}}</p>
      <p>{{title}}</p>
      <p>{{content}}</p>
      </div>`
    });
    var vm = new Vue({
        el: '#app',
        data: {
            pmsg: '父组件中内容',
            ptitle: '动态绑定属性'
        }
    });
</script>
————————————————
版权声明:本文为CSDN博主「温柔的坚持」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_43745003/article/details/104908639

JS的原型介绍及原型的继承

前端达人

前言

在学习JS中的原型,原型链,继承这些知识之前,我们先学习下基础知识:函数和对象的关系。

我们一直都知道,函数也是对象的一种,因为通过instanceof就可以判断出来。但是函数和对象的关系并不是简单的包含和被包含的关系,这两者之间的关系还是有点复杂的。接下来我们就来捋一捋。



首先,阐述一点,对象都是通过函数创建的

对于下面这种类型的代码,一般叫做“语法糖”

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都是函数,可以自己用typeof函数进行验证。
所以,可以得出:对象都是通过函数创建的

正文
说完了前言,接下来我们进入正题。

原型prototype
在前言中,我们说了函数也是一种对象,所以函数也是属性的集合,同时,也可以对函数进行自定义属性。
每个函数都有一个属性——prototype。这个prototype的属性值是一个对象(属性的集合),默认只有一个叫做constructor的属性,指向这个函数本身.

“隐式原型”proto
我们先看一段非常常见的代码:
function Fn() { }
   Fn.prototype.name = '张三';
    Fn.prototype.getAge = function () {
       return 12;
};
   var fn = new Fn();
   console.log(fn.name);
   console.log(fn.getAge ());

即,Fn是一个函数,fn对象是从Fn函数new出来的,这样fn对象就可以调用Fn.prototype中的属性。

但是,因为每个对象都有一个隐藏的属性——“proto”,这个属性引用了创建这个对象的函数的prototype。即:fn.proto === Fn.prototype
那么,这里的_proto_到底是什么呢?

其实,这个__proto__是一个隐藏的属性,javascript不希望开发者用到这个属性值,有的低版本浏览器甚至不支持这个属性值。

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

每个对象都有一个_proto_属性,指向创建该对象的函数的prototype。

构造函数、原型、实例之间的关系
实例,原型对象,构造函数,三者之间的关系:

(1) 实例有__proto__属性指向原型对象

(2) 原型对象有constructor指针指向构造函数

(3)构造函数又有prototype属性指向原型对象
点击查看原图


实例和原型关系检测

isPrototypeOf()函数,用于检测两个对象之间似乎否存在原型关系,使用方法如下:

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



 //// 查看 f 对象是否是构造函数 Fn 的实例
 //console.log(f instanceof Fn); 
 //// 查看 f 对象是否是构造函数 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运算符右侧为构造函数,并且js中所有原型都来自Object构造函数。

JS解析器访问属性顺序
当访问实例 f 的属性或方法时,会先在当前实例对象 f 中查找,如果没有,则沿着__proto__继续向上寻找,如果找到最顶头的Object还是找不到,则会抛出undefined。如果在实例中找到,或某层原型中找到,就会读取并使用,同时停止向上找寻。
由此可见,解析器的解析顺序遵循就近原则,如果在最近的位置发现属性存在,便不会继续向上找寻。

原型的应用
数组去重:

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」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/zyfacd/article/details/104909948

vue非父子组件间的传值

前端达人

vue非父子组件传值的基本语法

创建一个新的vue对象
var newvue = new Vue()
    
触发事件
newvue.$emit('自定义事件名', 参数)
    
监听事件
newvue.on('自定义事件名', 触发方法名)
    
销毁事件
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">
    /*
      兄弟组件之间数据传递
    */
    // 提供事件中心
    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() {
        // 监听事件
        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(){
          // 触发兄弟组件的事件
          hub.$emit('tom-event', 1);
        }
      },
      mounted: function() {
        // 监听事件
        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博主「温柔的坚持」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_43745003/article/details/104919633



日历

链接

个人资料

蓝蓝设计的小编 http://www.lanlanwork.com

存档