day44 js
内容回顾
1.DOM
三步走 1.获取事件源 2.绑定事件 3.事件驱动
DOM操作: 对节点的操作
1.对标签属性的操作
getAttribute()
setAttribute()
.src
.alt
.id
.className
2.对标签样式属性的操作
objDiv.style.cssStyle
3.对值的操作
双闭合标签
innerText: 只设置文本
innerHTML: 即设置了文本, 又渲染了标签
单闭合标签
input:value
4.对DOM的创建 销毁操作(和上面三种不同的是, 这些都是方法(即函数): 都是动态创建的)
创建: document.creatElement('')
追加: 父.appendChild(子)
父.insertBefore('要插入的新节点','参考的节点') #插入的是参考节点的兄弟节点
销毁: 父.removeChild(子)
5.对DOM的获取的三种方式
document.getElementById()
document.getElementsByClassName()
document.getElementsByTagName()
2.什么是动态页面和静态页面?
动态: 有数据交互的, 有数据驱动的叫动态页面
今日内容
库和框架的区别:
库: 小而精, 实现了js的一部分功能, 主要是DOM的操作
框架: 大而全
路由的跳转:
<body>
<a href="#/home">首页</a>
<a href="#/course">课程</a>
<div class="app"></div>
<script>
//路由的跳转, 通过A标签, 给url加锚点实现, 原来的标题栏不变, 只是下面的页面渲染在变
//如何获取url里面的锚点(#/home), 通过BOM对象获取,浏览器对象模型
window.onhashchange = function () {
switch(window.location.hash){ //window可以省略, hash可以获取url中的'#/home'
case '#/home':
document.getElementsByClassName('app')[0].innerHTML = '<h2>我是首页</h2>';
break;
case '#/course':
document.getElementsByClassName('app')[0].innerHTML = '<h2>我是课程</h2>';
break;
default:
break;
}
}
</script>
</body>
一.选项卡案例(tab栏选项卡)
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style>
*{
margin: 0;
padding: 0;
}
#tab{
width: 480px; /*父盒子的高度不设置,直接让子盒子撑起来*/
margin: 20px auto;
border: 1px solid red;
}
ul{
width: 100%;
overflow: hidden;
list-style-type: none;
}
ul li{
float: left;
width: 160px;
height: 60px;
text-align: center;
line-height: 60px;
}
ul li a{
text-decoration: none;
color: #000;
}
li.active{
}
p{
display: none;
height: 200px;
text-align: center;
line-height: 200px;
}
p.active{
display: block;
}
</style>
</head>
<body>
<div id="tab">
<ul>
<li class="active">
<a href="#">首页</a>
</li>
<li>
<a href="#">新闻</a>
</li>
<li>
<a href="#">图片</a>
</li>
</ul>
<p class="active">首页内容</p>
<p>新闻内容</p>
<p>图片内容</p>
</div>
<script>
//先做标题栏效果, 在做内容区效果
//标题栏效果
var objlis = document.getElementsByTagName('li');
var objps = document.getElementsByTagName('p');
for (var i=0; i<objlis.length; i++) {
objlis[i].index = i; //排除变量提升带来的影响; 把i保存起来
objlis[i].onclick = function () {
for (var j=0; j<objlis.length; j++){ //利用排他思想, 做标题部分的切换
objlis[j].className = '';
objps[j].className = '';
}
this.className = 'active'; //这里的this用objlis[i]行不行? 不行, 因为js的变量提升, 这个的i不是局部的,而是全局的
console.log(i); //i 的结果是for完事后i的结果, 是 3
objps[this.index].className = 'active';
}
}
</script>
变量的提升: 如何解决: 用不变的'对象.属性'来保存变量的值(上面的例子使用的就是此方法)
<script>
//js中的变量提升
console.log(a); //打印的是;undefined , 而不是报错, 是因为js会把所有var的变量提升到文档的开头; 比如这里是将 var a; 放到了开头, 下面相当于直接赋值 a = 2.
var a = 2;
console.log(a);
//js中的变量提升, 会带来一个问题: 作用域的问题, 会把局部的变量作用域搞成全局的.
console.log(a); //打印undefined(假设上面的a = 2不存在, 结果是undefined)
{
var a = 6; //由于js的变量提升: 这句实际是两句: 第一句是在文档的最开头声明变量 var a; 第二句是在这里赋值变量 a = 6;
console.log(a); //打印6
}
console.log(a); //打印6
</script>
</body>
</html>
变量的提升: 使用es6的let解决选项卡的问题: 而且var都可以用let替换, 不会有任何问题
<script>
//用let声明变量, 不会存在变量提升, 属于局部
console.log(a); //直接报错,
{
let a = 3;
console.log(a);
}
console.log(a); //直接报错
</script>
let解决变量提升
<script>
var objlis = document.getElementsByTagName('li');
var objps = document.getElementsByTagName('p');
for (let i=0; i<objlis.length; i++) {
objlis[i].onclick = function () {
for (var j=0; j<objlis.length; j++){
objlis[j].className = '';
objps[j].className = '';
}
objlis[i].className = 'active'; //这里原来的this 也就可以使用不会变量提升的: 局部的: let声明的变量i 了.
objps[i].className = 'active'; //这里原来的this 也就可以使用不会变量提升的: 局部的: let声明的变量i 了.
}
}
</script>
自定义标签: 系统的东西都是可以自定义的
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style>
abc{
width: 100px;
height: 100px;
display: block;
}
</style>
</head>
<body>
<div id="box">
<p class="child1">bajie</p>
</div>
<script>
var objDiv = document.getElementById('box');
var objP = document.createElement('abc');
objDiv.appendChild(objP);
</script>
</body>
</html>
父.insertBefore('要插入的新节点','参考的节点') #插入的是参考节点的兄弟节点
<body>
<div id="box">
<p class="child1">bajie</p>
</div>
<script>
var objDiv = document.getElementById('box');
var objP1 = document.getElementsByClassName('child1')[0];
var objP2 = document.createElement('p');
objDiv.insertBefore(objP2,objP1); //插入到参考元素之前, 没有After
objP2.innerText = 'wukong';
</script>
</body>
二.定时器
两种定时器:
一次性定时器: 可以做异步
循环周期定时器: 可以做倒计时, 可以做动画:比如每一秒改动值,
js跟python一样都有垃圾回收机制
但是定时器对象, 垃圾回收收不回
开定时器: 一次性定时器
var timer = setTimeout(fn, 1000) #一秒之后调用fn函数
开定时器: 循环定时器
(interval 间隔)
setInterval(fn, 1000) #每一秒执行一次fn
清定时器:
clearTimeout(timer) #开启定时器时,返回的定时器对象
clearInterval(timer)
一次性定时器:
<body>
<button id="start">开启定时器</button>
<button id="clear">清除定时器</button>
<script>
//一次性计时器主要是来做异步的
var timer; //全局变量,还是要在最外面写, 不要指望变量提升给你做这个事,
document.getElementById('start').onclick = function () {
//一次性定时器: 未来数据交互的时候, 如果数据阻塞了, 可以考虑加一个定时器来处理
timer = setTimeout(function () {
console.log(111)
},3000);
console.log(222);
// clearTimeout(timer); //此时的console.log(111)不会被执行
};
document.getElementById('clear').onclick = function () { //清除的实际, 如果在开始计时后的3秒内按清理, 是可以阻止 111 的打印的
clearTimeout(timer);
}
</script>
</body>
循环定时器
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style>
#box{
width: 100px;
height: 100px;
}
</style>
</head>
<body>
<button id="start">开启定时器</button>
<button id="clear">清除定时器</button>
<div id="box"></div>
<script>
var timer = null;
var count = 0;
document.getElementById('start').onclick = function () {
var objDiv = document.getElementById('box');
clearInterval(timer); //清除之前的定时器, 防止多次按钮的时候, 产生加速效果
timer = setInterval(function () {
count += 10;
objDiv.style.marginLeft = count + 'px';
},200)
}
</script>
</body>
</html>
三.js中的面向对象
1.创建对象的几种常用方式
使用Object()或对象字面量创建对象
<script>
//使用Object(): 内置的构造函数来创建对象
var person = new Object();
person.name = 'bajie';
person.age = 18;
person.fav = function () {
alert(person.name);
}
person.fav();
</script>
<script>
//字面量方式创建对象: 推荐这种方式创建对象
var person = {
name: 'bajie',
age: 18,
fav: function () {
alert(this.name);
}
};
person.fav();
//这两种方式创建非常简单, 但是有个问题, 当创建多个类似的对象时, 代码会重复多次, 如何解决? 使用"工厂模式"
</script>
工厂模式创建对象: 把重复创建对象的过程写进函数中
<script>
function createPerson() {
var person = {
name: 'bajie',
age: 18,
fav: function () {
alert(this.name);
}
};
return person;
}
var p1 = createPerson();
var p2 = createPerson();
console.log(p1 === p2); //不是一个内存地址
console.log(p1.age);
//有个问题, 我们现在虽然可以源源不断地创建对象了, 但是我们不能一眼就看出来 p1, 和p2是属于哪个对象类型:
console.log(p1 instanceof Object); //instanceof 可以检测出p1是属于object类型,但是不能检测出是属于person
//如何解决: 我们可以使用自定义的构造函数的方法来创建对象
</script>
自定义的 构造函数模式创建对象
在进行自定义构造函数创建对象之前, 我们首先了解一下构造函数和普通函数的区别
1.实际上并不存在创建构造函数的特殊语法 ? 其与普通函数唯一的区别在于调用方法
对于任意函数, 只要使用new操作符调用, 那么它就是构造函数;
不使用new操作符调用, 那么它就是普通函数
2.按照惯例, 我们约定构造函数以大写字母开头, 这样是为了有利于区分二者.
例如 new Array(); new Object();
<body>
<script>
//自定义构造函数
function Person(name, age) { //相当于python中的Class Person
this.name = name;
this.age = age;
this.fav = function () {
alert(this.name);
};
}
var p1 = new Person('八戒', 18); //相当于python中的实例化
console.log(p1); //和原生的有一点不同: 原生的方法都在 __proto__里, 而自定义的方法直接在对象里
p1.fav();
function Fruit(name, age) { //相当于python中的Class Person
this.name = name;
this.age = age;
this.fav = function () {
alert(this.name);
};
}
var f1 = new Fruit('wukong', 100);
console.log(p1 instanceof Object);
console.log(f1 instanceof Object);
console.log(p1 instanceof Person);
console.log(f1 instanceof Fruit); //四个打印的结果都是true, 而且能区分对象是属于哪个类了
//现在有个问题: 上面的Person和Fruit对象中有同样的方法, 当我们进行调用的时候, 无疑是内存的消耗
//如何解决: 原型模式创建对象
</script>
</body>
原型模式创建对象: 把几个对象相同的方法放到他们的父类中: 如 Person.prototype 就是Person的父类
<script>
//(constructor 构造器)
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.showName = function () { //原型: prototype
console.log(this); //this 是谁? 是Person
};
var p1 = new Person('datang', 100);
p1.showName();
console.log(p1); //此时对象的方法就在__proto__里面了, 和原生的构造函数一样了
</script>
四.BOM
BOM: 浏览器对象模型, 操作浏览器部分功能的api, 比如让浏览器自动滚动
BOM: 我们需要记的不多, 因为浏览器都给我们做好了, 比如刷新按钮,前进后退, 标题栏上面的叉,滚动, 地址栏上的信息
BOM是包含DOM的.
BOM window history历史信息
location本地对象
screen屏幕
1.弹出系统对话框
alert() 不同浏览器外观不一样
confirm() 兼容不好
prompt() 不推荐
2.打开窗口,关闭窗口
<script>
//需求: 3秒后, 打开百度网页
setTimeout(function () {
// window.open('http://www.baidu.com/','_blank'); //(blank 空白的)模式不写默认就是在新窗口打开
window.open('http://www.baidu.com/','_self'); //在自己当前窗口打开百度网址
},3000);
</script>
3.location对象
window.location对象中有很多方法和属性
属性:
hash: url中'#asdf'这一堆
host:主机(主机名+端口号)
hostname: 主机名
href:url完成地址 : https://www.baidu.com:80/home/a.jpg?srt=info&asd
origin:原始地址 : https://www.baidu.com:80
pathname:路径地址(也叫路由地址) : /home/a.jpg
search: : ?srt=info&asd
port:端口
protocol:协议, https: 是把用户名密码打包在传输, s = ssl
方法:
reload(): 就是网页上的刷新
toString()
<script>
window.location.href = 'http://www.baidu.com'; //也可以进行网页的跳转 , 是在当前窗口打开
</script>
4.(navigator 领航员)
userAgent: 用户代理,用的什么浏览器
5.history
history.go(-1): 上一页
history.go(0): 刷新
window.location.reload():刷新 //这三个都是全局刷新, 尽量少用. 局部刷新比较好(必用ajax)