day03 js 路由跳转 选项卡 变量提升问题 自定义标签 对DOM对象的操作 定时器 js中的面向对象 BOM对象的操作

day03 js 路由跳转 选项卡 变量提升问题 自定义标签 对DOM对象的操作 定时器 js中的面向对象 BOM对象的操作
 
一.小知识
1.什么是动态页面和静态页面?
    动态: 指的是有数据交互的, 有数据驱动的页面叫动态页面    
 
2.库和框架的区别
    库: 小而精, 实现了js的一部分功能, 主要是DOM的操作,如jQuery
    框架: 大而全,如VUE
 
3.路由的跳转    
    3.1.用来做单页面应用:
        通过a标签, 给url加锚点实现 
        整个页面没有跳转: 页面中原来的标题栏不变, 只是下面的页面渲染在切换
    3.2.如何获取url里面的锚点(#/home), 通过BOM对象获取,浏览器对象模型
        window.onhashchange = function () {                //点击a标签时,url栏会变化: 这时用window.onhashchange就可以检测url栏是否有变化
            switch(window.location.hash){                  //用window.location.hash获取锚点 
                case '#/home': ... ; break;                //不同的锚点对应不同的页面切换
                case '#/course': ... ; break;
                default: break;        
                }
            }
<body>
    <a href="#/home">首页</a>
    <a href="#/course">课程</a>
    <div class="app"></div>                                //这个内容区域不应该这样写,应该使用DOM的操作,动态地创建和销毁,(此处需做缓存,以后会说到)
    <script>
        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>
 
4.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{                                       /*标题栏ul的宽和大盒子的宽一样,给下面的li清除浮动,去掉默认的小圆点*/
            width: 100%;
            overflow: hidden;
            list-style: none;
        }
        ul li{                                    /*把所有的li浮动起来,实现并排显示,给每个li设置固定的宽高,让文字水平居中,垂直居中,给li搞个灰色*/
            float: left;
            width: 160px;
            height: 60px;
            text-align: center;
            line-height: 60px;
            background-color: #cccccc;
        }
        ul li a{                                  /*给a标签设置字体为黑色,去掉下划线*/
            text-decoration: none;
            color: #000;
        }
        li.active{                                /*动态设置: li的颜色,为红色*/
            background-color: #ff0000;
        }
        p{                                        /*内容区p,初始隐藏,设置为红色,固定一个高度,文字水平居中,垂直居中*/
            display: none;
            height: 200px;
            text-align: center;
            line-height: 200px;
            background-color: red;
        }
        p.active{                                 /*动态设置: 把内容区显示出来*/
            display: block;
        }
    </style>
</head>
<body>
    <div id="tab">                                <!--大盒子里,两个小盒子,第一个小盒子为ul选项区,里面是li; 第二个小盒子是p内容区-->
        <ul>
            <li class="active">
                <a href="script:void(0);">首页</a>
            </li>
            <li>
                <a href="script:void(0);">新闻</a>
            </li>
            <li>
                <a href="script:void(0);">图片</a>
            </li>
        </ul>
        <p class="active">首页内容</p>
        <p>新闻内容</p>
        <p>图片内容</p>
    </div>
    <script>
        //先做标题栏效果, 在做内容区效果
        var objlis = document.getElementsByTagName('li');            //获取所有选项卡li
        var objps = document.getElementsByTagName('p');              //获取所有内容区p
        //var i;                                                     //变量的提升: for里面的var i=0;提到了for的外面var i; 
        for (var i=0; i<objlis.length; i++) {                        //这个循序for用于检测所有li的点击事件: 就不用创建三个点击事件了
            objlis[i].index = i;                                     //排除变量提升带来的影响: 把i保存起来,谁能存?不同的标签对象objlis[i]可以,把i存到'对象.属性'里面
            objlis[i].onclick = function () {                        //这里的i没问题: 是绑定事件时给i的值
                                                                     //因为还没有点击,所以驱动程序还没开始执行,因为是全局的变量i,所以没有点击时: 驱动里的i没有问题
                                                                     //但是当有点击事件的时候, for已经完事了,这时驱动里面的i是全局的变量,是固定值: 3   
                for (var j=0; j<objlis.length; j++){                 //这个循环for用于重置所有的li和p: 就不用写三个重置li和三个重置p了
                    objlis[j].className = '';                        //利用排他思想,先把所有li重置: 重置颜色为灰色
                    objps[j].className = '';                         //利用排他思想,先把所有p重置: 重置所有内容区为隐藏
                    }
                this.className = 'active';                           //单独设置点击的li
                //objlis[i].className = 'active';                    //这里的this用objlis[i]不行,因为js的变量提升,点击事件事,驱动里的i是全局的 3 
                //console.log(i);                                    //测试验证: 驱动里的i的结果是for完事后全局变量i的结果, 是3
                objps[this.index].className = 'active';              //单独设置点击li对应的内容区域
            }
        }
    </script>
 
5.变量的提升(坑)
    5.1.如何理解: 这是因为js会把文档中所有的var定义的变量,提升到文档的开头,叫做'变量的提升'
    5.2.带来的问题: 作用域的问题: 会把局部的变量作用域搞成全局的, 也就是说没有js中没有了局部变量
    5.3.如何解决: 
        5.3.1.方式一: 把变量i保存起来,用不同的不变的标签对象的属性来保存: 即'对象.属性'来保存变量的值
    console.log(a);                         //如果单独这样打印会报错: a is not defined
    var a = 2;                              //如果有了这句,上面就会打印: undefined  
    {
    var a = 6;                              //由于js的变量提升: 这句实际是两句: 第一句变量提升:是在文档的最开头声明变量 var a; 第二句是在这里赋值变量 a = 6;
    console.log(a);                         //打印6; 全局的a的值
    }
    console.log(a);                         //打印6; 全局的a的值
        5.3.2.方式二: 使用es6的let解决选项卡的问题: 而且var都可以用let替换, 不会有任何问题
    console.log(a);                         //直接报错
    {
        let a = 3;
        console.log(a);
    }
    console.log(a);                         //直接报错
        5.3.3.方式二: 用let替换var,实现选项卡功能,更简单
<script>
    let objlis = document.getElementsByTagName('li');
    let objps = document.getElementsByTagName('p');
    for (let i=0; i<objlis.length; i++) {
        objlis[i].onclick = function () {
            for (let j=0; j<objlis.length; j++){       
                objlis[j].className = '';
                objps[j].className = '';
            }
            objlis[i].className = 'active';    
            objps[i].className = 'active';     
        }
    }
</script>
 
6.自定义标签
    自定义标签名,当系统的东西没有你写的好的时候, 那么就自定义
<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <style>
        abc{
            width: 100px;
            height: 100px;
            background-color: red;
            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>
 
二.DOM的操作: 
    对DOM对象的操作: 
        增
        var objP2 = document.createElement('p');                        //创建新子节点
        objDiv.insertBefore(objP2,objP1);                               //插入子节点,bojP1是新子节点的参照的兄弟节点
<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>
 
三.定时器(两种)
1.一次性定时器
    作用: 可以用来做异步
          垃圾回收机制: js和python一样都有,但是不包括定时器对象  
    开定时器: var timer = setTimeout(fn, 1000)                          //一秒之后调用fn函数, 只调用一次就结束
    关定时器: clearTimeout(timer) 
<body>
    <button id="start">开启定时器</button>
    <button id="clear">清除定时器</button>
    <script>
        var timer = null;                                              //全局变量,还是要事先定义, 不要暨希望变量提升来做这个事
        document.getElementById('start').onclick = function () {
            timer = setTimeout(function () {                           //未来数据交互的时候, 如果数据阻塞了, 可以考虑加一个一次性定时器来处理
                console.log(111)                                       //异步体现在哪? 不等待: 定时器外面的代码不用等我定时器里的代码执行完再往下走      
            },3000);
            console.log(222);
            //clearTimeout(timer);                                     //清除的时机: 如果在开始计时后的3秒内'清理', 是可以阻止 111 的打印的
        };
        document.getElementById('clear').onclick = function () {        
            clearTimeout(timer);
        }
    </script>
</body>
 
2.循环周期定时器
    作用: 可以做倒计时
          可以做动画: 比如每一秒改动值
          垃圾回收机制: js和python一样都有,但是不包括定时器对象
    开定时器: var timer = setInterval(fn, 1000)                         //每一秒执行一次fn (interval 间隔), 循环调用
    关定时器: clearInterval(timer)    
<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <style>
        #box{
            width: 100px;
            height: 100px;
            background-color: red;
        }
    </style>
</head>
<body>
    <button id="start">开启定时器</button>
    <button id="clear">清除定时器</button>
    <div id="box"></div>
    <script>
        var timer = null;                                              //timer对象需要事先定义好                                          
        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.创建对象的5种常用方式
    1.1.使用Object()函数: 内置的构造函数来创建对象
    var person = new Object();
    person.name = 'bajie';
    person.age = 18;
    person.fav = function () {
        alert(person.name);
    }
    person.fav();
    1.2.字面量方式创建对象: 推荐这种方式创建对象
    var person = {
        name: 'bajie',
        age: 18,
        fav: function () {
            alert(this.name);
        }
    };
    person.fav();
    1.1.和1.2.两种方式创建
        优点: 非常简单
        缺点: 但是有个问题, 当创建多个类似的对象时, 代码会重复多次
        如何解决? 使用"工厂模式"
        
    1.3.工厂模式创建对象: 把重复创建对象的过程写进函数: 函数里面使用1.1.或1.2.的方式
    function createPerson() {
        var person = {
            name: 'bajie',
            age: 18,
            fav: function () {
                alert(this.name);
            }
        };
        return person;
    }
    var p1 = createPerson();
    var p2 = createPerson();
    console.log(p1.name)
    console.log(p2.name)
    console.log(p1 === p2);                                             //测试验证: 两个对象不是一个内存地址
    console.log(p1 instanceof Object);                                  //使用instanceof虽然可以检测出p1是属于object类型,但是不能检测出是属于person
    1.3.方式创建
        优点: 解决了代码冗余的问题
        缺点: 不能判断实例对象到底属于哪个类,只能判断对象是属于Object类型
        如何解决: 使用"自定义的构造函数方式创建对象"
    
    1.4.自定义的构造函数方式创建对象
        1.4.1.普通函数
            创建: function person() { ... }
            调用: person()
        1.4.2.构造函数
            创建: function Person() { ... }                              //创建和普通函数并无不同: 构造函数名第一个字母大写,为了和普通函数区分
            调用: new Person()                                           //区别在于调用: 任意一个函数,包括普通函数,只要是用new来调用,那么就是构造函数
        1.4.3.使用 new Person()时经历的四个阶段
            1).创建一个新的对象
            2).将构造函数的作用域赋给新的对象,使this指向新对象
            3).执行构造函数代码
            4).返回新对象
    function Person(name, age) {                                       //自定义一个构造函数          
        this.name = name;
        this.age = age;
        this.fav = function () {
            alert(this.name);
        };
    }
    var p1 = new Person('八戒', 18);        
    console.log(p1);                                                   //和原生的有一点不同: 原生的方法都在 __proto__里, 而自定义的方法直接在对象里
    p1.fav();
    function Fruit(name, age) {                                        //自定义另一个构造函数               
        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, 而且能区分对象是属于哪个类了
    1.4.方式创建
        优点: 可以区分对象的类型了
        缺点: 现在有个问题: 上面的Person中有一个fav的方法, 当我们进行多次调用的时候, 无疑是内存的消耗
        如何解决: 原型模式创建对象
    
    1.5.原型模式创建对象: 把方法放到他们的父类(原型)中,以后用的时候希望使用这个
        自定义的构造函数Person的父类: 是已经存在的了,是Person.prototype
        只需往父类上设置方法即可: Person.prototype.showName = function(){ ... }
    function Person(name, age) {
        this.name = name;
        this.age = age;
    }
    Person.prototype.showName = function () {                          //把相同的方法设置在父类上
        console.log(this.name);                                        //this是谁? 是Person
    };
    var p1 = new Person('datang', 100);
    var p2 = new Person('bajie', 99);
    p1.showName();
    console.log(p1);                                                   //测试验证: 此时对象的方法就在__proto__里面了, 和原生的构造函数一样了
    console.log(p1.showName === p2.showName);                          //测试验证: 此时p1和p2两个对象共享同一个函数: showName()  
 
四.BOM 浏览器对象模型 (borwser object model)
    1.没有太多操作: 因为浏览器都给我们做好了, 比如 前进 后退 刷新按钮 标题栏上面的叉 滚动 地址栏上的信息
    2.BOM是什么: 操作浏览器部分功能的api
    3.BOM的结构: BOM是包含DOM的.
 
                                BOM
                              window
        DOM-document    history    location    screen    (screen 屏幕)
 
五.BOM中的操作
1.弹出系统对话框,下面这些都是window.xxx的简写,因为它是window的子方法
    alert()    不同浏览器外观不一样
    confirm()  兼容不好
    prompt()   不推荐
 
2.打开窗口,关闭窗口
    window.open(url,target)
        url: 要打开的地址
        target: 新窗口的位置: _self    _blank    _parent
    需求: 3秒后, 打开百度网页,未来做完某些事,直接跳到另外一个网址时用这个
<script>
    setTimeout(function () {
        window.open('http://www.baidu.com/','_self');                  //在自己当前窗口打开百度网址
    },3000);
</script>
    
3.location对象
    3.1.window.location对象中有很多方法和属性
        属性:
            location.hash         :url中的锚点                :"#asdf"
            location.host         :主机(主机名+端口号)        :"www.baidu.com:80"
            location.hostname     :主机名                     :"www.baidu.com"
            location.port         :端口                       :"80"
            location.protocol     :协议                       :https                                                    :是把用户名密码先打包再传输, s = ssl 
            location.href         :url完整地址                :"https://www.baidu.com:80/home/a.jpg?srt=info&asd"
            location.origin       :原始地址                   :"https://www.baidu.com:80"
            location.pathname     :路径名(也叫路由地址)       :"/home/a.jpg"
            location.search       :查询,get时才有的           :"?srt=info&asd"                                       
        方法:
            location.reload()     :就是浏览器上的: 刷新
            location.toString()
    3.2.需求: 跳转网页, 注意: 这个是在当前窗口打开
window.location.href = 'http://www.baidu.com';                     //也可以进行网页的跳转
    
4.navigator对象    (navigator 领航员)
    window.navigator.userAgent: 用户代理: 用的什么系统的浏览器
    window.navigator.platform: 浏览器支持的系统
 
5.history
    history.go(-1): 就是浏览器上的: 后退    :history.back()
    history.go(0):  就是浏览器上的: 刷新    :location.reload()
    history.go(1):  就是浏览器上的: 前进    :history.forward()
    这几个都是全局刷新, 尽量少用; 局部刷新比较好(必用ajax)
 
 
 
 
 

猜你喜欢

转载自www.cnblogs.com/aiaii/p/12232615.html
今日推荐