术语
链式风格
也叫jQuery风格
特殊函数jQuery
- jQuery(选择器)用于获取对应元素
- 但它不返回这些元素
- 它返回一个对象,称之为jQuery构造出来的对象
- 这个对象可以操作对应的元素
一些理解
- jQuery是构造函数,因为它构造出来一个对象
- jQuery不是构造函数,因为它不需要通过new jQuery()构造一个对象
- 总结:jQuery是一个不需要加new的构造函数
- jQuery不是常规意义上的构造函数
- jQuery用了一些技巧
最后推荐一篇不错的博客
jQuery 都过时了,那我还学它干嘛?
实现jQuery示例
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>实现jQuery示例</title>
</head>
<body>
<div class="test">
你好1
<div class="child">child1</div>
<div class="child">child2</div>
<div class="child">child3</div>
</div>
<div class="test">
你好2
<div class="child">child4</div>
<div class="child">child5</div>
</div>
<div class="test">
你好3
<div class="child">child6</div>
</div>
<div id="container">
container
</div>
<script src="jquery.js"></script>
<script src="main.js"></script>
</body>
</html>
//这种写法代码不够优化,原因:当你创建多个jQuery对象的时候,对象的共有属性是不共有的,占用内存
window.$ = window.jQuery = (selectorOrArrayOrTemplate) => {
let elements;
if(typeof selectorOrArrayOrTemplate === "string"){
if(selectorOrArrayOrTemplate[0] === "<"){
elements = [createElement(selectorOrArrayOrTemplate)];
}else{
elements = document.querySelectorAll(selectorOrArrayOrTemplate);
}
}else if(selectorOrArrayOrTemplate instanceof Array){
elements = selectorOrArrayOrTemplate;
}
function createElement (String){
const container = document.createElement("template");
container.innerHTML = string.trim();
return container.content.firstChild;
}
//返回本身,可以操作elements
return {
jquery: true,
elements: elements,
get (index) {
return elements[index];
},
appendTo (node) {
if( node instanceof Element){
// 遍历 elements,对每个 el 进行 node.appendChild 操作
this.each(el => node.appendChild(el));
}else if(node.jquery === true){
// 遍历 elements,对每个 el 进行 node.get(0).appendChild(el)) 操作
this.each(el => node.get(0).appendChild(el))
}
},
append (children) {
if(children instanceof Element){
this.get(0).appendChild(children);
}else if(children instanceof HTMLCollection){
for(let i = 0; i <children.length; i++){
this.get(0).appendChild(children[i]);
}
}else if(children.jquery === true){
children.each(node => this.get(0).appendChild(node));
}
},
find (selector) {
let array = [];
for(let i = 0 ; i < elements.length; i++){
const elements2 = Array.from(elements[i].querySelectorAll(selector));
array = array.concat(elements2);
}
array.oldApi = this; //指向旧 api
return jQuery(array);
},
each (fn) {
for(let i = 0; i < elements.length; i++){
fn.call(null, elements[i],i);
}
return this;
},
parent () {
const array = [];
this.each((node) => {
if(array.indexOf(node.parentNode) === -1){
array.push(node.parentNode);
}
});
return jQuery(array);
},
children () {
const array = [];
this.each((node) => {
array.push(...node.children);
});
return jQuery(array);
},
print () {
console.log(elements);
},
//闭包:函数访问外部变量
addClass (className) {
for(let i = 0; i < elements.length; i++){
const element = elements[i];
element.classList.add(className);
}
return this;
},
oldApi: selectorOrArrayOrTemplate.oldApi,
end () {
return this.oldApi;// this就是新的api
}
}
}
//代码优化
window.$ = window.jQuery = (selectorOrArrayOrTemplate) => {
let elements;
if(typeof selectorOrArrayOrTemplate === "string"){
if(selectorOrArrayOrTemplate[0] === "<"){
elements = [createElement(selectorOrArrayOrTemplate)];
}else{
elements = document.querySelectorAll(selectorOrArrayOrTemplate);
}
}else if(selectorOrArrayOrTemplate instanceof Array){
elements = selectorOrArrayOrTemplate;
}
function createElement (String){
const container = document.createElement("template");
container.innerHTML = string.trim();
return container.content.firstChild;
}
const api = Object.create(jQuery.prototype);
Object.assign({
elements: elements,
oldApi: selectorOrArrayOrTemplate.oldApi,
});
return api;
}
jQuery.fn = jQuery.prototype = {
constructor:jQuery,
jQuery: true,
get (index) {
return this[index];
},
appendTo (node) {
if( node instanceof Element){
// 遍历 elements,对每个 el 进行 node.appendChild 操作
this.each(el => node.appendChild(el));
}else if(node.jquery === true){
// 遍历 elements,对每个 el 进行 node.get(0).appendChild(el)) 操作
this.each(el => node.get(0).appendChild(el))
}
},
append (children) {
if(children instanceof Element){
this.get(0).appendChild(children);
}else if(children instanceof HTMLCollection){
for(let i = 0; i <children.length; i++){
this.get(0).appendChild(children[i]);
}
}else if(children.jquery === true){
children.each(node => this.get(0).appendChild(node));
}
},
find (selector) {
let array = [];
for(let i = 0 ; i < this.length; i++){
const elements2 = Array.from(this[i].querySelectorAll(selector));
array = array.concat(elements2);
}
array.oldApi = this; //指向旧 api
return jQuery(array);
},
each (fn) {
for(let i = 0; i < this.length; i++){
fn.call(null, this[i],i);
}
return this;
},
parent () {
const array = [];
this.each((node) => {
if(array.indexOf(node.parentNode) === -1){
array.push(node.parentNode);
}
});
return jQuery(array);
},
children () {
const array = [];
this.each((node) => {
array.push(...node.children);
});
return jQuery(array);
},
print () {
console.log(this);
},
//闭包:函数访问外部变量
addClass (className) {
for(let i = 0; i < this.length; i++){
const element = this[i];
element.classList.add(className);
}
return this;
},
end () {
return this.oldApi;// this就是新的api
}
}
const $div = $('<div><span>1</span></div>');
const $childList = $('.child');
$('body').append(childList);