一,重要的jQuery概念
1,jQuery的核心概念
1) jquery的核心函数: $ 这个是一个函数方法
2)jquery的核心对象:$() 所返回的对象
所以jQuery的两个特性是:
1】链式调用
2】读写合一:jquery作为函数调用和作为对象调用的不同的方法
// 绑定文档监听$( function() {// 获取页面的元素,写交互的逻辑var $btn = $("#btn2") // 这个表示用的jquery的核心函数 $ 就可以拿到对应的dom元素// 这里可以看到,返回的不是dom的对象,因为dom对象没有后边的.方法,所以应该是jquery特有的对象,// 被jquery封装了一些方法$btn.click(function() {var username = $("#username").val()alert(username)})})
执行jquery函数,返回的就是jquery的对象
2,jQuery是什么
// 这里是一个匿名的函数(function(window) {// 定义的jQuery,是一个函数var jQuery = function() {// 定义的这个jQuery返回的是jQuery对象return new jQuery}// 给window全局的对象绑定jQuery的方法window.$ = window.jQuery = jQuery}).(window) // 立即执行函数的调用,同时赋值了一个参数是window
3,jQuery里面的this是什么
this 依旧是 发生事件的那个dom元素
$(function() {$("#btn2").click(function() {alert(this.innerHTML)})})
4,jQuery里面的$( ) 里面的参数可以是什么类型
1)可以是选择器
2)可以是dom元素
这个时候,里面得参数是this,而this指的是发生事件得那个dom元素,然后获取dom元素得html内容
$(function() {$("#btn2").click(function() {// alert(this.innerHTML)alert($(this).html())})})
3)可以是一个函数,回调函数,就如同上面一样
4)
5,jQuery的遍历
1)语法的遍历,
$(function() {var arr = [1,2,3]$.each(arr, function(index, item) {console.log(index,item )})})
2)遍历页面的元素
<div>用户名:<input type="text" id="username"><button> 使用jqury 获取input 的值 </button><button> 使用jqury 获取input 的值 </button><button> 使用jqury 获取input 的值 </button><button> 使用jqury 获取input 的值 </button></div><script>// 遍历页面的button,这个时候,each里面的参数是每一个遍历的dom元素$('button').each(function(index, item) {console.log(index, item.innerHTML, this)})</script>
6,jQuery的dom伪数组
$ 有一个size和length的方法,这个表示选中的是对应dom元素的数组,这样就是一个伪数组
// 查看$ 的dom 数组console.log($('button').length,$('button').size() )
注意:伪数组没有数组相应的方法,伪数组是一个对象类型,只有length和index属性
7,使用index() 可以拿到其所在兄弟元素的下标
兄弟的dom元素
<div>用户名:<input type="text" id="username"><button id="btn1"> 使用jqury 获取input 的值 </button><button> 使用jqury 获取input 的值 </button><button id="btn"> 使用jqury 获取input 的值 </button><button> 使用jqury 获取input 的值 </button></div><script>console.log($('#btn').index())console.log($('#btn1').index())console.log($('input').index())</script>
二,jQuery的选择器
jQuery 中文文档:http://jquery.cuishifeng.cn/
1,基本的选择器
// id 选择器$('#btn-id')// class选择器$('.btn-class')// 元素 选择器$('input')// 并集选择器$('input', '#btn-id')// 交集选择器$('input''#btn-id')
2,层次选择器
用途:用来查找兄弟元素,子元素,后代元素的
// 类似于css的选择器ancestor decendant // 找后代parent > child // 找孩子prev + nextprev ~ siblings
3,过滤选择器
用途:在原有的选择器匹配的元素中进一步进行过滤的选择器
例子
// 找到第一个div,设置为红色 —— API :first$('div:first').css('background', 'red')// 找到box元素的最后一个元素,设置为红色 —— API :last$('.box:last').css('background', 'red')// 选择div中没有box属性的元素(这个class中有没有box属性和没有class属性的box) —— API :not(selector)$('div:not(.box)').css('background', 'red')// 选取li元素的第2个和第3个元素 —— API :gt(index) :lt(index)// 多个过滤选择器是依次执行的,不是同时执行$('li:gt(0):lt(3)').css('background', 'red')// 选择li选择器里面内容为BBB的元素,标记为红色$('li:contains('BBB')').css('background', 'red')// 查找隐藏的元素$('li:hidden').css('background', 'red')// 选择有title属性的li元素$('li[title]').css('background', 'red')// 选择有title属性值为hello的li元素$('li[title=hello]').css('background', 'red')
例子:
给表格添加隔行变色的功能
// 找到表格id=data的元素里面的奇数行$('#data>tbody>tr:odd').css('background', 'red')
4,表单选择器
// 选择不可用的input为text的选择框$(':text:disable').css('background', 'red')// 显示已选择的爱好的个数$(':checkbox:checked').length
三,jQuery工具
// 数组和对象操作$.each(object,[callback])$.inArray(val,arr,[from])$.type(obj)$.trim(str)
例子:
点击一个按键 显示对应的div内容
方法一:
1,给按钮都添加click事件
2,拿到点击的按键的下标
3,找到div的所有内容,设置所有的div的css为display:none
4,使用得到的下标去修改对应的div的dispaly:block
方法二:不一定需要把所有的div都去设置为display:none,可以把当前已经显示的修改为none,再把点击的显示为block,其他的元素可以不做操作
四,属性
操作元素的属性
- 属性
- CSS 类
- HTML代码/文本/值
五,css
- 注意:jQuery的scrollTop的方法要获取页面的坐标方法对于chrome和ie浏览器有一个兼容问题
- (一个获取页面的坐标需要使用html元素,另外一个需要body元素)
- 解决方法
是需要整个页面的坐标会出现兼容,
// 兼容 1$('html').scrollTop() + $('body').scrollTop()// 兼容2$(document.documentElement).scrollTop() + $(document.body).scrollTop
如果需要设置页面坐标为0(比如需求是回到顶部),就需要选择好两个选择器,使用交集选择器
$('html,body').scrollTop(0)
需求:渐进式返回顶部(设置定时器不断的修改跳转的坐标)
$(function () {// 需要渐进的滚动$('#to-top').click(function () {// console.log('点击')// 总的距离,需要兼容浏览器var distance = $('body').scrollTop() + $('html').scrollTop()console.log(distance)// 总的时间var time = 500// 间隔时间var intervalTime = 50// 间隔的距离var intervalDis = distance / (time / intervalTime)// 设置定时器var intervalId = setInterval(function () {// 不断修改坐标distance -= intervalDis// 当到达顶部的时候,就清除定时器if (distance <= 0) {distance = 0clearInterval(intervalId)}$('html, body').scrollTop(distance)}, intervalTime)})})
六,事件
mouseout([[data],fn]) —— 在进入这个元素的子元素的时候,也会调用out和over
mouseover([[data],fn])
与
mouseenter([[data],fn]) —— 在进入子元素的时候不会调用,只有进入这个元素会调用
mouseleave([[data],fn])
的区别
hover使用的是enter和leave
jQuery2 - 练习 - 选择爱好运动
需求:
功能说明:
1. 点击’全选’: 选中所有爱好
2. 点击’全不选’: 所有爱好都不勾选
3. 点击’反选’: 改变所有爱好的勾选状态
4. 点击’全选/全不选’: 选中所有爱好, 或者全不选中
5. 点击某个爱好时, 必要时更新’全选/全不选’的选中状态
6. 点击’提交’: 提示所有勾选的爱好
[ ] [ ] [ ] [ ] [ ]
var $checkedAllBox = $('#checkedAllBox')var $items = $(':checkbox[name=items]')// 1. 点击'全选': 选中所有爱好$('#checkedAllBtn').click(function () {$items.prop('checked', true)$checkedAllBox.prop('checked', true)})// 2. 点击'全不选': 所有爱好都不勾选$('#checkedNoBtn').click(function () {// console.log('不选')$items.prop('checked', false)$checkedAllBox.prop('checked', false)})// 3. 点击'反选': 改变所有爱好的勾选状态$('#checkedRevBtn').click(function () {$items.each(function () {// dom对象的 checked属性this.checked = !this.checked})// 如果所有的items都选中,那就需要更新状态// 1,拿到里面没有选中的数量console.log($items.filter(':not(:checked)').length === 0)$checkedAllBox.prop('checked', $items.filter(':not(:checked)').length === 0)})// 4. 点击'全选/全不选': 选中所有爱好, 或者全不选中$('#checkedAllBox').click(function () {// console.log('点击')// console.log(this.checked)// dom的checkbox就是有一个checked的属性现在需要做的就是统一这个全选框和每一个爱好的选择情况$items.prop('checked', this.checked)})// 5. 点击某个爱好时, 必要时更新'全选/全不选'的选中状态// jQuery有一个隐式遍历,所以添加click事件是隐式遍历一个全部添加$items.click(function() {// 根据每一个item的点击状态,修改全选框的状态$checkedAllBox.prop('checked', $items.filter(':not(:checked)').length === 0)})// 6. 点击'提交': 提示所有勾选的爱好// 提交被选中的value$('#sendBtn').click(function() {// 需要遍历每一个选中的选项,然后alter$items.filter(':checked').each(function() {alert(this.value)})})
● 注意:
● 1,jQuery的对象和DOM的对象不一样,需要注意
● 2,jQuery的隐式遍历和需要给每一个对象遍历是不一样的,根据需求来做
● 3,设置属性的值,可以使用prop或者attr,prop是设置值为布尔值的属性
● 4,对于需要元素的筛选,可以使用filter,如果查找可以使用find
jQuery3 - 练习 - 文档的增删改查
需求:
功能说明:
1. 点击’Submit’, 根据输入的信息在表单中生成一行员工信息
2. 点击Delete链接, 提示删除当前行信息, 点击确定后删除信息
技术要点:
1. DOM查询
2. 绑定事件监听
3. DOM增删改
4. 取消事件的默认行为
<table id="employeeTable"><tr><th>name</th><th>email</th><th>salary</th><th> </th></tr><tr><td>Tom</td><td>tom@qq.com</td><td>5000</td><td><a href='dddd'>删除</a></td></tr><tr><td>jerry</td><td>jerry@qq.com</td><td>6000</td><td><a href='dddd'>删除</a></td></tr><tr><td>bob</td><td>bob@qq.com</td><td>7000</td><td><a href='dddd'>删除</a></td></tr></table><div id="formDiv"><h4>添加新员工</h4><table><tr><td class="word">name:</td><td class="inp"><input type="text" name="empName" id="empName"></td></tr><tr><td class="word">email:</td><td class="inp"><input type="text" name="email" id="email"></td></tr><tr><td class="word">salary:</td><td class="inp"><input type="text" name="salary" id="salary"></td></tr><tr><td colspan="2" align="center"><button id="addEmpButton" value="abc">提交</button></td></tr></table></div>
// 1. 点击'Submit', 根据输入的信息在表单中生成一行员工信息var $empName = $('#empName')var $email = $('#email')var $salary = $('#salary')console.log($empName)$('#addEmpButton').click(function () {// console.log('111', empName, email, salary)// 1,收集数据var empName = $empName.val()var email = $email.val()var salary = $salary.val()// 2,添加到页面// 2.1 ) 创建一个空的/*<tr><td>jerry</td><td>jerry@qq.com</td><td>6000</td><td><a href='dddd'>删除</a></td></tr>*/$('<tr></tr>').append('<td>' + empName + '</td>').append('<td>' + email + '</td>').append('<td>' + salary + '</td>').append('<td><a href="ddd">删除</a></td>').appendTo('#employeeTable')// 给新添加的a标签添加事件.find('a').click(deleteData)// 3,清空表格empName = $empName.val('')email = $email.val('')salary = $salary.val('')})// 2. 点击Delete链接, 提示删除当前行信息, 点击确定后删除信息$('a').click(deleteData)// 出现的问题:新增加的a标签还是会跳转,同时没有点击事件// 所以需要给a标签添加事件function deleteData() {// 阻止a的跳转,阻止默认行为event.preventDefault()// 找到当前点击的行// 可以使用$()包裹一个dom元素转换为jQuery对象,来使用jQuery的方法var $tr = $(this).parent().parent()var name = $tr.children('td:first').html()if (confirm('确定删除' + 'name' + '么?')) {$tr.remove()}}
- 总结点:
- 1,无法打印jQuery的值,是空,所以需要区分jQuery对象和dom对象,
必要的时候可以使用jQuery包裹DOM对象,来转换DOM对象,使其拥有jQuery对象的方法
// 可以使用$()包裹一个dom元素转换为jQuery对象,来使用jQuery的方法var $tr = $(this).parent().parent()
2,对于一个jQuery对象可以使用链式的方法,不断的给这个对象增加元素和给新的元素新增方法
$('<tr></tr>').append('<td>' + empName + '</td>').append('<td>' + email + '</td>').append('<td>' + salary + '</td>').append('<td><a href="ddd">删除</a></td>').appendTo('#employeeTable')// 给新添加的a标签添加事件.find('a').click(deleteData)
3,如果一个函数需要多次调用,可以单独定义一个函数,然后把这个函数传入需要调用的click事件中,这个时候不能给函数添加括号,添加括号表示函数的调用,不添加就表示传入的函数参数
// 2. 点击Delete链接, 提示删除当前行信息, 点击确定后删除信息$('a').click(deleteData)function deleteData() {event.preventDefault()// 找到当前点击的行// 可以使用$()包裹一个dom元素转换为jQuery对象,来使用jQuery的方法var $tr = $(this).parent().parent()var name = $tr.children('td:first').html()if (confirm('确定删除' + 'name' + '么?')) {$tr.remove()}}
4,在jQuery中,阻止元素的默认行为的方法和原生的js一样
// 阻止a的跳转,阻止默认行为event.preventDefault()
5,要获取点击的当前元素,可以使用this关键字
// 找到当前点击的行var $tr = $(this).parent().parent()
jQuery4 - 练习 - 轮播图
实现功能:
点击上下可以平滑的移动
实现思路:
1,先完成简单功能,瞬间翻页,
1.1 拿到当前的list的left的值,
1.2 判断是上翻还是下翻
1.3 修改left的值,加上偏移量
2,设置定时器,一段距离一段距离的翻页,当达到目标距离的时候,就清除定时器
2.1 找到总的偏移量
2.2 通过总时间和间隔时间,拿到每一个单位距离
2.3 设置定时器,每次给当前的left的坐标添加一个单位距离,然后给list更新left的值
2.4 计算总的偏移量的目标坐标
2.5 当移动的坐标 === 目标坐标时,就清除定时器,不再翻页
代码
<body><div id="container"><div id="list"><img src="./img/1.jpg" alt="1"><img src="./img/2.jpg" alt="2"><img src="./img/3.jpg" alt="3"><img src="./img/4.jpg" alt="4"><img src="./img/5.jpg" alt="5"></div><div id="printsDiv"><span index='1' class="on"></span><span index='2'></span><span index='3'></span><span index='4'></span><span index='5'></span></div><a href="javascript" id="prev" class="arrow"><</a><a href="javascript" id="next" class="arrow">></a></div><script src="./app.js"></script></body>
$(function () {/*// 1.1 找到下一页的图标,添加点击事件$('#next').click(function () {// 阻止a的默认行为event.preventDefault()// console.log('点击')// 1.2 每次点击的时候,就修改list的left的值$('#list').css('left', -600)})*/// 1,定义需要的变量var $container = $('#container')var $list = $('#list')var $points = $('#printsDiv')var $prev = $('#prev')var $next = $('#next')// 定义图片长度,也就是偏移长度var page_width = 600var Time = 400var Item_Time = 20// 2,定义上下翻页$next.click(function () {// 阻止a标签的默认行为event.preventDefault()// 执行翻页函数,下一页nextPage(true)})$prev.click(function () {// 阻止a标签的默认行为event.preventDefault()// 执行翻页函数,上一页nextPage(false)})// 3,定义翻页函数function nextPage(next) {// console.log('----', currentLeft)/* 瞬间翻页的效果// 定义总的偏移量// 简单的条件判断可以使用三元表达式var offset = next ? -page_width : page_width// 设置新的left值,当前的left 加上 偏移的长度$list.css('left', currentLeft + offset)*/// 4,实现平滑的翻页/*1)总的偏移量 offset2)总的时间 Time = 400 ??为什么要定义总的时间3)移动的时间间隔:Item_Time = 20 ??4)单位的偏移量:offset/(Time/Item_Time)??直接定义一个间隔数,直接拿到间隔的时间和距离,不用定义总时间,间隔时间,再拿到间隔次数*/// 4.1 定义总的偏移量var offset = 0offset = next ? -page_width : page_width// 4.2 定义总的时间// 4.3 计算单元移动的距离,然后不断的增加这个距离var ItemOffset = offset / (Time / Item_Time)// 拿到当前list的left值,根据参数判断是左翻还是右翻var currentLeft = $list.position().left// 4.4 设置定时器,每次增加单元的距离// 目标left距离var targetLeft = currentLeft + offsetvar intervalId = setInterval(function () {// 每次需要修改的left的值,要不断的变化currentLeft += ItemOffset// 4.5 在翻页left达到目标距离,就清除定时器if (currentLeft === targetLeft) {clearInterval(intervalId)}// 设置新的left值,当前的left 加上 偏移的长度$list.css('left', currentLeft)}, Item_Time)}})
总结:
1,首先可以考虑好实现的方案,一步一步的思考,不用太着急 —— 不要着急写
2,先分析需要调用的函数,再去定义函数 —— 这样可以把函数执行的函数抽离出来,简化逻辑
3,简单的条件判断可以直接简写为三元表达式 —— 简化代码
4,在过程中需要的变量可以集中定义在代码顶部 —— 方便代码解读
5,当实现功能的逻辑复杂的时候,可以一步一步的去做,一个变量一个变量的定义 —— 理清思路,慢慢来
jQuery5 - 源码解析 - 整体结构
整体架构
jQ的两大特色是
1,jQuery对象的构建方式:$(‘#id’)
2 ,jQueryl方法的调用方式$(‘#id’).css().html.hide()
1,实现jQ对象
1.1)一般都是使用js的类去构建,为了不使用new去创建实例,所以需要这个类返回一个实例
var aQuery = function(selector, context) {return new aQuery();}aQuery.prototype = {name:function(){},age:function(){}}
问题:这样会构建的类,返回类的实例,就会造成陷入死循环
1.2)所以需要返回一个正确的实例
var aQuery = function(selector, context) {return aQuery.prototype.init();}aQuery.prototype = {init:function(){return this;}name:function(){},age:function(){}}// 这样返回的就是一个类的拥有的三个方法
代码审查:构建的类返回类的一个实例,这个实例返回它自己this
问题如下:
var aQuery = function(selector, context) {return aQuery.prototype.init();}aQuery.prototype = {init: function() {this.age = 18return this;},name: function() {},age: 20}aQuery().age //18
实例的方法访问不到类自己的属性,只能拿到这个实例的属性
1.3)需要独立类的属性和方法的属性,所以可以返回一个新类去区分单独的作用域
var aQuery = function(selector, context) {return new aQuery.prototype.init();}aQuery.prototype = {init: function() {this.age = 18return this;},name: function() {},age: 20}//Uncaught TypeError: Object [object Object] has no method 'name'console.log(aQuery().name())
代码审查:每次使用new一个新的init实例,就可以独立不同实例的作用域
出现的问题:由于返回的是init的this,就不能拿到类的其他的方法
1.4)正确的建立实例,同时拿到类的属性和方法
实现的关键点:看jQ的处理
// Give the init function the jQuery prototype for later instantiationjQuery.fn.init.prototype = jQuery.fn;
所以 我们可以写成
var aQuery = function(selector, context) {return new aQuery.prototype.init();}aQuery.prototype = {init: function() {return this;},name: function() {return this.age},age: 20}// 关键点aQuery.prototype.init.prototype = aQuery.prototype;console.log(aQuery().name()) //20
代码审查:
init是作为实例化这个类,所以里面不要放其他的属性
关键点的解释:(不是很明白)
2,链式调用
DOM的链式调用的特点:
1,可以节约js的代码
2,返回的都是同一个对象
2.1)要让所有的方法都指向一个DOM对象,可以使用扩展原型的方法,然后return this来实现
var aQuery = function(selector, context) {return new aQuery.prototype.init();}aQuery.prototype = {init: function() {return this;},name: function() {return this},age: 20}// 关键点aQuery.prototype.init.prototype = aQuery.prototype;// 链式调用aQuery().init().name()// 分解a = aQuery();a.init()a.name()
代码审查:由于每个方法都是返回this,所以又会回到当前的实例,然后访问到自己的原型
这些链式的调用都是同步链式,因为js是无阻塞的语言,所以都是同步链式操作,js的异步是需要调用一些接口来实现的,比如setTimeout类似的
3,jQ的插件接口
目的:jq已经做好了属性和方法的封装,但是也需要给开发者提供对方法的扩展(就是提供一个安装插件的接口,来扩展jq的功能),从封装的角度来说,不是直接去修改prototye的友好用户接口,而是需要提供一个对于jq函数的扩展接口 extend,jq一般提供jQuery.fn.extend( ) 来对对象添加方法
以下是extend的实现:
说明:
jQuery.extend和jQuery.fn.extend其实是同指向同一方法的不同引用
jQuery.extend 对jQuery本身的属性和方法进行了扩展
jQuery.fn.extend 对jQuery.fn的属性和方法进行了扩展
但是源码使用的语句是:jQuery.extend = jQuery.fn.extend = function() { }
jQuery.extend = jQuery.fn.extend = function() {var src, copyIsArray, copy, name, options, clone,target = arguments[0] || {}, // 常见用法 jQuery.extend( obj1, obj2 ),此时,target为arguments[0]i = 1,length = arguments.length,deep = false;// Handle a deep copy situationif ( typeof target === "boolean" ) { // 如果第一个参数为true,即 jQuery.extend( true, obj1, obj2 ); 的情况deep = target; // 此时target是truetarget = arguments[1] || {}; // target改为 obj1// skip the boolean and the targeti = 2;}// Handle case when target is a string or something (possible in deep copy)if ( typeof target !== "object" && !jQuery.isFunction(target) ) { // 处理奇怪的情况,比如 jQuery.extend( 'hello' , {nick: 'casper})~~target = {};}// extend jQuery itself if only one argument is passedif ( length === i ) { // 处理这种情况 jQuery.extend(obj),或 jQuery.fn.extend( obj )target = this; // jQuery.extend时,this指的是jQuery;jQuery.fn.extend时,this指的是jQuery.fn--i;}for ( ; i < length; i++ ) {// Only deal with non-null/undefined valuesif ( (options = arguments[ i ]) != null ) { // 比如 jQuery.extend( obj1, obj2, obj3, ojb4 ),options则为 obj2、obj3...// Extend the base objectfor ( name in options ) {src = target[ name ];copy = options[ name ];// Prevent never-ending loopif ( target === copy ) { // 防止自引用,不赘述continue;}// Recurse if we're merging plain objects or arrays// 如果是深拷贝,且被拷贝的属性值本身是个对象if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {if ( copyIsArray ) { // 被拷贝的属性值是个数组copyIsArray = false;clone = src && jQuery.isArray(src) ? src : [];} else {// 被拷贝的属性值是个plainObject,比如{ nick: 'casper' }clone = src && jQuery.isPlainObject(src) ? src : {};}// Never move original objects, clone themtarget[ name ] = jQuery.extend( deep, clone, copy ); // 递归~// Don't bring in undefined values} else if ( copy !== undefined ) { // 浅拷贝,且属性值不为undefinedtarget[ name ] = copy;}}}}// Return the modified objectreturn target;}
注意1:
jQuery中利用上面实现的扩展机制,添加了许多方法,其中
1)直接添加在构造函数上,被称为工具方法
jQuery.extend({isFunction: function() {},type: function() {},parseHTML: function() {},parseJSON: function() {},ajax: function() {}// ...})
2)添加到原型上
jQuery.fn.extend({queue: function() {},promise: function() {},attr: function() {},prop: function() {},addClass: function() {},removeClass: function() {},val: function() {},css: function() {}// ...})
当我们直接使用$(‘#test’)创建一个对象时,实际上是创建了一个init的实例,这里的真正构造函数是原型中的init方法
所以涉及到的使用jQ的一个点:
// 在使用jQuery时常常会毫无节制使用$(),比如对于同一个元素的不同操作:var width = parseInt($('#test').css('width'));if(width > 20) {$('#test').css('backgroundColor', 'red');}
从对于jq内部源码了解以后,发现执行$() 就构建一个init的实例,所以对于同一个对象重新去做$()的获取,是非常消耗内存的,所以建议对于一个对象的操作,进行一次命名赋值。
注意2:
区别:静态方法,工具方法,实例方法
工具方法:是jq放在构造函数中的方法,就是添加在 jQuery.extend里面的方法,这里面的方法不需要声明一个实例对象就可以直接使用,又叫静态方法,工具方法在使用的时候因为不用创建新的实例,因此相对效率会高很多,但是不节省内容。
实例方法:是放在原型中的方法,就是添加在jQuery.fn.extend里面的方法,在使用的时候需要创建一个新的实例对象才能访问,所以称为实例方法,由于需要创建实例才能使用,所以使用的成本比工具的方法高,但是节约内存。
汇总代码
jq的框架代码
(function(ROOT) {// 构造函数var jQuery = function(selector) {// 在jQuery中直接返回new过的实例,这里的init是jQuery的真正构造函数return new jQuery.fn.init(selector)}jQuery.fn = jQuery.prototype = {constructor: jQuery,version: '1.0.0',init: function(selector) {// 在jquery中这里有一个复杂的判断,但是这里我做了简化var elem, selector;elem = document.querySelector(selector);this[0] = elem;// 在jquery中返回一个由所有原型属性方法组成的数组,我们这里简化,直接返回this即可// return jQuery.makeArray(selector, this);return this;},// 在原型上添加一堆方法toArray: function() {},get: function() {},each: function() {},ready: function() {},first: function() {},slice: function() {}// ... ...}jQuery.fn.init.prototype = jQuery.fn;// 实现jQuery的两种扩展方式jQuery.extend = jQuery.fn.extend = function(options) {// 在jquery源码中会根据参数不同进行很多判断,我们这里就直接走一种方式,所以就不用判断了var target = this;var copy;for(name in options) {copy = options[name];target[name] = copy;}return target;}// jQuery中利用上面实现的扩展机制,添加了许多方法,其中// 直接添加在构造函数上,被称为工具方法jQuery.extend({isFunction: function() {},type: function() {},parseHTML: function() {},parseJSON: function() {},ajax: function() {}// ...})// 添加到原型上jQuery.fn.extend({queue: function() {},promise: function() {},attr: function() {},prop: function() {},addClass: function() {},removeClass: function() {},val: function() {},css: function() {}// ...})// $符号的由来,实际上它就是jQuery,一个简化的写法,在这里我们还可以替换成其他可用字符ROOT.jQuery = ROOT.$ = jQuery;})(window);// 写一个Drag插件例子:(function() {// 构造function Drag(selector) {}// 原型Drag.prototype = {constructor: Drag,init: function() {// 初始时需要做些什么事情this.setDrag();},// 稍作改造,仅用于获取当前元素的属性,类似于getNamegetStyle: function(property) {},// 用来获取当前元素的位置信息,注意与之前的不同之处getPosition: function() {},// 用来设置当前元素的位置setPostion: function(pos) {},// 该方法用来绑定事件setDrag: function() {}}// 一种对外暴露的方式window.Drag = Drag;})();// 通过扩展方法将拖拽扩展为jQuery的一个实例方法(function ($) {$.fn.extend({becomeDrag: function () {new Drag(this[0]);return this; // 注意:为了保证jQuery所有的方法都能够链式访问,每一个方法的最后都需要返回this,即返回jQuery实例}})})(jQuery);
代码审查:
1,构建的jq插件也需要让他可以有jq的特性,所以需要按照jq的框架去构建新的插件
2,插件传入是一个键值对的形式
参考连接:
jQuery 2.0.3 源码分析core - 整体架构
详细图解jQuery对象,以及如何扩展jQuery插件
