整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

JS常用方法和一些封装:dom相关

JS常用方法和一些封装:dom相关

s一个非常重要的作用就是对dom进行操作,所谓的dom,可以理解为html代码里的一个个节点。比如,body标签元素就是一个dom。本文对js的dom操作进行一些总结。

按照惯例,先上一个刚写好的小例子,代码在最后给出:

现在,来看看js对dom的一些操作吧。

首先,给出一个html模板,接下来开始用js来做一些有趣的事情吧,css样式的绘制就不细说了,先上代码:

css

*{margin: 0;padding: 0;}
.parent {
 width: 305px;
 height: 302px;
 background: #d7e6ea;
 margin: 100px auto;
 
}
.parent .child {
 width: 80px;
 height: 80px;
 background: deepskyblue;
 float: left;
 margin-top: 10px;
 margin-left: 9px;
 margin-right: 12px;
 margin-bottom: 12px;
 box-shadow: 3px -3px 2px #9898c7;
 text-align: center;
 line-height: 80px;
 font-family: "微软雅黑";
 font-size: 28px;
 text-shadow: 2px 2px 2px yellowgreen;
}

html

<body>
 <div class='parent'>
 <div class='child'>1</div>
 <div class='child'>2</div>
 <div class='child'>3</div>
 <div class='child'>4</div>
 <div class='child'>5</div>
 <div class='child'>6</div>
 <div class='child'>7</div>
 <div class='child'>8</div>
 <div class='child'>9</div>
 </div>
</body>

效果图

从代码中,我们可以看到,body是一个大节点,里面套了一个class属性为parent的div盒子,然后我们又在这个盒子里面放了9个小盒子。

1.最简单的dom方法封装

在本系列中,假设我们不考虑用jQuery。

现在给第三个盒子添加一个id。

<div id='targetBox' class='child'>3</div>

如何拿到这个盒子呢?

很显然,最先想到的肯定是document.getElementById() 方法,于是就有了这样的代码。

var box=document.getElementById('targetBox');
box.style.background='#FEAF51';

效果:

当然,我们很多时候都不希望每次都把document.getElementById(id)给写一遍,那么,是不是可以将这一个过程封装起来呢?

于是,自然而然的,我们会这么写:

//获取JavaScript的dom对象
function dom(id){
 return document.getElementById(id);
};
var box=dom('targetBox');
box.style.background='#FEAF51';

完美运行,我们知道,在jQuery中,是这样的:

var box=$('#targetBox');

那么,为了让代码更加山寨,不妨将dom方法稍微改进一下嘞!

//获取JavaScript的dom对象
function dom(id){
 if(id.toString().indexOf('#') !=-1) {
 id=id.replace('#','');
 }
 return document.getElementById(id);
};
var box=dom('#targetBox');
box.style.background='#FEAF51';

2.如何获取dom元素在父盒子中的位置?

刚才,我们已经获得了编号为3的div盒子,要得到它在父盒子的角标位置,首先肯定要拿到它的父盒子对象吧。

像这样:

var box=dom('#targetBox');
var parent=box.parentElement;

parent打印出来是这样的:

看来很顺利呢,接下来因为要知道目标元素在父盒子的位置,则需要拿到父盒子所有的孩子节点。

像这样:

var children=parent.children;

打印结果:

接下来就要遍历这些孩子节点啦,children 的数据类型是object。

然而,在js中我们可以遍历数组,却无法直接遍历object,咋办呢?

原来,这是一个特殊的object,因为它有一个length属性。有length属性的object,可以通过以下方式转换成数组(注:当然,这边也可以直接获取获取object中的length,然后来遍历。):

Array.prototype.slice.call(object);

举个例子:

var obj={length:2,0:'first',1:'second'};
objArr=Array.prototype.slice.call(obj);
alert(objArr);

结果:

注1: length是几个,就转换几个,如果你length写1,那么只弹出first。

注2: key必须为数字,而且与数组的角标是对应的。

这里不深究call的的意思,我会在以后重新写这方面的内容。

回到正题,现在可以拿到数组形式的children了!

var children=Array.prototype.slice.call(parent.children);

开始遍历:

for(var i=0,len=children.length;i < len;i++){
 if(children[i]==box){
 alert(i);
 }
}

结果:

弹出来下标是2,因为数组下标的起始值是从0开始的。

上面的循环结构还欠缺了一个东西,就是一旦找到box之后,因为及时退出循环才是。像这样:

for(var i=0,len=children.length;i < len;i++){
 if(children[i]==box){
 alert(i);
 break;
 }
}

这样便可以一定程度地提高性能。顺便附上forEach的写法:

children.forEach(function(child,index){
 if(child==box){
 alert(index);
 return false;
 }
});

这样也可以,最后,将这些内容封装成方法,就采用forEach的方式吧!

//查找当前dom元素在父盒子中的位置
function getIndex(dom){
 var index=-1;
 var domArr=Array.prototype.slice.call(dom.parentElement.children);
 domArr.forEach(function(obj,i){
 if(obj==dom){
 index=i;
 return false;
 }
 });
 return index;
};

我学习js的路线就是如此,先想尽办法把功能实现了,然后才开始封装成方法。封装的好处不言而喻,没有人喜欢每次用到这个功能的时候,就去把实现代码拷贝一份吧。

3.如何获取parent下面指定class的元素列表?

parent盒子下面有9个孩子节点,我们能否通过一个什么办法获取到这9个孩子节点呢?显然,这些孩子节点都有一个共同的className,那么我们可以通过这个className来获取。

IE9 + 已经可以通过下面的方式来实现了:

var children=parent.getElementsByClassName('child');

效果:

IE678还是不支持的,那么,如果让我们自己来封装一个方法,又该如何呢?

这里提供一种思路:

1.用getElementsByTagName获取parent元素下所有的节点。

2.遍历这些节点,比较className,如果相同,就用一个数组装起来。

3.返回这个数组。

上代码:

/*通过className获取dom元素进行过滤*/
function getClass(pid,sClass){
 var aEle=dom(pid).getElementsByTagName('*');
 var arrs=[];
 for(var i=0;i<aEle.length;i++){
 if(aEle[i].className.indexOf(sClass)!=-1){
 arrs.push(aEle[i]);
 }
 }
 return arrs;
}

最后,附上最开始小例子的源码:

<!DOCTYPE html>

<html>

<head>

<meta charset="UTF-8">

<title></title>

<style type="text/css">

*{margin: 0;padding: 0;}

body {

background: url(https://ss1.bdstatic.com/lvoZeXSm1A5BphGlnYG/skin/12.jpg?2) no-repeat;

background-size: 100% 128%;

overflow: hidden;

}

.content {

height: 600px;

width: 305px;

margin: 100px auto;

position: relative;

border-top:8px solid #ccc;

border-right:10px solid #ccc;

}

.content .screen {

height: 298px;

width: 305px;

background: #333;

position: absolute;

}

.content .screen .icon {

width: 78px;

height: 78px;

display: inline-block;

background: url(android.png) no-repeat;

background-size: 100% 100%;

position: absolute;

top: 50%;

left: 50%;

margin-top: -39px;

margin-left: -39px;

}

.parent {

width: 305px;

height: 302px;

background: #d7e6ea;

position: absolute;

bottom: 0px;

}

.parent .child {

width: 80px;

height: 80px;

background: #eee;

float: left;

margin-top: 10px;

margin-left: 9px;

margin-right: 12px;

margin-bottom: 12px;

box-shadow: 3px -3px 2px #9898c7;

text-align: center;

line-height: 80px;

font-family: "微软雅黑";

font-size: 28px;

text-shadow: 2px 2px 2px yellowgreen;

}

.parent .child:hover {

cursor: pointer;

background: linear-gradient(#ccc,#666);

}

.putIn {

position: absolute;

width:100%;

height:60px;

line-height: 60px;

color: #fff;

bottom:0;

right: 0;/*为了让padding起作用*/

text-align:right;

font-size: 40px;

overflow: hidden;

padding-right: 8px;

padding-bottom: 8px;

}

</style>

</head>

<body>

<div class="content">

<div class="screen">

<i class="icon"></i>

<span id="putIn" class="putIn"></span>

</div>

<div class='parent'>

<div class='child'>1</div>

<div class='child'>2</div>

<div id='targetBox' class='child'>3</div>

<div class='child'>4</div>

<div class='child'>5</div>

<div class='child'>6</div>

<div class='child'>7</div>

<div class='child'>8</div>

<div class='child'>9</div>

</div>

</div>

</body>

<script>

//获取JavaScript的dom对象

function dom(id){

if(id.toString().indexOf('#') !=-1) {

id=id.replace('#','');

}

return document.getElementById(id);

};

var buttons=document.getElementsByClassName('child');

var putIn=dom('#putIn');

for(var i=0,len=buttons.length;i < len;i++){

buttons[i].onclick=function(){

var num=this.innerHTML;

if(putIn.innerText.length < 13 )

putIn.innerText=putIn.innerText + num;

}

}

</script>

</html>

包是JavaScript这门语言中一个非常强大的特性,它允许函数访问并操作函数外部的变量。在深入理解闭包之前,我们先来看看什么是作用域和词法作用域。

作用域与词法作用域

在JavaScript中,每个函数都有自己的作用域。作用域可以被视为一个变量存储的环境,只有在这个环境中声明的变量和函数才可以被访问。词法作用域是指在代码编写时函数和变量的作用域就已经确定下来,不会改变。

闭包的定义

闭包是指那些能够访问自由变量的函数。所谓自由变量,是指在函数中使用的,但既不是函数参数也不是函数局部变量的变量。闭包可以记忆并访问所在的词法作用域,即使该函数在其词法作用域之外执行。

闭包的用途

闭包有多种用途,包括但不限于:

  • 数据封装和隐私
  • 在异步编程中保持对变量的引用
  • 实现模块化代码

闭包的例子

下面通过几个实际的例子来演示闭包的概念。

示例1:计数器

这个例子展示了如何使用闭包来创建一个私有变量count,这个变量只能通过特定的函数来访问和修改。

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>闭包示例:计数器</title>
</head>
<body>
    <button id="counterBtn">点击我</button>
    <p>点击次数:<span id="count">0</span></p>

    <script>
        function createCounter() {
            let count=0; // 私有变量
            return function() {
                count +=1;
                document.getElementById('count').textContent=count;
            };
        }

        const counter=createCounter();
        document.getElementById('counterBtn').addEventListener('click', counter);
    </script>
</body>
</html>

在这个例子中,createCounter函数返回了一个匿名函数,这个匿名函数能够访问createCounter函数作用域中的count变量。即使createCounter函数执行完成后,这个匿名函数依然能够访问到count变量,这就是闭包的作用。

示例2:模块化代码

闭包允许我们创建模块化的代码,我们可以将相关的功能封装在一个函数中,只暴露必要的接口。

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>闭包示例:模块化</title>
</head>
<body>
    <button id="helloBtn">问好</button>
    <button id="byeBtn">告别</button>

    <script>
        const greetingModule=(function() {
            const name='小明'; // 私有变量
            function sayHello() {
                alert('你好, ' + name + '!');
            }
            function sayGoodbye() {
                alert('再见, ' + name + '!');
            }
            return {
                hello: sayHello,
                bye: sayGoodbye
            };
        })();

        document.getElementById('helloBtn').addEventListener('click', greetingModule.hello);
        document.getElementById('byeBtn').addEventListener('click', greetingModule.bye);
    </script>
</body>
</html>

在这个例子中,我们创建了一个立即执行的函数表达式(IIFE),它返回了一个对象,这个对象包含两个方法:sayHello和sayGoodbye。这两个方法都可以访问到私有变量name,但是外部代码却无法直接访问name变量。这样我们就创建了一个简单的模块,它封装了私有数据和公共接口。

示例3:在循环中使用闭包

经典的面试题之一是在循环中使用闭包。下面的例子演示了如何正确地在循环中创建闭包。

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>闭包示例:循环中的闭包</title>
</head>
<body>
    <script>
        function createButtons() {
            for (var i=1; i <=5; i++) {
                let button=document.createElement('button');
                button.textContent='按钮 ' + i;
                button.addEventListener('click', (function(number) {
                    return function() {
                        alert('这是按钮 ' + number);
                    };
                })(i));
                document.body.appendChild(button);
            }
        }

        createButtons();
    </script>
</body>
</html>

在这个例子中,我们在循环中创建了五个按钮,并为每个按钮添加了点击事件监听器。注意我们是如何使用立即执行的函数表达式来创建闭包的,它捕获了当前的i值,并使每个按钮都能弹出正确的编号。

结论

闭包是JavaScript中一个非常强大的特性,它允许我们以优雅的方式封装和管理数据和功能。理解闭包对于成为一名高效的前端工程师至关重要。以上例子仅仅是闭包用途的冰山一角,但它们展示了闭包的基本概念和一些常见的应用场景。掌握闭包,你将能够编写出更加模块化、高效和可维护的代码。

件是 Web 开发的方向,现在的热点是 JavaScript 组件,但是 HTML 组件未来可能更有希望。 本文就介绍 HTML 组件的基础知识:自定义元素(custom elements)。

一、浏览器处理

我们一般都使用标准的 HTML 元素。

<p>Hello World</p>

上面代码中,<p>就是标准的 HTML 元素。

如果使用非标准的自定义元素,会有什么结果?

<greeting>Hello World</greeting>

上面代码中,<greeting>就是非标准元素,浏览器不认识它。这段代码的运行结果是,浏览器照常显示Hello World,这说明浏览器并没有过滤这个元素。

现在,为自定义元素加上样式。

greeting {
 display: block;
 font-size: 36px;
 color: red;
}

运行结果如下。

接着,使用脚本操作这个元素。

function customTag(tagName, fn){
 Array
 .from(document.getElementsByTagName(tagName))
 .forEach(fn);
}
function greetingHandler(element) {
 element.innerHTML='你好,世界';
} 
customTag('greeting', greetingHandler);

运行结果如下。

这说明,浏览器对待自定义元素,就像对待标准元素一样,只是没有默认的样式和行为。这种处理方式是写入 HTML5 标准的。

“User agents must treat elements and attributes that they do not understand as semantically neutral; leaving them in the DOM (for DOM processors), and styling them according to CSS (for CSS processors), but not inferring any meaning from them.”

上面这段话的意思是,浏览器必须将自定义元素保留在 DOM 之中,但不会任何语义。除此之外,自定义元素与标准元素都一致。

事实上,浏览器提供了一个HTMLUnknownElement对象,所有自定义元素都是该对象的实例。

var tabs=document.createElement('tabs');
tabs instanceof HTMLUnknownElement // true
tabs instanceof HTMLElement // true

上面代码中,tabs是一个自定义元素,同时继承了HTMLUnknownElement和HTMLElement接口。

获取方式:

1.在你手机的右上角有【关注】选项,或点击我的头像,点击关注!(关注我)

2.关注后,手机客户端点击我的主页面,右上角有私信,请私信发我:编程

电脑已经设置好了关键词自动回复,自动领取就好了!这几天上万个消息,真的回复不过来,所以回复的时候请注意关键词!

其实做为一个开发者,有一个学习的氛围跟一个交流圈子特别重要这里请私信我“编程”不管你是小白还是大牛欢迎入住大家一起交流成长。小编会在里面不定期分享干货源码,包括我精心整理的一份零基础教程。欢迎各位感兴趣的的小伙伴。

学习思路:


二、HTML import

有了自定义元素,就可以写出语义性非常好的 HTML 代码。

<share-buttons>
 <social-button type="weibo">
 <a href="...">微博</a>
 </social-button>
 <social-button type="weixin">
 <a href="...">微信</a>
 </social-button>
</share-buttons>

上面的代码,一眼就能看出语义。

如果将<share-buttons>元素的样式与脚本,封装在一个 HTML 文件share-buttons.html之中,这个元素就可以复用了。

使用的时候,先引入share-buttons.html。

<link rel="import" href="share-buttons.html">

然后,就可以在网页中使用<share-buttons>了。

<article>
 <h1>Title</h1>
 <share-buttons/>
 ... ...
</article>

HTML imports 的更多用法可以参考教程(1,2)。目前只有 Chrome 浏览器支持这个语法。


三、Custom Elements 标准

HTML5 标准规定了自定义元素是合法的。然后,W3C 就为自定义元素制定了一个单独的 Custom Elements 标准。

它与其他三个标准放在一起—- HTML Imports,HTML Template、Shadow DOM—-统称为 Web Components 规范。目前,这个规范只有 Chrome 浏览器支持。

Custom Elements 标准对自定义元素的名字做了限制。

“自定义元素的名字必须包含一个破折号(-)所以<x-tags>、<my-element>和<my-awesome-app>都是正确的名字,而<tabs>和<foo_bar>是不正确的。这样的限制使得 HTML 解析器可以分辨那些是标准元素,哪些是自定义元素。”

注意,一旦名字之中使用了破折号,自定义元素就不是HTMLUnknownElement的实例了。

var xTabs=document.createElement('x-tabs');
xTabs instanceof HTMLUnknownElement // false
xTabs instanceof HTMLElement // true

Custom Elements 标准规定了,自定义元素的定义可以使用 ES6 的class语法。

// 定义一个 <my-element></my-element>
class MyElement extends HTMLElement {...}
window.customElements.define('my-element', MyElement);

上面代码中,原生的window.customElements对象的define方法用来定义 Custom Element。该方法接受两个参数,第一个参数是自定义元素的名字,第二个参数是一个 ES6 的class。

这个class使用get和set方法定义 Custom Element 的某个属性。

class MyElement extends HTMLElement {
 get content() {
 return this.getAttribute('content');
 }
 set content(val) {
 this.setAttribute('content', val);
 }
}

有了这个定义,网页之中就可以插入<my-element>了。

<my-element content="Custom Element">
 Hello
</my-element>

处理脚本如下。

function customTag(tagName, fn){
 Array
 .from(document.getElementsByTagName(tagName))
 .forEach(fn);
}
function myElementHandler(element) {
 element.textConent=element.content;
}
customTag('my-element', myElementHandler);

运行结果如下。

ES6 Class 的一个好处是,可以很容易地写出继承类。

class MyNewElement extends MyElement {
 // ...
}
customElements.define('my-new-element', MyNewElement);

今天的教程就到这里,更多用法请参考谷歌的官方教程。