jquery及zepto的使用

# jQuery

jQuery是一个基于DOM操作的类库;

# 初始化

<title>检测是否正确引入Jquery</title>
<script type="text/javascript" src="public/js/jquery-2.2.3.min.js"></script>
<script>
  // $(document).ready(function () {
  //   alert("jquery it work");
  // });
  $(function () {
    alert("jquery it work");
  });
</script>
1
2
3
4
5
6
7
8
9
10

# 选择器

# 基本选择器

ID 选择器和class 选择器

  1. 兼容性:ID兼容,class 不兼容IE6,7,8
  2. 数量: 通过ID只能获取一个dom元素,通过class可以获取一组元素
  3. 通用性:ID不能重复,class可以重复,所以class比较好用,这也是jQuery能被广泛应该的原因(选择器好)。
$('#LoginTextBox')  // Returns element wrapped as jQuery object with id='LoginTextBox'
$('.active') // Returns all elements with CSS class active.
1
2

# 选择器的使用方式

  • 并列:$("div,span, p.myClass")
  • 家族:$("form input")
  • 父子:$("form > input")
  • 紧邻:$("label + input")
  • 同辈[后辈]:$("form ~ input")
//选择所有在段落内部的超链接
 $("p>a")
//p>a只能选中p标签里的子元素中的a标签,p a会选中p标签下所有(子孙元素)a标签 
1
2
3

# 伪类

# 如何找到所有 HTML select 标签的选中项?

$('[name=NameOfSelectedTag] :selected').each(function(selected) {
  alert($(selected).text());
});

$("#samy").click(function(){ //点击反选功能
  $("[type=checkbox]").each(function(){	//type=checkbox实行便利循环
    if(this.checked){}	//判断type=checkbox里面是否有checked="checked"
  })
})
1
2
3
4
5
6
7
8
9

js实现checkbox全选以及反选

<body>
    <button id="other">反选</button>
    <input type="checkbox" id="all" />全选
    <input type="checkbox" class="check" />1
    <input type="checkbox" class="check" />2
    <input type="checkbox" class="check" />3
    <script>
        var checkbox = document.getElementsByClassName('check')
        var checkAll = document.getElementById('all')
        var checkOther = document.getElementById('other')
        checkAll.onclick = function() {
            var flag = true
            for (var i = 0; i < checkbox.length; i++) {
                if (!checkbox[i].checked) flag = false
            }
            if (flag) {
                for (var i = 0; i < checkbox.length; i++) {
                    checkbox[i].checked = false
                }
            } else {
                for (var i = 0; i < checkbox.length; i++) {
                    checkbox[i].checked = true
                }
            }
        }
        checkOther.onclick = function() {
            for (var i = 0; i < checkbox.length; i++) {
                checkbox[i].checked = !checkbox[i].checked
            }
        }
    </script>
</body>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

# Sizzle选择器

# jQuery 通过哪个方法和 Sizzle 选择器结合

  • Sizzle 选择器采取 Right To Left 的匹配模式,先搜寻所有匹配标签,再判断它的父节点
  • jQuery 通过 $(selecter).find(selecter); 和 Sizzle 选择器结合;

# jQuery/css选择器的区别

  1. 两者的作用不同,CSS选择器找到元素后为设置该元素的样式jQuery选择器找到元素后添加行为;
  2. jQuery选择器拥有更好的跨浏览器的兼容性;

# Dom元素/操作

# jQuery对象与Dom对象

# dom对象转换为jquery对象

一般情况下,dom对象直接用$()就可以转换成jquery对象,如:

$(document.getElementById("samy"))
1
# jquery对象转换成dom对象

一种是用jquery的内置函数get,来获取dom对象,如:

$("#samy").get(0)
1

还有一种方法更简单,因为jquery对象的属性是一个集合,所以我们可以像数组那样,取出其中一项就行

$("#samy")[0];
$("div")[5];//上面这两种返回的都是dom对象,可以直接使用js里的方法
1
2
# document.getElementbyId("myId") 还是 $("#myId")更高效率?

第一种,因为它直接调用了 JavaScript 引擎

document.getElementById("samy")😕/这种方法获取到的就是dom对

$("#samy"): //这种方式获取得到的就是jquery对象

# html API

  • 属性: attr(), removeAttr()

  • 元素/节点内容: text(), html() and val(); 对于input是用val

  • 文档处理

    • append appendTo: 将一个 HTML 元素添加到 DOM 树中
      • **append():**在被选元素的结尾(但仍在元素内部)插入指定的内容。 $(selector).append(content);
      • **appendto():**在被选元素的结尾(但仍在元素的内部)插入指定的内容。但不能使用函数来附加内容。$(content).appendto(selector);
    • prepend prependTo
    • after insertAfter
    • before insertBefore
    • wrap unwrap wrapAll()
    • empty
    • remove
    • clone clone() and Cloning Event Handlers and Data
    • replace target.replaceWith() and replaceAll(target)
    • detach

# detach() 和 remove() 方法的区别

尽管 detach() 和 remove() 方法都被用来移除一个DOM元素, 两者之间的主要不同:

  • 在于 detach() 会保持对过去被解除元素的跟踪, 因此它可以被取消解除,

  • remove() 方法则会保持过去被移除对象的引用.

//提取一个HTML 标记的属性 例如. 链接的href;
//例如. attr(name, value), 这里name是属性的名称,value是属性的新值。
  $("#attr_set").click(function () {
    alert($(this).attr('href'))
    $("#img_src img").attr("src", "../../../../../../img/fengjing.jpg");
    // <div data-id="something"></div>//注意这里有data-id属性;
    //            $("div").attr("data-id", "something");
    /*        $("div").attr({//设置属性回调
                'data-id':'something',
                class:'red'
            });*/
  });
1
2
3
4
5
6
7
8
9
10
11
12

# css API

class操作

  • addClass
  • removeClass
  • toggleClass
  • hasClass

添加和移除CSS类:通过利用 addClass() 和 removeClass() 这两个 jQuery 方法;

css 基础操作

  • offset
  • position
  • scrollTop
  • scrollLeft
  • height
  • width
  • innerHeight
  • innerWidth
  • outerHeight
  • outerWidth
$(document).ready(function () {
  $('button').on("click",function () {
    //$('li:first').css('backgroundColor','yellow');
    $('li:first').css({//一起设置多个
      'backgroundColor':'yellow',
      'font-size':'40px'
    });
    $('li:first').css('font-size',function (index, oldValue) {//设置时回调
      alert(oldValue);//40px
      return '20px';//最后为20px;
    });
  });
});
1
2
3
4
5
6
7
8
9
10
11
12
13

# html/css完整案例

$(function () {
  // 属性 操作 获取,设置
  $("#attr_get").click(function () {
    alert($("#img_src img").attr("src"));
  });
  $("#attr_set").click(function () {
    $("#img_src img").attr("src", "../../../../../../img/fengjing.jpg");
    // <div data-id="something"></div>//注意这里有data-id属性;
    //            $("div").attr("data-id", "something");
    /*        $("div").attr({//设置属性回调
                'data-id':'something',
                class:'red'
            });*/
  });
  $("#attr_remove").click(function () {
    $("#img_src img").removeAttr("src","../../../../../../img/fengjing.jpg");
    //            $("div").removeAttr("data-id");
  });

  // 节点数值的获取 html text val
  // 获取
  $("#node_html").click(function () {
    //            alert($("#get_html").html());//获取
    //            $("#get_html").html("<p>add html</p><p>by click</p>");//替换
    $("#get_html").html(function (index, html) {//有回调的设置
      alert(index+"===:==="+ html);
    });
  });
  $("#node_text").click(function () {
    alert($("#get_text").text());
  });
  $("#node_val").click(function () {
    alert($("#get_val").val());
  });

  // 设置
  $("#node_shtml").click(function () {
    $("#get_html").html('<strong>man</strong>');
  });
  $("#node_stext").click(function () {
    $("#get_text").text('man');
  });
  $("#node_sval").click(function () {
    //对于input是用val
    $("#get_val").val('不约!');
  });

  // 文档处理 append prepend
  $("#dom_add").click(function () {
    $("#fabao ul").append('<li>老师,有第四条吗?</li>')
  });
  $("#dom_pre_add").click(function () {
    $("#fabao ul").prepend('<li>老师,我弱弱的问一下?</li>')
  });

  // 文档处理 appendTo prependTo
  $("#dom_to_add").click(function () {
    $('<li>老师,有第四条吗?</li>').appendTo("#fabao ul")
  });
  $("#dom_preto_add").click(function () {
    $('<li>老师,我弱弱的问一下?</li>').prependTo("#fabao ul")
  });

  // 文档处理 after before
  $("#dom_after").click(function () {
    $("#gongzi").after('<li>这个可以有!</li>');
  });
  $("#dom_before").click(function () {
    $("#gongzi").before('<li>嘿嘿!</li>');
  });

  // 文档处理 insertAfter insertBefore
  $("#dom_insert_after").click(function () {
    $('<li>这个可以有!</li>').insertAfter("#gongzi");
  });
  $("#dom_insert_before").click(function () {
    $('<li>嘿嘿!</li>').insertBefore("#gongzi");
  });

  // 文档处理 wrap unwrap
  $("#dom_wrap").click(function () {
    $("#baoguo p").wrap('<div style="color:#a52a2a"></div>');
  });
  $("#dom_unwrap").click(function () {
    $("#baoguo p").unwrap('<div style="color:#a52a2a"></div>');
  });

  // 文档处理 empty remove clone
  $("#dom_empty").click(function () {
    $("#node_empty").empty();//只移除文字信息;
  });
  $("#dom_remove").click(function () {
    $("#node_remove").remove();//只移除控件
  });
  $("#dom_clone").click(function () {
    alert($("#node_clone").clone().html());
    $("#node_clone").before($("#node_clone").clone())
  });
  $("#dom_replace").click(function () {
    //            $("#node_replace").replaceWith("<p>node_replace by samy</p>");
    $('<p>node_replace by samy</p>').replaceAll($("#node_replace"));
  });

  // CSS 类 操作
  $("#dom_addClass").click(function () {
    $("#dom_class").addClass('new_style');
  });
  $("#dom_removeClass").click(function () {
    $("#dom_class").removeClass('new_style');
  });
  $("#dom_toggleClass").click(function () {
    $("#dom_class").toggleClass('new_style');
    alert($("#dom_class").hasClass('new_style'));
    alert(JSON.stringify($("#dom_class").css(['color','background-color'])));
  });

  // CSS 基础操作//详见之前【选择器】操作
  $("#dom_css").click(function () {
    $("#dom_css_set").css('color', 'red');
    $("#dom_css_set").css({border: "red solid 1px"});
  });
  $("#dom_height").click(function () {
    $("#dom_css_set").height('300px');
  });
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125

# 事件

# 浏览器事件

  • ready 文档就绪事件(当 HTML 文档就绪可用时) 加载/退出 ready() : document.onload 提示:ready() 函数不应与 <body onload=""> 一起使用。
    • ready() 函数用于在文档进入ready状态时执行代码
    • 当DOM 完全加载(例如HTML被完全解析DOM树构建完成时),jQuery允许你执行代码。使用**$(document).ready()的最大好处在于它适用于所有浏览器,jQuery帮你解决了跨浏览器的难题**。
  • resize 触发、或将函数绑定到指定元素的 resize 事件 尺寸缩放
  • scroll 触发、或将函数绑定到指定元素的 scroll 事件
# window.onload 事件和 jQuery ready 函数区别
  • 1.执行时间   window.onload必须等到页面内包括图片的所有元素加载完毕后才能执行。 $(document).ready()是DOM结构绘制完毕后就执行,不必等到加载完毕。

  • 2.编写个数不同   window.onload不能同时编写多个,如果有多个window.onload方法,只会执行一个 $(document).ready()可以同时编写多个,并且都可以得到执行

  • 3.简化写法   window.onload没有简化写法 $(document).ready(function(){})可以简写成$(function(){});

# 事件处理方式

  • on
  • bind 向匹配元素附加一个或更多事件处理器
  • unbind 从匹配元素移除一个被添加的事件处理器
  • trigger 所有匹配元素的指定事件

# 在一个 jQuery 事件处理程序里返回了 false

这通常用于阻止事件向上冒泡。

# bind(),live(),delegate(),on()的区别

jquery中bind(),live(),delegate()都是基于on实现的,on是封装了一个兼容的事件绑定方法,在选择元素上绑定一个或多个事件的事件处理函数;

  • bind(type,[data],fn) 为每个匹配元素的特定事件绑定事件处理函数
  • live(type,[data],fn) 给所有匹配的元素附加一个事件处理函数,即使这个元素是以后再添加进来的
  • delegate(selector,[type],[data],fn) 指定的元素(属于被选元素的子元素)添加一个或多个事件处理程序,并规定当这些事件发生时运行的函数

差别

  • .bind()是直接绑定在元素上
  • .live()则是通过冒泡的方式来绑定到元素上的。更适合列表类型的,绑定到document DOM节点上。和.bind()的优势是支持动态数据
  • .delegate()则是更精确的小范围使用事件代理,性能优于.live()
  • .on()则是最新的1.9版本整合了之前的三种方式的新事件绑定机制

# 自定义事件及fire函数

事件即“发布/订阅”模式,自定义事件即“消息发布”,事件的监听即“订阅订阅” ; jQuery中有更简单的trigger()方法实现自定义事件功能

jQuery 里的 fire 函数用于调用 jQuery 自定义事件列表中的事件

$("#btn").bind("myEventName",function(){//绑定到自定义事件和自定义事件触发时将被执行
	alert("myEventName triggered");
});
$event.trigger("myEventName");

$('input').trigger('focus')//trigger()方法触发事件后,会执行浏览器默认操作
1
2
3
4
5
6

传递参数:

<button id="btn">按钮</button>
<p id="msg"></p>
<script>
  $(function(){
    $('#btn').bind("clickMe",function(event,msg1,msg2){
      $("#msg").text(msg1+' '+msg2)
    })
    $('#btn').trigger("clickMe",["hello","jquery"])
  })
</script>
1
2
3
4
5
6
7
8
9
10

one方法

one方法的功能是让所选定的元素绑定一个仅触发一次的处理函数,格式为:one(type,${data},fn)

<script>
  $(function() {
    function btn_Click() { 
      this.value = "abc123"
    }
    $("input").one("click", btn_Click); //绑定自定义事件
  })
</script>
</head>
<body>
  <input id="Button1" type="button" value="点击查看联系方式" class="btn" />
1
2
3
4
5
6
7
8
9
10
11

JS 原生支持自定义事件步骤:

  • 创建事件 document.createEvent(type)
    • 自定义事件的类型有(即document.createEvent('HTMLEvents')中的参数):
      1. UIEvents:一般化的UI事件。
      2. MouseEvents:一般化的鼠标事件。
      3. MutationEvents:一般化的DOM变动事件。
      4. HTMLEvents:一般化的HTML事件。
  • 初始化事件 event.initEvent(eventType, canBubble, prevent)
  • 监听事件 target.addEventListener('dataavailable', handler, false)
  • 触发事件 target.dispatchEvent(e)
var event = document.createEvent('HTMLEvents'); 
event.initEvent('click', true, true);//接受3个参数: 事件类型,是否冒泡,是否阻止浏览器的默认行为
event.eventType = 'click'; 

a.addEventListener('click', function(){
  console.log(input.value);
  console.log(this.getAttribute('href'));
  console.log(location.href);
}, false); //a是我已经通过id获得好的一个a标签
a.dispatchEvent(event); //触发a上绑定的自定义事件   
//注:jQuery中有更简单的trigger()方法实现自定义事件功能
1
2
3
4
5
6
7
8
9
10
11

自定义事件的发生比较容易控制,你什么时候触发(dispatchEvent/fireEvent)它,它就什么时候发生。

# 同时绑定多个事件

# 一个对象可以同时绑定多个事件,这是如何实现的?

jquery中事件绑定的函数中传递多个事件参数,执行事件的时候判断执行事件的类型

//多个事件同一个函数:
$("div").on("click", "mouseover", function(){});
//多个事件不同函数
$("div").on({
  click: function(){},
  mouseover: function(){}
});
1
2
3
4
5
6
7

# 父元素div绑定两个事件(一个冒泡阶段、一个捕获阶段),子元素也是这种情况。事件触发顺序如何。

var div = document.querySelector('div');
var btn = document.querySelector('button');

//useCapture	可选。布尔值,指定事件是否在捕获或冒泡阶段执行。
// true - 事件句柄在捕获阶段执行
//false- false- 默认。事件句柄在冒泡阶段执行
div.addEventListener('click', function(){
  console.log('bubble','div');//1
},false);
div.addEventListener('click', function(){
  console.log('capture','div');//4
},true);

btn.addEventListener('click', function(){
  console.log('bubble','btn');//2
},false);
btn.addEventListener('click', function(){
  console.log('capture','btn');//3
},true);

//capture div 
//bubble btn
//capture btn
//bubble div
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

捕获事件,后发生冒泡事件。所有事件的顺序是:其他元素捕获阶段事件 -> 本元素代码顺序事件 -> 其他元素冒泡阶段事件 。

<script>
  $(function () {
  // 点击
  $("#click1").click(function () {
    alert("你点击我了");
  });
  // 悬停
  $("#hover1").hover(function () {
    alert("悬停进入事件");
  }, function () {
    alert("悬停离开事件");
  });
  // focus blur 事件
  $("#input1").blur(function () {
    alert("blur事件");
  });
  $("#input1").focus(function () {
    $(this).blur();// 否则会不断的 执行这个,
    alert("focus事件");
  });
  // 键盘事件
  $("#input2").keydown(function () {
    $("#target1").text($(this).val())
  });
  $("#input3").keyup(function () {
    $("#target1").text($(this).val())
  });
  $("#input4").keypress(function () {
    $("#target1").text($(this).val())
  });
  // 事件验证 on bind trigger live
  $("#t_on").on("click", function () {
    alert("on 形式的点击");
  });
  $("#t_bind").bind("click", function () {
    alert("bind 形式的点击");
  });
  $("#t_trigger").click(function () {
    alert("这个动作会触发 #t_on 的点击事件");
    $("#t_on").trigger("click");
  });
  $("#t_live").click(function () { n 
  $("#jiazai").append('<span id="gaibian">装载完成....请点击测试.</span>');
                                  $("#gaibian").click(function () {
                                    alert("live/ 补充方式 形式的点击");
                                  });
                                 });
  $('#ip2').on('keypress', function(){
    $('#result3').append('<br/>keypress');
  });
  $('#ip3').on('change', function(){
    $('#result4').html('changed');
  });
  $('#form1').on('submit', function(){
    alert('submit!');
  });
})
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58

# 动画

# 基本动画

# 方法
  • show( speed, [callback])
  • hide( speed, [callback])
  • toggle( speed, [callback])

描述 ​ $(selector).方法(speed,callback); ​ 可选的 speed 参数规定隐藏/显示的速度,可以取以下值:"slow"、"fast" 或毫秒。 ​ 可选的 callback 参数是隐藏或显示完成后所执行的函数名称。

toggle默认切换hide()和show()   如果你在toggle()方法自定义多个方法,则toggle()是切换你的方法,toggle语法实际如下:   $(selector).toggle(function1(),function2(),functionN(),...)

$("button").click(function(){
  $("p").hide(1000);
});
$('#ButtonToClick').click(function(){
  $('#ImageToHide').hide();//.toggle();
});
1
2
3
4
5
6

# 动画优化

# jQuery 的 slideUp动画 ,如果目标元素是被外部事件驱动, 当鼠标快速地连续触发外部元素事件, 动画会滞后的反复执行,该如何处理呢?

  • 在触发元素上的事件设置为延迟处理:使用 JS 原生 setTimeout 方法
  • 在触发元素的事件时预先停止所有的动画,再执行相应的动画事件:$('.tab').stop().slideUp();
// 上下滑动【卷帘门效果】
// 显示
$("#t_slideDown").click(function () {
  $('.img_container').slideDown();
});
// 隐藏
$("#t_slideUp").click(function () {
  $('.img_container').slideUp();
});
// toggle
$("#t_slideToggle").click(function () {
  $('.img_container').slideToggle();
});
1
2
3
4
5
6
7
8
9
10
11
12
13

# 正则验证

详见【js中的详解】

# 验证插件的使用

​ jQuery Validate https://jqueryvalidation.org/

# jQuery要点其他

# 实现原理

(function( window, undefined ) {//A
  //用一个函数域包起来,就是所谓的沙箱
  //在这里边var定义的变量,属于这个函数域内的局部变量,避免污染全局
  //把当前沙箱需要的外部变量通过函数参数引入进来
  //只要保证参数对内提供的接口的一致性,你还可以随意替换传进来的这个参数
  window.jQuery = window.$ = jQuery;//B
})( window );
1
2
3
4
5
6
7
  • (function(window, undefined) {})(window);:jQuery 利用 JS 函数作用域的特性,采用立即调用表达式包裹了自身,解决命名空间和变量污染问题

  • window.jQuery = window.$ = jQuery;在闭包当中将 jQuery 和 $ 绑定到 window 上,从而将 jQuery 和 $ 暴露为全局变量

jQuery或zepto源码写的好的地方

  • jquery源码封装在一个匿名函数的自执行环境中,有助于防止变量的全局污染;
    • 通过传入window对象参数,可以使window对象作为局部变量使用,好处是当jquery中访问window对象的时候,就不用将作用域链退回到顶层作用域了**,从而可以更快的访问window对象**。
    • 同样,传入undefined参数,可以缩短查找undefined时的作用域链
  • jquery将一些原型属性和方法封装在了jquery.prototype中,为了缩短名称,又赋值给了>jquery.fn,这是很形象的写法;
  • jquery实现的链式调用可以节约代码,所返回的都是同一个对象,可以提高代码效率。 jquery的优势就是链式操作,隐式迭代;

# 入口函数

jQuery 入口函数:

//两种方式: 实现文档就绪后执行 jQuery 方法。
$(document).ready(function(){
   // 开始写 jQuery 代码...
});
//简洁写法(与以上写法效果相同):
$(function(){
   // 开始写 jQuery 代码...
});
1
2
3
4
5
6
7
8

JavaScript 入口函数:

window.onload = function () {
    // 执行代码
}
1
2
3

jQuery 入口函数JavaScript 入口函数的区别

  • jQuery 的入口函数是在 html 所有标签(DOM)都加载之后,就会去执行。执行次数:可以执行多次,第 N 次都不会被上一次覆盖;DOMContentLoaded
  • JavaScript 的 window.onload 事件是等到所有内容,包括外部图片之类的文件加载完后,才会执行。执行次数:只能执行一次,如果第二次,那么第一次的执行会被覆盖;

# $() 函数

$() 函数是 jQuery() 函数的别称; $() 函数用于将任何对象包裹成 jQuery 对象,接着你就被允许调用定义在 jQuery 对象上的多个不同方法。可以将一个选择器字符串传入 $() 函数,它会返回一个包含所有匹配的 DOM 元素数组的 jQuery 对象

$ =  function(){...}();
/func = function(){...}; 
$ =  func(); 
$(".div1") //表示获取类名为div1的元素,例如获取<div class="div1"></div>
$(".div1").onclick //表示类名为div1的div点击事件
//jquery中$.,例如$.post(),$.get(),$.ajax()等这些都是jquery这个对象的方法
1
2
3
4
5
6

jQuery 名称冲突 jQuery 使用 $ 符号作为 jQuery 的简介方式。 某些其他 JavaScript 库中的函数(比如 Prototype)同样使用 $ 符号。 jQuery 使用名为 noConflict() 的方法来解决该问题。 var jq=jQuery.noConflict(),帮助您使用自己的名称(比如 jq)来代替 $ 符号。

# extend/ fn.extend

# 简介
  • $.extend(object); // 为jQuery添加“静态方法”(工具方法);
  • $.extend([true,] targetObject, object1[, object2]); // 对targt对象进行扩展;
  • $.fn.extend(json); // 为jQuery添加“成员函数”(实例方法); 源码中jquery.fn = jquery.prototype,所以对jquery.fn的扩展,就是为jquery类添加成员函数
$.extend({
  min: function(a, b) { return a < b ? a : b; },
  max: function(a, b) { return a > b ? a : b; }
});
$.min(2,3); //  2
$.max(4,5); //  5

var settings = {validate:false, limit:5};
var options = {validate:true, name:"bar"};
$.extend(settings, options);  // 注意:不支持第一个参数传 false
// settings == {validate:true, limit:5, name:"bar"}

$.fn.extend({
  alertValue: function() {
    $(this).click(function(){
      alert($(this).val());
    });
  }
});
$("#email").alertValue();

//比如我们要开发一个插件,做一个特殊的编辑框,当它被点击时,便alert 当前编辑框里的内容。
$.fn.extend({
  alertWhileClick:function() {   
    $(this).click(function(){      
      alert($(this).val());      
    });
  }
});
//页面上为$("#input1")为一个jQuery实例,便实现了扩展,每次被点击时它会先弹出目前编辑里的内容。
$("#input1").alertWhileClick(); 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# fn函数

jQuery.fn = jQuery.prototype 即指向jQuery对象的原型链,对其它进行的扩展,作用在jQuery对象上面;一般用此方法来扩展jQuery的对象插件

jQuery.fn的init方法返回的this指的就是当前操作后的jquery对象,为了实现jquery的链式操作

源码:.fn是指jQuery的命名空间,fn上的成员(方法function及属性property),会对jQuery实例每一个有效。

jQuery.fn = jQuery.prototype = {
  init: function( selector, context ) {//....
};
1
2
3
  • jQuery.fn 的 init 方法 返回的 this 就是 jQuery 对象
  • 用户使用 jQuery() 或 $() 即可初始化 jQuery 对象,不需要动态的去调用 init 方法
# 拷贝(extend)的实现原理

浅拷贝(只复制一份原始对象的引用) var newObject = $.extend({}, oldObject);

深拷贝(对原始对象属性所引用的对象进行进行递归拷贝); 这种方式会完全拷贝所有数据,优点是与不会相互依赖(完全脱离关联),缺点是拷贝的速度更慢,代价更大。 var newObject = $.extend(true, {}, oldObject);

jQuery.extend( target [, object1 ] [, objectN ] ):合并object1, objectN到target对象,如果只有一个参数,则该target对象会被合并到jQuery对象中

jQuery.extend( [deep ], target, object1 [, objectN ] ):深度复制合并对象,第一个参数是boolean类型的true时,将object1, objectN深度复制后合并到target中;关于深度复制,是将除null, undefined,window对象,dom对象,通过继承创建的对象外的其它对象克隆后保存到target中;

深度与非深度复制区别是,深度复制的对象中如果有复杂属性值(如数组、函数、json对象等),那将会递归属性值的复制,合并后的对象修改属性值不影响原对象

obj1 = { a : 'a', b : 'b' };  
obj2 = {  x : { xxx : 'xxx', yyy : 'yyy' },  y : 'y' };  
$.extend(true, obj1, obj2);  
alert(obj1.x.xxx);  // 得到"xxx"  
obj2.x.xxx = 'zzz'; //修改obj2对象属性的内联值,不影响合并后对象obj1
alert(obj2.x.xxx); // 得到"zzz"  
alert(obj1.x.xxx); // 得到"xxx"  //值保持;如果不加true,则得到“zzz”
1
2
3
4
5
6
7
# extend 与 fn.extend的区别

jQuery.extend 扩展jQuery全局, 静态方法; 为jQuery类添加类方法; 可以理解为添加静态方法 jQuery.fn.extend(object); 扩展jQuery对象方法

jQuery.extend 为jquery类添加类方法,可以理解为添加静态方法;

jQuery.extend(object); 为扩展jQuery类本身,为自身添加新的方法。 jQuery.fn.extend(object);给jQuery对象添加方法源码中jquery.fn = jquery.prototype,所以对jquery.fn的扩展,就是为jquery类添加成员函数

jQuery.extend({
  sayhello:function(){
    console.log("Hello,This is jQuery Library");
  }
})
$.sayhello();    //Hello, This is jQuery Library

jQuery.fn.extend({
  check: function() {
    return this.each(function() {
      this.checked = true;
    });
  },
  uncheck: function() {
    return this.each(function() {
      this.checked = false;
    });
  }
})
$( "input[type='checkbox']" ).check(); //所有的checkbox都会被选择
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 扩展序列化及反序列化功能
//jQuery 中没有提供这个功能,所以需要先编写两个jQuery的扩展: 简单扩展;内部实现,详见下面;
$.fn.stringifyArray = function(array) {
  return JSON.stringify(array)
}
$.fn.parseArray = function(array) {
  return JSON.parse(array)
}
//然后调用:
$("#xxx").stringifyArray(array)//$("#xxx")为一个jQuery实例

// 通过原生 JSON.stringify/JSON.parse 扩展 jQuery 实现
$.array2json = function(array) {
  return JSON.stringify(array);
}
$.json2array = function(array) {// $.parseJSON(array); // 3.0 开始,已过时
  return JSON.parse(array);
}
// 调用
var json = $.array2json(['a', 'b', 'c']);
var array = $.json2array(json);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

新版本已经实现: $.parseJSON() 函数用于将符合标准格式的的JSON字符串转为与之对应的JavaScript对象

$(function () { 
    var obj = jQuery.parseJSON('{"name":"samy"}');
    alert( obj.name === "samy" );
})

var str = '[{"href":"baidu.com","text":"test","orgId":123,"dataType":"curry"}]';
jQuery.parseJSON(str);
1
2
3
4
5
6
7

JSON.parse()和jQuery.parseJSON()的区别

有的浏览器不支持JSON.parse()方法,使用jQuery.parseJSON()方法时,在浏览器支持时会返回执行JSON.parse()方法的结果,否则会返回类似执行eval()方法的结果;

parseJSON: function( data ) {
  // Attempt to parse using the native JSON parser first
  if ( window.JSON && window.JSON.parse ) {
    return window.JSON.parse( data );
  }
  if ( data === null ) {
    return data;
  }
  if ( typeof data === "string" ) {
    // Make sure leading/trailing whitespace is removed (IE can't handle it)
    data = jQuery.trim( data );
    if ( data ) {
      // Make sure the incoming data is actual JSON
      // Logic borrowed from http://json.org/json2.js
      if ( rvalidchars.test( data.replace( rvalidescape, "@" )
                            .replace( rvalidtokens, "]" )
                            .replace( rvalidbraces, "")) ) {
        return ( new Function( "return " + data ) )();
      }
    }
  }
  jQuery.error( "Invalid JSON: " + data );
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 深浅拷贝的实现
$ = { //浅复制的模拟实现
  extend : function(target, options) { //浅拷贝
    for (name in options) { 
      target[name] = options[name]; 
    } 
    return target; 
  }, 
  extend : function(deep, target, options) { //深拷贝
    for (name in options) { 
      copy = options[name]; 
      if (deep && copy instanceof Array) { 
        target[name] = $.extend(deep, [], copy); 
      } else if (deep && copy instanceof Object) { 
        target[name] = $.extend(deep, {}, copy); 
      } else { 
        target[name] = options[name]; 
      } 
    } 
    return target; 
  } 
}; 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

深拷贝分析: 跟js中对象的深拷贝类似;

具体分为三种情况:

1. 属性是数组时,则将target[name]初始化为空数组,然后递归调用extend;   2. 属性是对象时,则将target[name]初始化为空对象,然后递归调用extend;   3. 否则,直接复制属性。

源码实现:

$ = function() { 
  var copyIsArray, 
      toString = Object.prototype.toString, 
      hasOwn = Object.prototype.hasOwnProperty; 
  class2type = { 
    '[object Boolean]' : 'boolean', 
    '[object Number]' : 'number', 
    '[object String]' : 'string', 
    '[object Function]' : 'function', 
    '[object Array]' : 'array', 
    '[object Date]' : 'date', 
    '[object RegExp]' : 'regExp', 
    '[object Object]' : 'object' 
  }, 
    type = function(obj) { 
    return obj == null ? String(obj) : class2type[toString.call(obj)] || "object"; 
  }, 
    isWindow = function(obj) { 
    return obj && typeof obj === "object" && "setInterval" in obj; 
  }, 
    isArray = Array.isArray || function(obj) { 
    return type(obj) === "array"; 
  }, 
    isPlainObject = function(obj) { 
    if (!obj || type(obj) !== "object" || obj.nodeType || isWindow(obj)) { 
      return false; 
    } 
    if (obj.constructor && !hasOwn.call(obj, "constructor") 
        && !hasOwn.call(obj.constructor.prototype, "isPrototypeOf")) { 
      return false; 
    } 
    var key; 
    for (key in obj) { 
    } 
    return key === undefined || hasOwn.call(obj, key); 
  }, 
    extend = function(deep, target, options) { 
    for (name in options) { 
      src = target[name]; 
      copy = options[name]; 
      if (target === copy) { continue; } 
      if (deep && copy && (isPlainObject(copy) || (copyIsArray = isArray(copy)))) { 
        if (copyIsArray) { 
          copyIsArray = false; 
          clone = src && isArray(src) ? src : []; 
        } else { 
          clone = src && isPlainObject(src) ? src : {}; 
        } 
        target[name] = extend(deep, clone, copy); 
      } else if (copy !== undefined) { 
        target[name] = copy; 
      } 
    } 
    return target; 
  }; 
  return { extend : extend }; 
}(); 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57

# jQuery 的队列

定义及使用场景

  • jQuery 核心中有一组队列控制方法,由 queue()/dequeue()/clearQueue() 三个方法组成。
  • 主要应用于 animate(),ajax,其他要按时间顺序执行的事件中
var func1 = function(){alert('事件1');}
var func2 = function(){alert('事件2');}
var func3 = function(){alert('事件3');}
var func4 = function(){alert('事件4');}

// 入栈队列事件
$('#box').queue("queue1", func1);  // push func1 to queue1
$('#box').queue("queue1", func2);  // push func2 to queue1

// 替换队列事件
$('#box').queue("queue1", []);  // delete queue1 with empty array
$('#box').queue("queue1", [func3, func4]);  // replace queue1

// 获取队列事件(返回一个函数数组)
$('#box').queue("queue1");  // [func3(), func4()]

// 出栈队列事件并执行
$('#box').dequeue("queue1"); // return func3 and do func3
$('#box').dequeue("queue1"); // return func4 and do func4

// 清空整个队列
$('#box').clearQueue("queue1"); // delete queue1 with clearQueue
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

动画中用到的示例:

var _slideFun = [
  function() {
    $('.one').delay(500).animate({
      top: '+=270px'
    },500, _takeOne);
  },
  function() {
    $('.two').delay(300).animate({
      top: '+=270px'
    },500, _takeOne);
  }
];
$('#demo').queue('slideList', _slideFun);
var _takeOne = function() {
  $('#demo').dequeue('slideList');
};
_takeOne();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 性能的优化方法【要点】

  • 缓存频繁操作DOM对象; 频繁操作的DOM,先缓存起来再操作。
  • 尽量使用id选择器代替class选择器; 因为需遍历所有DOM元素。
  • 总是从#id选择器来继承;
  • 尽量使用链式操作; 用Jquery的链式调用更好。
  • 使用事件委托 on 绑定事件;
  • 采用jQuery的内部函数data()来存储数据;
  • 使用最新版本的 jQuery;

示例:

var str=$("a").attr("href");//比如:
for (var i = size; i < arr.length; i++) {}
for (var i = size, length = arr.length; i < length; i++) {}// 优化后
1
2
3

# 相关问题

# 为什么要将JS源文件的全部内容包装在一个函数中?

这是一种越来越普遍的做法,被许多流行的JS库所采用。 这种技术围绕文件的整个内容创建一个闭包,最重要的是,它可以创建一个私有命名空间,从而有助于避免不同JS模块和库之间潜在的名称冲突

该技术的另一个特性是允许为全局变量提供一个简单的别名,这在jQuery插件中经常使用。

# $(this) 和 this 关键字在 jQuery 中有何不同

  • this表示的是javascript提供的当前对象
  • $(this)表示的是用jquery封装候的当前对象

# jQuery 中的方法链是什么?使用方法链有什么好处?

方法链是对一个方法返回的结果调用另一个方法,这使得代码简洁明了,同时由于只对 DOM 进行了一轮查找,性能方面更加出色。

# jQuery UI

# jQuery 与 jQuery UI、jQuery Mobile 区别

  • jQuery 是 JS 库,兼容各种PC浏览器,主要用作更方便地处理 DOM、事件、动画、AJAX
  • jQuery UI 是建立在 jQuery 库上的一组用户界面交互、特效、小部件及主题
  • jQuery Mobile 以 jQuery 为基础,用于创建“移动Web应用”的框架

# jQuery UI自定义组件

通过向 $.widget() 传递组件名称和一个原型对象来完成;

示例:$.widget("ns.widgetName", [baseWidget], widgetPrototype);

# zepto

# 引入

方式一:在页面中引入并使用Zepto.js; Bower方式安装; 使用zepto.min.js

npm install -g bower
bower install zepto
tree
1
2
3

方式二:Zepto.js自定义构建方法; http://github.e-sites.nl/zeptobuilder/

方式三:处理在线Hack方式

var ndParent = document.getElementsByTagName("script")[0];
var ndScript = document.createElement("script");
//ndScript.src = "http://zeptojs.com/zepto.js";
ndScript.src = "http://127.0.0.1:8080/dist/zepto.custome-touch.js";
ndScript.onload = function () {
    if (window.Zepto){
        console.log("injected");
        window.$ = window.Zepto;
    } 
};
ndParent.parentNode.appendChild(ndScript);
1
2
3
4
5
6
7
8
9
10
11

![](~/20-37-51.jpg)

# 常用方法

# $

用法

  • ​ $(selector, [context]) ⇒ collection
  • $(<Zepto collection>) ⇒ same collection
  • $(<DOM nodes>) ⇒ collection
  • ​ $(htmlString) ⇒ collection
  • ​ $(htmlString, attributes) ⇒ collection v1.0+
  • ​ Zepto(function($){ ... })

说明

  • ​ 使用$选择元素
  • ​ 使用$构造DOM
  • ​ 使用$绑定页面事件
  • ​ $全局变量的注意事项 :$==Zepto
$('div')  //=> all DIV elements on the page
$('#foo') //=> element with ID "foo"

// create element:
$("<p>Hello</p>") //=> the new P element
// create element with attributes:
$("<p />", { text:"Hello", id:"greeting", css:{color:'darkblue'} })
//=> <p id=greeting style="color:darkblue">Hello</p>

// execute callback when the page is ready:
Zepto(function($){
  alert('Ready to Zepto!')
})
1
2
3
4
5
6
7
8
9
10
11
12
13

# 数组

$.each, $.map, $.grep => Array.prototype 遍历对象

# 对象

$.extend => Object.assign

# 工具

$.is* => typeof, instanceof

# 节点

$.length $.camelCase $.trim

# 字符

$.trim, $parseJSON

常用方法示例:

/*        $(function () {
            console.log("zepto page.dome ready");
        });*/
//遍历对象
console.log("遍历对象:");
$.each({a: "name"},function (key, value){
  console.log({key:key, value:value});//打印的是对象;Object {key: "a", value: "name"}
});
//遍历数组
console.log("遍历数组:");
$.each([1,2,3,"a"],function (index, value){
  //[0, 1] [1, 2] [2, 3] [3, "a"]
  console.log(arguments);
});

//遍历数组
console.log("遍历数组:forEach");
var arr = [1,"b",3];
arr.forEach(function (key, value){
  console.log({key:key, value:value});//Object {key: 1, value: 0}  Object {key: b, value: 1} Object {key: 3, value: 2}
});

console.log("遍历数组:each");
$.each(arr,function (key, value){
  console.log({key:key, value:value});//Object {key: 0, value: 1}  Object {key: 1, value: b} Object {key: 2, value: 3}
});

console.log("遍历Map");
var arr = [1,"b",3];
var map = $.map(arr,function(value){
  return value * value;
});
console.log(map);//[1, NaN, 9]

console.log("Grep用法:");
var arr = [1,"b",3];
var grep = $.grep(arr,function(value){//[1, NaN, 9]
  return value %3==0;
});
console.log(grep);//[3]

console.log("Extend用法:");
var obj1 = {name: "samy"};
var obj2 = {gender: "男"};
console.log($.extend(obj1,obj2));//Object {name: "samy", gender: "男"}
var obj1 = {name: "samy"};
var obj2 = {name: "zhang",gender: "男"};//原来key的字段会被冲突掉;
console.log($.extend(obj1,obj2));//Object {name: "zhang", gender: "男"}

console.log("is*用法:");
var obj1 = {name: "samy"};
console.log($.isPlainObject(obj1));//true
console.log($.isArray([]));//true

console.log("CamelCase用法:");
var str = "Samy zhang";
console.log($.camelCase(str));//Samy zhang
console.log($.camelCase("hello-there"));//helloThere

console.log("length trim用法:");
var str = "Samy zhang  ";
console.log(str.length,$.trim(str).length);//12 10

//        console.log("contains用法:");
/*        var str = "Samy zhang  ";
        console.log(str.contains("Samy"));//12 10*/

console.log("parseJSON用法:");//把Json转化成对象;
//        var obj1 = {name: "samy"};
var obj1 = '{"name": "samy"}';
console.log($.parseJSON(obj1));//Object {name: "samy"}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71

# 用Zepto增删改查节点

  • # 插入节点
    • insetAfter
    • insetBefore
    • append
    • prepend
  • 减少节点

    • remove
  • 修改节点

    • html
    • css
    • attr
    • props
    • *class
  • 获取节点

    • parent
    • prev
    • next
    • find
    • children
  • 计算节点

    • width
    • height
    • position
    • offset
    • data

# Detect

检测浏览器允许环境; 构建包含Detect模块的Zepto版本;$.os、$browser用法

# Event

# 高效管理

  • 事件绑定、解绑:on 、off
  • 事件委托机制:on
  • 自定义事件机制:trigger

# 移动端事件(touch)

​ 构建包含Zepto移动端事件的版本 ​ 通过命令行构建 ​ 通过WEB界面构建 ​ 使用移动端事件 ​ 手势事件模块

# 方法

  • $.Event

  • $.proxy

  • bind

  • delegate

  • die

  • ​ event.isDefaultPrevented

  • ​ event.isImmediatePropagationStopped

  • ​ event.isPropagationStopped

  • ​ live

  • ​ off

  • ​ on

  • ​ one

  • ​ trigger

  • ​ triggerHandler

  • ​ unbind

  • ​ undelegate

# Ajax

# 异步加载数据

  • $.ajax
  • $.get、$.post、 load
  • $.param

# jQuery.get() 和 jQuery.ajax() 方法之间的区别

ajax() 方法更强大更具可配置性, 让你可以指定等待多久,以及如何处理错误。get() 方法是一个只获取一些数据的专门化方法。

# 方法

  • $.ajax
  • $.ajaxJSONP
  • $.ajaxSettings
  • $.get
  • $.getJSON
  • $.param
  • $.post
  • load

# 使用单页应用将文件上传到服务器的有哪些方法?

XMLHttpRequest2(streaming),fetch(non-streaming),File API

# Form

# 操作表单

​ 表单的数据序列化; 表单的提交事件

# 方法

​ serialize ​ serializeArray ​ submit

# Effects

​ 方法: $.fx animate

# jQuery 和 Zepto 的区别及使用场景

  • jQuery 主要目标是PC的网页中,兼容全部主流浏览器。在移动设备方面,单独推出 jQuery Mobile
  • Zepto 从一开始就定位移动设备,相对更轻量级。它的 API 基本兼容 jQuery,但对PC浏览器兼容不理想

# 使用上的区别

# 事件

# tap事件点透问题

场景

当A/B两个层上下z轴重叠,上层的A点击后消失或移开(这一点很重要),并且B元素本身有默认click事件(如a标签)或绑定了click事件。在这种情况下,点击A/B重叠的部分,就会出现点透的现象

原因

zepto的tap事件是通过监听绑定在document上的touch事件来完成tap事件的模拟的,并且tap事件是冒泡到document上触发的;在移动端不使用click而用touch事件代替触摸是因为click事件有着明显的延迟,具体touchstart与click的区别如下:

  • touchstart:在这个DOM(或冒泡到这个DOM)上手指触摸开始即能立即触发;

  • click:在这个DOM(或冒泡到这个DOM)上手指触摸开始,且手指未曾在屏幕上移动,且在这个DOM上手指离开屏幕,且触摸和离开屏幕之间的间隔时间较短(某些浏览器不检测间隔时间,也会触发click)才能触发

也就是说,在移动端事件的触发时间按由早到晚排列为:touchstart 早于 touchend 早于 click。亦即click的触发是有延迟的,这个时间大概在300ms左右。

由于我们在touchstart阶段就已经隐藏了罩层A,当click被触发时候,能够被点击的元素则是其下的B元素,根据click事件的触发规则:**只有在被触发时,当前有click事件的元素显示,且在面朝用户的最前端时,才触发click事件。**由于B绑定了click事件(或者B本身默认存在click事件),所以B的click事件被触发,产生了点透的情况。

解决方案

方案一:来得很直接github上有个fastclick可以完美解决

# 为什么基本相同的代码,zepto会点透而fastclick不会呢?

**原因: **zepto的代码里面有个settimeout,在settimeout里面执行e.preventDefault()不会生效,因此zepto中的延迟300ms的click事件会触发,而fastClick不会。

所以zepto的tap事件(通过touchstart和touchend模拟出来的)有点透问题,而fastClick的click事件(通过touchstart和touchend模拟出来的)没有。

因为zepto的tap事件统一是在document的touchend时触发的,若在这里使用e.preventDefault(),那页面上所有元素在touchend后触发的事件都不会被执行了。fastClick使用了touch事件但是touch事件是绑定到了具体dom而不是document上;

//引入fastclick.js,因为fastclick源码不依赖其他库所以你可以在原生的js前直接加上
window.addEventListener( "load", function() {
  FastClick.attach( document.body );
}, false );
//或者有zepto或者jqm的js里面加上
$(function() {
  FastClick.attach(document.body);
});
//当然require的话就这样:
var FastClick = require(‘fastclick‘);
FastClick.attach(document.body, options);
1
2
3
4
5
6
7
8
9
10
11

方案二:用touchend代替tap事件并阻止掉touchend的默认行为preventDefault()

$("#cbFinish").on("touchend", function (event) {
    //很多处理比如隐藏什么的
     event.preventDefault();
});
1
2
3
4

方案三:延迟一定的时间(300ms+)来处理事件

这种方法其实很好,可以和fadeInIn/fadeOut等动画结合使用,可以做出过度效果

$("#cbFinish").on("tap", function (event) {
     setTimeout(function(){
     //很多处理比如隐藏什么的
     },320);
 });
1
2
3
4
5

方案四: 理论上上面的方法可以完美的解决tap的点透问题,如果真的倔强到不行,改用click。

特别是对于遮盖浮层,由于遮盖浮层的点击即使有小延迟也是没有关系的,反而会有疑似更好的用户体验,所以这种情况,可以针对遮盖浮层自己采用click事件,这样就不会出现点透问题

# 使用示例

function hackZepto(){
  var ndParent = document.getElementsByName("script")[0];
  var ndScript = document.createElement("script");
  // ndScript.src = "http://127.0.0.1:8080/dist/zepto.custome-touch.js";
  ndScript.src = "http://zeptojs.com/zepto.js";
  ndScript.onload = function () {
    if (window.Zepto){
      console.log("injected");
      window.$ = window.Zepto;
    }
  };
  ndParent.parentNode.appendChild(ndScript);
}
1
2
3
4
5
6
7
8
9
10
11
12
13

hello示例:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <title>zepto基本示例</title>
    <script type="text/javascript" src="public/js/zepto-1.2.0.js"></script>
    <script type="text/javascript">
      //Hack在线网站的代码方式;
      /*     
       var ndParent = document.getElementsByName("script")[0];
        var ndScript = document.createElement("script");
       // ndScript.src = "http://127.0.0.1:8080/dist/zepto.custome-touch.js";
        ndScript.src = "http://zeptojs.com/zepto.js";
        ndScript.onload = function () {
            if (window.Zepto){
                console.log("injected");
                window.$ = window.Zepto;
            }
        };
        ndParent.parentNode.appendChild(ndScript);
        */
      $(function () {
        console.log("zepto page.dome ready");
      })
    </script>
  </head>
  <body>
    <h1>Hello Samy</h1>
  </body>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

# 相关问题

# 延迟加载(Lazyload)【要点】

# 定义

延迟加载也称为惰性加载,即在长网页中延迟加载图像。用户滚动到它们之前,视口外的图像不会加载。这与图像预加载相反,在长网页上使用延迟加载将使网页加载更快。在某些情况下,它还可以帮助减少服务器负载。

# 好处

  • 首先它能提升用户的体验,试想一下,如果打开页面的时候就将页面上所有的图片全部获取加载,如果图片数量较大,对于用户来说简直就是灾难,会出现卡顿现象,影响用户体验。
  • 有选择性地请求图片,这样能明显减少了服务器的压力和流量,也能够减小浏览器的负担。

# 实现方式

# 第一种

首先将页面上的图片的 src 属性设为 loading.gif,而图片的真实路径则设置在 data-src 属性中,页面滚动的时候计算图片的位置与滚动的位置,当图片出现在浏览器视口内时,将图片的 src 属性设置为 data-src 的值,这样,就可以实现延迟加载。

比较 image 的 offsetTop 与 seeHeight + scrollTop 的大小,当小于时则说明图片已经出现过在视口中,这时候继续判断图片是否已经替换过,如果没有替换过,则进行替换。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Lazyload 1</title>
    <style>
        img {
	    display: block;
	    margin-bottom: 50px;
	    height: 200px;
	}
    </style>
</head>
<body>
    <img src="images/loading.gif" data-src="images/1.png">
    <img src="images/loading.gif" data-src="images/2.png">
    <img src="images/loading.gif" data-src="images/3.png">
    <img src="images/loading.gif" data-src="images/4.png">
    <img src="images/loading.gif" data-src="images/5.png">
    <script>
        function lazyload() {
	    var images = document.getElementsByTagName('img');
	    var len    = images.length;
	    var n      = 0;//存储图片加载到的位置,避免每次都从第一张图片开始遍历		
	    return function() {
		var seeHeight = document.documentElement.clientHeight;
		var scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
		for(var i = n; i < len; i++) {
		    if(images[i].offsetTop < seeHeight + scrollTop) {
		        if(images[i].getAttribute('src') === 'images/loading.gif') {
			     images[i].src = images[i].getAttribute('data-src');
			}
			n = n + 1;
		   }
		}
	  }
	}
	var loadImages = lazyload();
	loadImages();          //初始化首页的页面图片
	window.addEventListener('scroll', loadImages, false);
    </script>
</body>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43

优化:加入抖动功能;做检查判断;

在做事件绑定的时候,可以对 lazyload 函数进行函数节流(throttle)与函数去抖(debounce)处理。

function throttle(fn, delay, atleast) {
    var timeout = null, startTime = new Date();
    return function() {
        var curTime = new Date();
        clearTimeout(timeout);
        if(curTime - startTime >= atleast) {
            fn();
            startTime = curTime;
        }else {
            timeout = setTimeout(fn, delay);
        }
    }
}
var loadImages = lazyload();
loadImages();          //初始化首页的页面图片
window.addEventListener('scroll', throttle(loadImages, 500, 1000), false);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

设置了 500ms 的延迟,和 1000ms 的间隔,当超过 1000ms 未触发该函数,则立即执行该函数,不然则延迟 500ms 执行该函数。

# 第二种

使用 IntersectionObserver API;目前有一个新的IntersectionObserver API (opens new window)可以自动"观察"元素是否可见,Chrome 51+ 已经支持。

  • io.observe(document.getElementById('example'));// 开始观察
  • io.unobserve(element);// 停止观察
  • io.disconnect();// 关闭观察器

IntersectionObserver API 是异步的,不随着目标元素的滚动同步触发。

规格写明,IntersectionObserver的实现,应该采用requestIdleCallback(),即只有线程空闲下来,才会执行观察器。这意味着,这个观察器的优先级非常低,只在其他任务执行完,浏览器有了空闲才会执行。

实现代码:简洁,但是浏览器尚未全部实现。

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Lazyload 3</title>
        <style>
            img {
                display: block;
                margin-bottom: 50px;
                width: 800px;
            }
        </style>
    </head>
    <body>
        <img src="images/loading.gif" data-src="images/1.png">
        <img src="images/loading.gif" data-src="images/2.png">
        <img src="images/loading.gif" data-src="images/3.png">
        <img src="images/loading.gif" data-src="images/4.png">
        <img src="images/loading.gif" data-src="images/5.png">
        <script>
            function query(selector) {
                return Array.from(document.querySelectorAll(selector));
            }
            var io = new IntersectionObserver(function(items) {
                items.forEach(function(item) {
                    var target = item.target;
                    if(target.getAttribute('src') == 'images/loading.gif') {
                        target.src = target.getAttribute('data-src');
                    }
                })
            });
            query('img').forEach(function(item) {
                io.observe(item);
            });
        </script>
    </body>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
  • IntersectionObserver 传入一个回调函数,当其观察到元素集合出现时候,则会执行该函数。
  • io.observe 即要观察的元素,要一个个添加才可以。
  • io 管理的是一个数组,当元素出现或消失的时候,数组添加或删除该元素,并且执行该回调函数

有时,我们希望某些静态资源(比如图片),只有用户向下滚动,它们进入视口时才加载,这样可以节省带宽,提高网页性能。这就叫做"惰性加载"。

function query(selector) {
  return Array.from(document.querySelectorAll(selector));
}
var observer = new IntersectionObserver(
  function(changes) {
    changes.forEach(function(change) {
      var container = change.target;
      var content = container.querySelector('template').content;
      container.appendChild(content);
      observer.unobserve(container);
    });
  }
);
query('.lazy-loaded').forEach(function (item) {
  observer.observe(item);
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

上面代码中,只有目标区域可见时,才会将模板内容插入真实 DOM,从而引发静态资源的加载

# h5移动端兼容问题

# 移动端最小触控区域

移动端最小触控区域44*44px,再小就容易点击不到或者误点

# 移动端的点击事件的有延迟,时间是多久,为什么会有? 怎么解决这个延时?

click 有 300ms 延迟, 为了实现safari的双击事件的设计,浏览器要知道是不是要双击操作

# 参考链接

https://zeptojs.com/

上次更新: 2022/04/15, 05:41:26
×