JS 学习笔记

## 1. tab切换

```js

<style>

        *{

            margin: 0;

            padding:0;

        }

        ul,ol,li{

            list-style: none;

        }

        .cont{

            width: 800px;

            height: 600px;

            border: 5px solid #333;

            margin: 0 auto;

            display: flex;

            flex-direction: column;

        }

        .cont ul{

            width: 100%;

            height: 60px;

            display: flex;

        }

        .cont ul li{

            flex:1;

            font-size: 35px;

            color: #fff;

            border-left: 2px solid blue;

            border-right: 2px solid blue;

            background: hotpink;

            display: flex;

            justify-content: center;

            align-items: center;

        }

        .cont ol{

            flex:1;

            position: relative;

        }

        .cont ol li{

            width: 100%;

            height: 100%;

            font-size: 150px;

            display: flex;

            justify-content: center;

            align-items: center;

            position: absolute;

            top:0;

            left:0;

            background: burlywood;

            display: none;

        }

        /* 按钮标签 哪个标签有这个属性,哪个就显示特殊背景颜色 */

        .cont ul li.active{

            background: skyblue;

            color: black;

        }

        /* 内容标签 哪个标签有这个属性,哪个就显示 */

        .cont ol li.active{

            display: flex;

        }

    </style>

</head>

<body>

    <div class="cont">

        <ul>

            <li class="active">按钮1</li>

            <li>按钮2</li>

            <li>按钮3</li>

        </ul>

        <ol>

            <li class="active">内容1</li>

            <li >内容2</li>

            <li>内容3</li>

        </ol>

    </div>

    <script>

        // 1,核心思想:

        //  利用 按钮标签 与 内容标签 标签数量是一一对应的关系

        //  通过点击 按钮标签 同时操作 对应的内容标签

        // 2,基本步骤:

        //  点击 按钮标签 时

        //    1,给所有的li标签,包括ul,ol中的所有li标签,清除class样式

        //    2,给当前点击的 按钮标签 添加样式

        //    3,给对应的 内容标签 添加样式

        // 方法1: 两个forEach循环

        // 获取标签对象

        var ullis = document.querySelectorAll('ul li');

        var ollis = document.querySelectorAll('ol li');

        // 通过第一层循环,给所有的ul中的li,添加点击事件

        ullis.forEach(function(item1 , key1){

            // item1,是ul中的li标签,key1是这个ul标签,对应的索引下标

            item1.onclick = function(){

                // 1,点击时,给所有的li标签,清除class样式

                // 需要点击时,循环遍历所有的li标签,设定class样式为 ''

                // 可以通过两个循环完成

                // ullis.forEach(function(item2,key2){

                //    item2.className = '';

                // })

                // ollis.forEach(function(item3,key3){

                //    item3.className = '';

                // })

                // 利用ul>li,ol>li索引下标完全下同的原理

                // 利用循环ul时生成的索引下标,从ol中,获取li标签,进行操作

                ullis.forEach(function(item2,key2){

                    item2.className = '';

                    ollis[key2].className = '';

                })

                // 2,给当前的点击标签,添加css样式

                item1.className = 'active';

                // 3,给索引相同的,ol中的li标签,添加样式

                ollis[key1].className = 'active';

            }

        })

```

## 2. tab切换之事件的委托

```js

<style>

        *{

            margin: 0;

            padding:0;

        }

        ul,ol,li{

            list-style: none;

        }

        .cont{

            width: 800px;

            height: 600px;

            border: 5px solid #333;

            margin: 0 auto;

            display: flex;

            flex-direction: column;

        }

        .cont ul{

            width: 100%;

            height: 60px;

            display: flex;

        }

        .cont ul li{

            flex:1;

            font-size: 35px;

            color: #fff;

            border-left: 2px solid blue;

            border-right: 2px solid blue;

            background: hotpink;

            display: flex;

            justify-content: center;

            align-items: center;

        }

        .cont ol{

            flex:1;

            position: relative;

        }

        .cont ol li{

            width: 100%;

            height: 100%;

            font-size: 150px;

            display: flex;

            justify-content: center;

            align-items: center;

            position: absolute;

            top:0;

            left:0;

            background: burlywood;

            display: none;

        }

        /* 按钮标签 哪个标签有这个属性,哪个就显示特殊背景颜色 */

        .cont ul li.active{

            background: skyblue;

            color: black;

        }

        /* 内容标签 哪个标签有这个属性,哪个就显示 */

        .cont ol li.active{

            display: flex;

        }

    </style>

</head>

<body>

    <div class="cont">

        <ul>

            <li name="ulli"  class="active">按钮1</li>

            <li name="ulli" >按钮2</li>

            <li name="ulli" >按钮3</li>

        </ul>

        <ol>

            <li name="olli"  class="active">内容1</li>

            <li name="olli" >内容2</li>

            <li name="olli" >内容3</li>

        </ol>

    </div>

    <script>

        // 1,核心思想:

        //  利用 按钮标签 与 内容标签 标签数量是一一对应的关系

        //  通过点击 按钮标签 同时操作 对应的内容标签

        // 2,基本步骤:

        //  点击 按钮标签 时

        //    1,给所有的li标签,包括ul,ol中的所有li标签,清除class样式

        //    2,给当前点击的 按钮标签 添加样式

        //    3,给对应的 内容标签 添加样式

        // 事件委托

        //    1,给父级div,添加事件委托

        //    2,判断点击 ul中的li时,执行程序

        //          1,给所有的li清除class样式标签

        //          2,给点击的li添加class样式

        //          3,给点击的li对应的ol中的li,添加class样式

        // 区别:

        //    1,获取父级div标签对象,添加点击事件

        //    2,给li添加属性,做区别

        //    3,没有循环:当前标签是 e.target

        //    4,没有循环,无法获取到当前标签的索引下标

        //      必须要在标签中,定义属性来存储索引下标

        //      方法1,直接写在标签中

        //      方法2,通过循环遍历,给ul中的li,setAttribute

        // 总结:事件委托方式,代码更麻烦但是,少了一层循环,执行效率更高

        // 方法2: 事件委托

        // 获取父级div标签对象

        var oDiv = document.querySelector('div');

        // 获取标签对象

        var ullis = document.querySelectorAll('ul li');

        var ollis = document.querySelectorAll('ol li');

        // 给父级div添加点击事件

        // 获取事件对象,我偷懒,不写兼容了

        oDiv.onclick = function(e){

            // 判断,点击的是ul中的li标签

            // e.target,就是触发点击事件的标签对象

            // 如果点击的标签对象,name是ulli,表示点击的是ul中的li标签

            if(e.target.getAttribute('name') === 'ulli'){

                // 1,给所有的li标签,清除样式

                ullis.forEach(function(item,key){

                    item.className = '';

                    ollis[key].className = '';

                    // 给item,也就是ul中的li标签,定义属性

                    item.setAttribute('index',key);

                })

                // 2,给当前ul中的li,添加样式

                // 没有循环 当前的li是 e.target

                e.target.className = 'active';

                // 3,给对应的ol中的li,添加样式

                // 没有forEach循环,没有索引下标,获取标签中定义的属性的属性值

                ollis[e.target.getAttribute('index')].className = 'active';

            }       

        }

    </script>

```

## 3. 拖拽效果边界值

```js

<style>

        * {

            padding: 0;

            margin: 0;

        }

        body {

            height: 5000px;

        }

        .box {

            width: 800px;

            height: 800px;

            border: 10px solid #000;

            margin: 40px auto;

            position: relative;

            background: skyblue;

        }

        .inner {

            width: 100px;

            height: 100px;

            background: pink;

            position: absolute;

            top: 0;

            left: 0;

        }

    </style>

</head>

<body>

    <div class="box">

        <div class="inner"></div>

    </div>

    <script>

        // 1,获取标签对象

        var oBox = document.querySelector('.box');

        var oInner = document.querySelector('.inner');


        // 2,获取相应的数据

        // 获取父级标签的---占位---不包括边框线

        var oBoxWidth = oBox.clientWidth;

        var oBoxHeight = oBox.clientHeight;

        // 获取子级标签的---占位---包括边框线

        var oInnerWidth = oInner.offsetWidth;

        var oInnerHeight = oInner.offsetHeight;

        // 给父级标签添加事件

        oInner.onmousedown = function () {

            document.onmousemove = function (e) {

                // 获取计算,设定子级标签定位的数值

                // page坐标 - 外边距 - 边框线 - 子级宽度的一半

                var x = e.pageX - oBox.offsetLeft - oBox.clientLeft - oInnerWidth / 2;

                var y = e.pageY - oBox.offsetTop - oBox.clientTop - oInnerHeight / 2;

                // 设定极限值

                // 最小值是0

                if (x < 0) {

                    x = 0;

                }

                if (y < 0) {

                    y = 0;

                }

                // 最大值

                // 父级标签占位(没有border) - 移动标签占位(计算border)

                if (x > oBoxWidth - oInnerWidth) {

                    x = oBoxWidth - oInnerWidth;

                }

                if (y > oBoxHeight - oInnerHeight) {

                    y = oBoxHeight - oInnerHeight

                }

                // 将设定好的数值,作为子级标签的定位

                oInner.style.left = x + 'px';

                oInner.style.top = y + 'px';

            }

        }

        window.onmouseup = function () {

            document.onmousemove = null;

        }

    </script>

```

### 思路步骤和问题

1. 事件,到底是绑定给 父级,子级,还是document,还是window

    事件,取消,到底是通过谁取消

  没有固定的写法,看你需要的效果

还是document和window效果相同,没有区别

  鼠标按下

            oInner.onmousedown  鼠标在粉色div上,按下鼠标,并且移动鼠标,才会有效果

            oBox.onmousedown    鼠标在蓝色div上,按下鼠标,并且移动鼠标,才会有效果

            window.onmousedown  鼠标在全屏上,按下鼠标,并且移动鼠标,都会有效果

    鼠标移动

          最好写成 document.onmousemove  /  window.onmousemove

          鼠标可以快速移动,不怕移出粉色div

鼠标抬起

            oInner.onmouseup    鼠标在粉色div上抬起,才会执行,标签不跟随移动

            oBox.onmouseup      鼠标在蓝色div上抬起,才会执行,标签不跟随移动

            window.onmouseup    鼠标在整个页面上抬起,都会执行,标签不跟随移动

2. 闪烁问题

原因: 相对于标签内容的左上角的定位

  会因为鼠标经过不同的标签对象,获取不同的数据

  而且JavaScript执行时,有时还会有bug产生

  offsetX  offsetY  我们是不推荐使用的

  解决: 使用 pageX 和  pageY

  定位: page距离 - 父级标签外边距 - 父级border - 移动标签占位/2(标签中心点和鼠标重合)

极值1: 左  上  都是 0

极值2: 右  下  父级标签占位(不算border) - 移动标签占位(计算border)

## 4. 事件的监听

### 事件的监听

作用:

  如果是普通的事件绑定,相同事件类型,只能绑定一个事件处理函数

如果同一个类型,绑定多个事件处理函数,后绑定的事件会覆盖之前绑定的事件

语法:

标签对象.addEventListener(事件类型 , 事件处理函数)

  第三个参数: true / false(默认值)

  事件的获取方式

冒泡 : 从子级开始,向父级执行

捕获 : 从父级开始,向子级执行

  浏览器默认都是冒泡的执行方式

可以通过 addEventListener 第三个参数来设定获取方式

  默认值 false 是 冒泡方式  true是捕获方式

一般实际项目中,不定义第三个参数,就使用默认方式

低版本IE,只支持冒泡,不支持捕获,不会报错,只会按照冒泡的顺序执行

今后给标签,绑定事件,推荐都使用 事件监听方式

```js

        var oDiv1 = document.querySelectorAll('div')[0];

        var oDiv2 = document.querySelectorAll('div')[1];

        var oDiv3 = document.querySelectorAll('div')[2];

        // 普通事件绑定方式,只会执行最后一个绑定的事件处理函数

        // oDiv1.onclick = function(){

        //    console.log(123)

        // }

        // oDiv1.onclick = function(){

        //    console.log(456)

        // }

        // oDiv1.onclick = function(){

        //    console.log(789)

        // }

        // 事件监听方式

        // oDiv1.addEventListener('click' , function(){

        //    console.log(123);

        // })

        // oDiv1.addEventListener('click' , function(){

        //    console.log(456);

        // })

        // oDiv1.addEventListener('click' , function(){

        //    console.log(789);

        // })

        // 使用事件监听的方式,给父子级关系的标签,绑定事件

        oDiv1.addEventListener('click' , function(){

            console.log(1111)

        } , true)

        oDiv2.addEventListener('click' , function(){

            console.log(2222)

        } , true)

        oDiv3.addEventListener('click' , function(){

            console.log(3333)

        } , true)

```

## 5. 事件监听的兼容方式

兼容方式

普通浏览器

标签对象.addEventListener('事件类型' , 事件处理函数)

事件类型必须是字符串形式,直接写事件类型名称,不能有on

低版本IE浏览器

  标签对象.attachEvent('on事件类型' , 事件处理函数)

```js

<div id="div">123</div>

    <script>

        // 兼容方式

        // 普通浏览器

        // 标签对象.addEventListener('事件类型' , 事件处理函数)

        // 事件类型必须是字符串形式,直接写事件类型名称,不能有on

        // 低版本IE浏览器

        // 标签对象.attachEvent('on事件类型' , 事件处理函数)

        var oDiv = document.getElementById('div');

        // 一般的监听方式

        oDiv.addEventListener('click' , function(){

            console.log(123);

        })

        // 低版本IE浏览器

        oDiv.attachEvent('onclick' , function(){

            console.log(456);

        }) 

        // 使用函数的方式,来做兼容处理

        // 参数1,要绑定的事件对象

        // 参数2,要绑定的事件类型

        // 参数3,要绑定的事件处理函数

        // 如果是特殊的事件类型,需要绑定,可以再单独写判断

        var oDiv = document.getElementById('div');


        myAddEvent(oDiv , 'click' , function(){console.log(123) } );

        function myAddEvent(ele,type,fun){

            if(ele.addEventListener){

                ele.addEventListener(type,fun)

            }else{

                ele.attachEvent( 'on'+type , fun)

            }

        }

```

## 6.事件监听的删除

```js

<div>123</div>

    <script>

        var oDiv = document.querySelector('div');

        var fun4 = function(){

            console.log('abc');

        }

        oDiv.addEventListener('click' , fun1);

        oDiv.addEventListener('click' , fun2);

        oDiv.addEventListener('click' , fun3);

        oDiv.addEventListener('click' , fun4);

        oDiv.addEventListener('click' , function(){console.log('别想删我')});

        // 可以删除

        oDiv.removeEventListener('click' , fun1);

        oDiv.removeEventListener('click' , fun4);

        // 不能删除

        oDiv.removeEventListener('click' , function(){console.log('别想删我')});

        // 注意:

        // 绑定时,必须是函数名称,或者存储函数的变量名称

        //        才能删除

        // 绑定时,如果直接定义函数,是不能删除的

        // 原因: 两个函数,程序相同,但是地址不同

        function fun1(){

            console.log(123);

        }

        function fun2(){

            console.log(456);

        }

        function fun3(){

            console.log(789);

        }

    </script>

```

## 7.轮播图之运动函数1

运动函数

轮播图中,图片的切换,不是瞬间切换完成的

而是以类似于动画/运动的方式,逐步切换完成

将位移/定位效果,分多次,逐步完成

transition 虽然可以实现类似的效果

  但是对于复杂的运动,复杂的设定,是不方便支持的

而且,transition过渡的兼容性,有待提高

通过JavaScript,配合 定时器 来逐步完成 运动效果

```js

<style>

        *{

            margin: 0;

            padding: 0;

        }

        div{

            width: 100px;

            height: 100px;

            background: pink;

            position: fixed;

            top: 100px;

            left: 0px;

        }

    </style>

</head>

<body>

    <button>点击</button>

    <div></div>

<script> 

        var oBtn = document.querySelector('button');

        var oDiv = document.querySelector('div');

        oBtn.addEventListener('click' , function(){

            // 定义的初始值

            var speed = 0;

            // 定时器

            var time = setInterval(function(){

                // 每次初始值,增加一个数值

                speed += 10;

                // 将这个数值定义为定位的数值

                oDiv.style.left = speed + 'px';

                // 当数值达到规定的数值时,清除定时器,终止执行

                // 运动也就终止了

                if(speed == 500){

                    clearInterval(time);

                }               

            } , 30)

        })

    </script>

```

## 8.轮播图之事件函数2

```js

<style>

        * {

            margin: 0;

            padding: 0;

        }

        div {

            width: 100px;

            height: 100px;

            background: pink;

            position: fixed;

            top: 100px;

            left: 200px;

            transition: all 3s;

        }

    </style>

</head>

<body>

    <button>点击</button>

    <div></div>

    <script>

        // 解决第一个问题

        // 封装成一个函数的形式

        // 如果有初始位置,怎么办?

        // 参数1,要运动的标签

        // 参数2,要运动的方向/方式 以及 目标位置

        //      一般,目标位置与运动方式是相关的,定义对象的形式

        //      { 方式 : 位置 }  {left : 500}

        // 获取标签对象

        var oDiv = document.querySelector('div');

        var oBtn = document.querySelector('button');

        // 不愿意写点击事件,直接执行也可以

        // move(oDiv,{left:500});

        // 执行函数

        // 给按钮绑定点击事件

        // 执行的函数,是调用move()函数,并且赋值参数

        // 注意:不能在 addEventListener 参数2的位置上,直接定义move()

        oBtn.addEventListener('click', function(){ move(oDiv,{left:500}) });

        // 直接写move函数,是直接调用move函数,不是绑定move函数

        // oBtn.addEventListener('click', move() );

        function move(ele, obj) {

            // 先通过for...in循环,来调用参数2,获取其中的执行属性和目标位置的数值

            // 目前是有obj中,有一个单元,会循环一次,生成left对应的定时器

            // 如果有obj中,有多个单元,会循环多次,生成每一个属性对应的定时器

            // 这样,每一个属性都有自己对应的定时器,便于控制和观察运动状态

            // type中存储的是,obj对象的键名,也就是left

            for(var type in obj) {

                // 初始位置,需要获取标签原始定位的数值

                // 参数2中,定义的运动属性,是谁,现在对应的就获取谁的初始数值

                // {left:500},就获取left属性对应的初始值


                // window.getComputedStyle 获取标签的css样式的属性值

                // 语法: window.getComputedStyle(标签对象).属性

                // 这里的属性是存储在type自定义变量中的,必须要用[]语法来解析

                var speed = parseInt(window.getComputedStyle(ele)[type]) ;

                // 定时器,每次循环都会生成一个新的定时器

                var time = setInterval(function(){

                    // 初始值,加上数值

                    speed += 20;

                    // 将数值作为定位的数据

                    // 点语法,不能解析变量,必须使用[]语法,解析存储的变量

                    // 设定 标签 css , 语法是 标签对象.style[属性] = 属性值

                    // type是for...in循环中,自定义的变量,用来存储对象的键名

                    // 要使用时,type是变量, 对象.变量,不能解析,只能使用对象[变量]才能解析变量

                    ele.style[type] = speed + 'px';

                    // 当数值,达到目标值的时候,来停止定时器

                    // obj是参数2,{left:500}

                    // 这个500使我们的目标数值

                    // 获取500这个数值,语法是 对象[属性]

                    // 属性存储在变量type中,必须要[]语法才能及解析

                    if (speed == obj[type]) {

                        clearInterval(time);

                    }

                }, 100);

            }

        }

        // 对象的操作

        // 点语法只能直接写属性

        // var obj = {name:'张三'};

        // console.log(obj.name);

        // []语法,可以写属性,要有引号

        //        也可以写变量,能解析变量,不用写引号

        // var str = 'name'

        // console.log(obj[str]);

```

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,039评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,223评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,916评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,009评论 1 291
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,030评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,011评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,934评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,754评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,202评论 1 309
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,433评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,590评论 1 346
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,321评论 5 342
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,917评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,568评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,738评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,583评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,482评论 2 352

推荐阅读更多精彩内容