JavaScript

462 阅读13分钟

页面加载事件

<script>
window.addEventListener('load', function() {}) // 页面加载完执行
// DOM加载完成,不包括图片、样式等,ie9以上支持
window.addEventListener('DOMContentLoaded', function() {})
</script>

窗口大小事件

window.addEventListener('resize', function() {
    console.log(window.innerWidth)
})

绑定事件

<audio id="aud" controls></audio>
<button onclick="go()">点击</button>

<script>
    function go() {
        console.log(aud);
    }
</script>

xxx.onclick = function (){} // 添加事件
xxx.onclick = null // 移除事件

<xxx onclick=""></xxx>

xxx.addEventListener('click', function(){}, false)
xxx.removeEventListener('click', function(){})
// 默认是false,不阻止冒泡,IE8及以下不支持

xxx.attachEvent('onclick', function(){})
xxx.detachEvent('onclick', function(){})

事件冒泡:由最具体的元素接收,并往上传播
事件捕获:由最不具体的元素接收,并往下传播
DOM事件流:事件捕获 -> 目标阶段 -> 事件冒泡

右键菜单

// 禁止右击菜单
document.addEventListener('contextmenu', function(e) {
    e.preventDefault()
})

禁止选中文字

document.addEventListener('selectstart', function(e) {
    e.preventDefault()
})

鼠标在页面的位置

e.clientX、e.clentY // 鼠标在可视区域的位置(不受滚动条的影响)
e.pageX、e.pageY // 鼠标在文档的位置(受滚动条的影响)

e.screenX、e.screenY // 用得少,鼠标在屏幕的位置

元素偏移量offset

offsetTop、offsetLeft 距离父元素的位置(父元素需要定位,不然一直往上找,直到body)
offsetWidth、offsetHeight 元素自身的大小(border+padding+content)

offsetParent 父元素的DOM节点(带有定位的父元素,不然一直往上找,直到body)

client系列

clientTop、clientLeft 获取自身边框的大小
clientWidth、clientHeight 元素自身的大小(padding+content)

鼠标在元素内的位置

e.pageX - this.offsetLeft
e.pageY - this.offsetTop

键盘事件

keyup // 按下松开后执行
keydown // 按下执行,能识别所有键
keypress // 按下执行,不能识别功能键,比如ctrl、shift、左右箭头键

执行顺序:keydown、keypress、keyup

阻止事件冒泡

function stopBubble(e) {
  if (e.stopPropagation) {
    e.stopPropagation()
  } else {
    window.event.cancelBubble = true;
  }
}

阻止默认事件

node.addEventListener('click', stopDefault)
function stopDefault(e) {
    e.preventDefault();
    window.event.returnValue = false; // ie678
}

node.onclick = function() {
    return false; // 只限于传统方式
}

事件委托

当所有子元素都需要绑定相同的事件的时候,可以把事件绑定在父元素上,这就是事件委托 优点有:

  • 绑定在父元素上只需要绑定一次,节省性能
  • 子元素不需要每个都去绑定同一事件
  • 如果后续又有新的子元素添加,由于事件委托的原因,自动接收到父元素的事件监听

Set、Map

set

set的用法:常用于数组去重,Set里不会有重复值
let set = new Set(['a','b','c'])
set.add('xxx') // 添加
set.clear() // 清空
set.delete('xxx') // 删除
set.size // 查看长度
set.has('xxx') // 查看是否有该属性
set.forEach() // 循环
set.keys()
set.values()
set.entries()

注意:引用类型和NaN(会去重)
// 两个对象都是不同的指针,所以没法去重
const set1 = new Set([1, {name: 'xxx'}, 2, {name: 'xxx'}])
console.log(set1) // Set(4) { 1, { name: 'xxx' }, 2, { name: 'xxx' } }
// 如果是两个对象是同一指针,则能去重
const obj = {name: '林三心'}
const set2 = new Set([1, obj, 2, obj])
console.log(set2) // Set(3) { 1, { name: '林三心' }, 2 }

map

map的用法:Map对比object最大的好处就是,key不受类型限制
const map = new Map() // 定义map
map.set('xxx', 'yyy') // 添加键值对使用 set(key, value)
map.delete('xxx') // // 删除
map.has('xxx') // 查看是否含有某个key
map1.get('xxx') // 获取key的value
map.size // 长度
map.clear()
map.keys()
map.values()
map.entries()
map.forEach()

// 把map转为对象
Object.fromEntries(map)

Object.entries是把对象转成数组,而Object.fromEntries则是把键值对转为对象

includes、indexOf

includes可以检测`NaN`,indexOf不能检测`NaN`
includes内部使用了`Number.isNaN``NaN`进行了匹配

获取DOM元素

document可以换成Dom节点,那么就是搜索范围就是Dom节点的子节点内

方法描述返回类型
document.getElementById()idDom对象
document.getElementsByTagName()标签名数组
document.getElementsByClassName()class(不支持IE8及以下)数组
document.getElementsByName(name)标签的属性name数组
document.querySelector(选择器)选择器获取dom第一个dom对象
document.querySelectorAll(选择器)选择器获取dom数组
document.body获取bodydom对象
document.documentElement获取htmldom对象
document.all获取所有元素dom对象

操作DOM元素有哪些方法

标题描述
createElement创建一个标签节点
createTextNode创建一个文本节点
cloneNode(deep)复制一个节点,连同属性与值都复制,deep为true时,连同后代节点一起复制,不传或者传false,则只复制当前节点
createDocumentFragment创建一个文档碎片节点
appendChild追加子元素
removeChild删除子元素
insertBefore(newN,oldN)将元素插入前面
replaceChild(newN,oldN)替换子元素
getAttribute获取节点的属性
dataset获取节点的自定义(data-)属性(兼容性没有上面的好)
createAttribute创建属性
setAttribute设置节点属性
romoveAttribute删除节点属性
element.attributes将属性生成类数组对象
firstElementChild获取第一个子元素节点(不支持IE8及以下浏览器)
lastElementChild获取最后一个子元素节点(不支持IE8及以下浏览器)
firstChild获取第一个子节点
lastChild获取最后一个子节点
childNodes获取子节点(包括文本节点,IE8及以下没有包括文本节点)
children获取子元素节点(获取子节点,推荐使用)
parentNode获取父节点
parentElement获取父元素节点
previousSibling获取当前节点的前一个节点
nextSibling获取当前节点的后一个节点
previousElementSibling获取当前节点的前一个元素节点(不支持IE8及以下浏览器)
nextElementSibling获取当前节点的后一个元素节点(不支持IE8及以下浏览器)
currentStyle.width获取样式(只有IE支持)
getComputedStyle(node, null).width获取样式(不支持IE8及以下浏览器)
style.width设置样式
className设置类名
className+添加类名

nodeType

元素节点:1 属性节点:2 文本节点:3 注释节点:8

轮播图

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link rel="stylesheet" href="//at.alicdn.com/t/font_3352572_lggtl00ced8.css" />
    <title>Document</title>
    <style>
        * {
            margin: 0;
            padding: 0;
        }
        
        #parent {
            position: relative;
            width: 800px;
            height: 300px;
            overflow: hidden;
            margin: 20px auto;
        }
        
        ul {
            list-style: none;
            display: flex;
            padding: 0;
            position: absolute;
            box-sizing: border-box;
        }
        
        ul>li {
            width: 800px;
            height: 300px;
        }
        
        ul>li>img {
            width: 100%;
            height: 100%;
        }
        
        ol {
            list-style: none;
            display: flex;
            position: absolute;
            bottom: 10px;
            left: 50%;
            padding: 0;
            transform: translate(-50%);
        }
        
        ol>li {
            border: 1px solid pink;
            width: 14px;
            height: 14px;
            border-radius: 50%;
            margin: 2px;
            cursor: pointer;
        }
        
        .bgdc {
            background-color: pink;
        }
        
        #left,
        #right {
            display: none;
            position: absolute;
            top: 50%;
            z-index: 10;
            font-size: 30px;
            transform: translate(0, -50%);
            cursor: pointer;
            color: green;
        }
        
        #left {
            left: 10px;
        }
        
        #right {
            right: 10px;
        }
        
        #animation {
            position: relative;
            width: 200px;
            height: 200px;
            border: 1px solid pink;
        }
    </style>
</head>

<body>
    <div id="parent">
        <ul id="ul">
            <li>
                <img src="https://img2.baidu.com/it/u=2579945444,3600776594&fm=253&fmt=auto&app=138&f=JPG?w=1000&h=450" />
            </li>
            <li>
                <img src="https://img1.baidu.com/it/u=1646921750,2843986497&fm=253&fmt=auto&app=138&f=JPEG?w=658&h=188" />
            </li>
            <li>
                <img src="https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg.zcool.cn%2Fcommunity%2F014a4055e6bc4032f875a13257daa2.jpg&refer=http%3A%2F%2Fimg.zcool.cn&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1653294775&t=1af8964bd76099aadad8a31f8d3b1855"
                />
            </li>
            <li>
                <img src="https://img0.baidu.com/it/u=3116932885,1264952736&fm=253&fmt=auto&app=138&f=JPEG?w=1846&h=500" />
            </li>
            <li>
                <img src="https://img0.baidu.com/it/u=2527001186,1884851821&fm=253&fmt=auto&app=138&f=JPG?w=1295&h=500" />
            </li>
        </ul>
        <ol id="ol"></ol>
        <div id="left" class="iconfont icon-left-circle-fill"></div>
        <div id="right" class="iconfont icon-right-circle-fill"></div>
    </div>

    <script>
        window.onload = function() {
            var parent = document.getElementById("parent");
            var ul = document.getElementById("ul");
            var ol = document.getElementById("ol");
            var left = document.getElementById("left");
            var right = document.getElementById("right");
            parent.onmouseenter = function() {
                left.style.display = "block";
                right.style.display = "block";
                clearInterval(timer);
                timer = null;
            };
            parent.onmouseleave = function() {
                left.style.display = "none";
                right.style.display = "none";
                timer = setInterval(() => {
                    right.click();
                }, 2000);
            };
            for (var i = 0; i < ul.children.length; i++) {
                var element = document.createElement("li");
                element.setAttribute("index", i);
                ol.appendChild(element);
                element.onclick = function() {
                    for (var m = 0; m < ol.children.length; m++) {
                        ol.children[m].className = "";
                    }
                    this.className += "bgdc";
                    circle = num = this.getAttribute("index");
                    // ul.style.left = -this.getAttribute("index") * parent.offsetWidth + "px";
                    animationCursom(
                        ul, -this.getAttribute("index") * parent.offsetWidth
                    );
                };
            }
            ol.children[0].className += "bgdc";
            var num = 0;
            var circle = 0;
            ul.appendChild(ul.children[0].cloneNode(true));
            left.onclick = function() {
                if (num === 0) {
                    num = ul.children.length - 1;
                    ul.style.left = -num * parent.offsetWidth + "px";
                }
                num--;
                // ul.style.left = -num * parent.offsetWidth + "px";
                animationCursom(ul, -num * parent.offsetWidth);
                circle--;
                if (circle < 0) {
                    circle = ol.children.length - 1;
                }
                for (var m = 0; m < ol.children.length; m++) {
                    ol.children[m].className = "";
                }
                ol.children[circle].className += "bgdc";
            };
            right.onclick = function() {
                if (num === ul.children.length - 1) {
                    ul.style.left = 0;
                    num = 0;
                }
                num++;
                // ul.style.left = -num * parent.offsetWidth + "px";
                animationCursom(ul, -num * parent.offsetWidth);
                circle++;
                if (circle === ol.children.length) {
                    circle = 0;
                }
                for (var m = 0; m < ol.children.length; m++) {
                    ol.children[m].className = "";
                }
                ol.children[circle].className += "bgdc";
            };
            var timer = setInterval(() => {
                right.click();
            }, 2000);

            function animationCursom(node, target, callback) {
                clearInterval(node.timer);
                node.timer = null;
                node.timer = setInterval(() => {
                    if (node.offsetLeft === target) {
                        clearInterval(node.timer);
                        node.timer = null;
                        callback && callback();
                    }
                    // 缓动动画:(目标位置-现在的位置)/10
                    var step = (target - node.offsetLeft) / 10;
                    step = step > 0 ? Math.ceil(step) : Math.floor(step);
                    node.style.left = node.offsetLeft + step + "px";
                }, 10);
            }
        };
    </script>
</body>

</html>

放大镜

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <style>
        .parent {
            width: 300px;
            height: 300px;
            border: 1px solid gray;
            position: relative;
            cursor: move;
        }
        
        .parent>img {
            width: 100%;
            height: 100%;
            display: block;
        }
        
        .select {
            display: none;
            width: 100px;
            height: 100px;
            /* background-color: rgba(204, 204, 33, 0.5); */
            background-color: yellow;
            opacity: 0.5;
            filter: Alpha(opacity=50);
            position: absolute;
            z-index: 1;
            top: 0;
        }
        
        .show {
            width: 300px;
            height: 300px;
            border: 1px solid gray;
            position: absolute;
            left: 102%;
            top: 0px;
            z-index: 99;
            display: none;
            overflow: hidden;
        }
        
        .show>img {
            position: relative;
            width: auto;
            height: auto;
        }
    </style>
</head>

<body>
    <div id="parent" class="parent">
        <img src="https://img1.baidu.com/it/u=1187162286,25291177&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=662" alt="" />
        <div id="select" class="select"></div>
        <div id="show" class="show">
            <img src="" alt="" />
        </div>
    </div>
    <script>
        window.onload = function() {
            var parent = document.getElementById("parent");
            var select = document.getElementById("select");
            var show = document.getElementById("show");
            parent.onmouseover = function() {
                select.style.display = "block";
                show.style.display = "block";
                show.children[0].src = parent.children[0].src;
            };
            parent.onmouseout = function() {
                select.style.display = "none";
                show.style.display = "none";
            };
            parent.onmousemove = function(event) {
                event = event || window.event;
                var x = event.clientX - this.offsetLeft - select.clientWidth / 2;
                var y = event.clientY - this.offsetTop - select.clientHeight / 2;
                var maxX = this.clientWidth - select.clientWidth;
                var maxY = this.clientHeight - select.clientHeight;
                if (x <= 0) {
                    x = 0;
                } else if (x >= maxX) {
                    x = maxX;
                }
                if (y <= 0) {
                    y = 0;
                } else if (y >= maxY) {
                    y = maxY;
                }
                /**
                 * (遮罩移动距离/遮罩最大移动距离)*放大图片最大移动距离 = 放大图片移动距离
                 */
                select.style.left = x + "px";
                select.style.top = y + "px";
                show.children[0].style.left =
                    (x / maxX) * (show.clientWidth - show.children[0].clientWidth) +
                    "px";
                show.children[0].style.top =
                    (y / maxY) * (show.clientHeight - show.children[0].clientHeight) +
                    "px";
            };
        };
    </script>
</body>

</html>

拖拽功能

var box = document.getElementById("box");
drag(box)
// 封装的方法,只需要传dom节点
function drag(node) {
    node.onmousedown = function (event) {
        event = event || window.event // 兼容ie8及以下
        var x = event.clientX - this.offsetLeft;
        var y = event.clientY - this.offsetTop;
        this.setCapture && this.setCapture(); // 兼容ie8及以下
        document.onmousemove = function (event) {
            event = event || window.event // 兼容ie8及以下
            node.style.left = event.clientX - x + 'px';
            node.style.top = event.clientY - y + 'px';
        }
        document.onmouseup = function () {
            document.onmousemove = null;
            document.onmouseup = null;
            node.releaseCapture && node.releaseCapture() // 兼容ie8及以下
        }
        return false
    };
}

全局作用域、局部作用域、块级作用域、作用域链

<script>
    var str = 'lxh' // 全局变量
    function fun() {
        var num = 25 // 局部变量
    }
    if() {
        let obj = {} // 块级作用域{}
    }
    function lxh() {
        var arr = []
        function hj() {
            console.log(arr) // 通过作用域链获取arr
        }
    }
</script>

创建对象object

let obj1 = {} // 通过字面量创建对象
let obj2 = new Object()

转数据类型

转string字符串

变量.toString()
String(变量) // 强制转换
变量 + '' //隐式转换,常用

转number数字

Number(变量) // 强制转换
parseInt(变量) // 转为整型
parseFloat(变量) // 转为浮点类型
变量 - 0 (隐式转换-*/,常用)

转为boolean布尔

Boolean()
false''0NANnullundefined

判断数据类型

typeof

用法:typeof obj 或 typeof(obj)
返回的是小写的字符串类型
用于判断原始类型比较方便
原始类型检查类型
Stringstring
Numbernumber
Booleanboolean
undefinedundefined
nullobject
Arrayobject
Objectobject
Functionfunction
BigIntbigint
Symbolsymbol

instanceof

用法:str instanceof String
返回一个布尔值
只能判断对象的具体类型,不能判断原始类型
通过检查对象的原型链上是否有类型的原型

constructor

用法:fun.constructor === Function
返回一个布尔值
是原型prototype上的一个属性
nullundefined没有constructor,所以这种方法不能判断
constructor在类继承的时候会出错

Object.prototype.toString.call()

这个方式最靠谱

Object.prototype.toString.call('') ;   // [object String]
Object.prototype.toString.call(1) ;    // [object Number]
Object.prototype.toString.call(true) ; // [object Boolean]
Object.prototype.toString.call(Symbol()); //[object Symbol]
Object.prototype.toString.call(undefined) ; // [object Undefined]
Object.prototype.toString.call(null) ; // [object Null]
Object.prototype.toString.call(new Function()) ; // [object Function]
Object.prototype.toString.call(new Date()) ; // [object Date]
Object.prototype.toString.call([]) ; // [object Array]
Object.prototype.toString.call(new RegExp()) ; // [object RegExp]
Object.prototype.toString.call(new Error()) ; // [object Error]
Object.prototype.toString.call(document) ; // [object HTMLDocument]
Object.prototype.toString.call(window) ; //[object global] window 是全局对象 global 的引用

浅拷贝、深拷贝

深拷贝和浅拷贝是只针对Object和Array这样的引用数据类型。 浅拷贝是内存指向同一地址。深拷贝是内层指向不同地址。

实现浅拷贝

Object.assign()

只有一层是深拷贝,第二层以后就是浅拷贝

let obj = {xxx: {xxx: 'xxx'} }
let objNew = Object.assign({}, obj)

Array.prototype.concat()、Arrar.prototype.slice()

concat、slice不会改变原对象,返回一个新对象

let arr = [1, 2, {xxx: 'xxx' } ]
let arrNew = arr.concat()
let arrNew = arr.slice()

手写

function cloneShallow(obj) {
    if(typeof obj === 'object' && obj !== null) {
        return Array.isArray(obj) ? [...obj] : {...obj}
    } else {
        return obj;
    }
}

实现深拷贝

JSON.parse(JSON.stringify())

缺点:对象里的函数、undefined,实现不了深拷贝

let arr = [1, {xxx: 'xxx' }, function() {}]
let arrNew = JSON.parse(JSON.stringify(arr))

lodash函数库

import _ from 'lodash'
let obj = {
    xxx: 'xxx'
    yyy: {
        zzz: {
            kkk: 'kkk'
        }
    }
}

let objNew = _.cloneDeep(obj)

手写递归

hasOwnProperty() 方法会返回一个布尔值,指示对象自身属性中是否具有指定的属性(也就是,是否有指定的键)。

function deepClone(obj, map = new Map()) {
    if (typeof obj !== "object" || obj === null) return obj;
    if (map.get(obj)) return map.get(obj);
    let result = {};
    if (Object.prototype.toString.call(obj) === "[object Array]") result = [];
    map.set(obj, result);
    for (const key in obj) {
        if (Object.hasOwnProperty.call(obj, key)) {
            result[key] = deepClone(obj[key], map);
        }
    }
    return result;
}

防抖、节流

防抖常用在:搜索框
function debounce(fun, time = 1000) {
    let timer = null;
    return function() {
        timer && clearTimeout(timer);
        timer = setTimeout(() => {
            fun.apply(this, [...arguments]);
            timer = null;
        }, time)
    }
}

节流常用在:按钮点击
function throttle(fun, time = 2000) {
  let timer = null;
  return function () {
      if(timer) return;
      timer = setTimeout(() => {
          fun.apply(this, [...arguments]);
          timer = null;
      }, time)
  };
}

运算符的优先级

image.png

常见的一下判断[]、null、undefined等

undefined === undefined // true
undefined >= undefined // false 隐式转换为NaN >= NaN NaN不等于NaN,所以为false

null === null // true
null >= null // true 隐式转换为0 >= 0 所以为true

Boolean([]) // true
Boolean(![]) // false
[] == [] // false
[] === [] // false
[] == ![] // true
!优先级高于==,[]不是假值,右边为布尔值,false先转数字0
左边为对象,[]调用toString为''''转换为0
最终为0 == 0

0.1 + 0.2 === 0.3 // false
js中小数是浮点数,需转二进制进行运算,有些小数无法用二进制表示,所以只能取近似值,所以造成误差
解决方法:
    先变成整数运算,然后再变回小数
    toFixed() 性能不好,不推荐
    // 0.5.toFixed(1) 为0.5 会四舍五入,括号里是保留小数位数,注意不能处理整数,不然报错

数组

判断是否为数组:Array.isArray(xxx)

✅改变原数组、❌不改变原数组

  • pop 删除数组最后一项,返回被删除项 ✅
  • push 在数组后添加元素,返回数组长度 ✅
  • shift 删除数组第一项,并返回被删除项 ✅
  • unshift 数组开头添加元素,返回新数组长度 ✅
  • splice 截取数组,返回被截取的区间 ✅
  • sort 排序一个数组,返回修改后的数组 ✅
  • reserve 反转一个数组,返回修改后的数组 ✅
  • flat 数组扁平化 ❌
  • concat 连接数组 ❌
  • slice 截取数组,返回被截取的区间 ❌
  • some 数组有符合规则的一项就返回true ❌
  • every 数组每一项都符合规则才返回true ❌
  • reduce 接收上一个return和数组的下一项 ❌
  • map 操作数组每一项并返回一个新数组,不能结束循环 ❌
  • filter 对数组所有项进行判断,返回符合规则的新数组 ❌
  • join 将一个数组所有元素连接成字符串并返回这个字符串 ❌
  • forEach 遍历数组,没有返回值,结束本次循环return,跳出循环体抛出一个错误 ❌
升序 [].sort((a, b) => a-b)
降序 [].sort((a, b) => b-a)
随机 [].sort(() => Math.random - 0.5)

最大值 [].reduce((a, b) => a > b ? a : b)
最小值 [].reduce((a, b) => a < b ? a : b)

navigator

if(navigator.userAgent.match(/(phone | pad|pod| iPhone |iPod| ios | iPad |Android | Mobile |BlackBerry| IEMobile |MQQBrowser|JUC | Fennec |wOSBrowser | BrowserNG |Webos |Symbian | Windows Phone)/i)) {
    window.location.href = ""; //手机
    } else {
    window.location.href = ""; //电脑
}
window.navigator.onLine // 是否有网,包括内网,返回布尔值

window常用API

  • history 操纵浏览器的记录
back() forward() go(-1) length pushState() replaceState()
  • location操作刷新按钮和地址栏
search // 获取参数
href // 获取url、跳转
assign() // 跳转,可以后退
replace() // 跳转,不能后退
reload() // 刷新,相当于f5
reload(true) // 强制刷新,相当于ctrl+f5

滚动条和坐标

e.pageX、e.pageY是页面的坐标
e.pageX - this.offsetLeft、e.pageY - this.offsetTop 在盒子里的坐标
元素被卷去的头部element.scrollTop、页面被卷去的头部window.pageYOffset(IE8及以下不支持)

网页可见区域宽:document.body.clientWidth (不包括边线的宽border)
网页可见区域高:document.body.clientHeight(不包括边线的高border)
网页可见区域宽:document.body.offsetWidth (包括边线的宽border)
网页可见区域高:document.body.offsetHeight(包括边线的高border)
网页正文全文宽:document.body.scrollWidth  
网页正文全文高:document.body.scrollHeight  
网页被卷去的高:document.body.scrollTop  
网页被卷去的左:document.body.scrollLeft 
网页正文部分上:window.screenTop
网页正文部分左:window.screenLeft

屏幕的高:window.screen.height 
屏幕的宽:window.screen.width
屏幕可用工作区高度:window.screen.availHeight(不包括Windows任务栏)
屏幕可用工作区宽度:window.screen.availWidth (不包括Windows任务栏)
浏览器的宽:window.outerWidth (包括导航栏、地址栏等)
浏览器的高:window.outerHeight(包括导航栏、地址栏等)
当前窗口的宽:window.innerWidth (不包括导航栏、地址栏等)
当前窗口的高:window.innerHeight(不包括导航栏、地址栏等)


滚动到具体位置:
document.documentElement.scrollTop = 300; // 不需要加单位
document.documentElement.scrollTo(0, 300); // (水平, 垂直)
document.getElementById("ID").scrollIntoView();
/*
    scrollIntoView(true) ==> {block:"start",inline:"nearest"}
    scrollIntoView(false) ==> {block:"end",inline:"nearest"}
    滚动到具体某元素
    `behavior`:定义动画过渡效果, "auto"或 "smooth(平滑滚动)" 之一。默认为 "auto"。
-   `block`:定义垂直方向的对齐, "start", "center", "end", 或 "nearest"之一。默认为 "start"。
-   `inline`:定义水平方向的对齐, "start", "center", "end", 或 "nearest"之一。默认为 "nearest"。
*/

获取元素距离父元素顶部和左边距离
`offsetTop offsetLeft`元素相对父元素上边、左边的距离
const ID = document.getElementById("id")
ID.parentNode.scrollTop = ID.offsetTop;

最底部:
parent.scrollTop = parent.scrollHeight - parent.clientHeight;

倒计时

function supplement(num) {
  return num.toString().padStart(2, 0);
}

function countDown(overdueTime = "2022-4-24 0:0:0") {
  const time = (+new Date(overdueTime) - +new Date()) / 1000;
  const day = supplement(parseInt(time / 60 / 60 / 24)) + "天";
  const hours = supplement(parseInt((time / 60 / 60) % 24)) + "小时";
  const minutes = supplement(parseInt((time / 60) % 60)) + "分钟";
  const second = supplement(parseInt(time % 60)) + "秒";
  return day + hours + minutes + second;
}

let timer = setInterval(() => {
  const date = countDown();
  console.log(date);
  if (date === "00天00小时00分钟00秒") {
    clearInterval(timer);
    timer = null;
  }
}, 1000);

Math 常用方法

  • Math.max(...arr) 取arr中的最大值
  • Math.min(...arr) 取arr中的最小值
  • Math.ceil(小数) 小数向上取整
  • Math.floor(小数) 小数向下取整
  • Math.round(小数) 小数四舍五入
  • Math.sqrt(num) 对num进行开方
  • Math.pow(num, m) 对num取m次幂
  • Math.random() 取0(包括)到1(不包括)的随机数
Math.round(-222.5)   // -222
Math.round(-222.51)  // -223
Math.round(num * 100) / 100 // 保留两位小数

// 得到一个两数之间的随机整数,包括两个数在内
Math.floor(Math.random()*(max - min + 1)) + min

promise

function fun() {
    return new Promise((resolve, reject) => {
        setTimeout(() => {}, 1000)
    })
}

fun().then(res => {}).catch(err => {}).finally(() => {})

Promise.all([]) 全部成功才会返回成功
Promise.rase([]) 返回最快的成功或者失败
Promise.any([]) 返回最快的成功,全部失败则会报错
Promise.allSettled([]) 返回数组

?.和??

obj && obj.xxx    obj?.xxx
arr && arr[1]     arr?.[1]
fun && fun()      fun?.()

const a = 0 || 'xxx'          // xxx
const b = '' || 'xxx'         // xxx
const c = false || 'xxx'      // xxx
const d = undefined || 'xxx'  // xxx
const e = null || 'xxx'       // xxx

?? 只有nullundefined才算假值
const d = undefined ?? 'xxx'  // xxx
const e = null ?? 'xxx'       // xxx

||= 和 &&=

  • 或等于(||=)   a ||= b 等同于 a || (a = b);
  • 且等于(&&=)   a &&= b 等同于 a && (a = b);

浏览器从输入url地址到看到界面的过程

  1. 通过DNS域名解析
  2. 建立TCP连接(三次握手)
  3. 发送HTTP请求
  4. 服务器处理请求并返回HTTP报文
  5. 关闭TCP连接(四次挥手)
  6. 浏览器解析渲染页面

原型

// es5
原型通过构造函数的prototype属性
通过对象的__proto__
// es6
通过类的prototype

let obj = {
    name: 'lxh',
}
obj.__proto__.age = 25
console.log(obj.age)

let Fun = function(name) {
    this.name = name
}

Fun.prototype.age = 25
let fun = new Fun('lxh')
console.log(fun.age)

class Lxh {
    constructor(name) {
        this.name = name
    }
}

Lxh.prototype.title = 'liaoxianhui'
let lxh = new Lxh('lxh')
console.log(lxh.title)
console.log(lxh.name)

通过id获取数组里的父数据或者当前数据

/**
 * 在数组里通过id获取数据
 * @param {*} arr 数组
 * @param {*} id 唯一标识
 * @param {*} childArr 子数组的名称
 * @param {*} bool 是否返回父数据
 * @returns 返回数据对象
 */
function queryParentElement(arr, id, childArr = 'children', bool = false) {
    let fallback = {}

    arr.some((item) => {
        if (item.id === id) {
            fallback = item
            return true
        } else {
            if (item[childArr].length) {
                fallback = queryParentElement(item[childArr], id, childArr, bool)
            }

            if (Object.keys(fallback).length) {
                bool && (fallback = item)
                return true
            }
        }
    })

    return fallback
}

1到100的和

// 方法1
function fun(num = 100, data = 0, sum = 0) {
  let newData = data;
  let newSum = sum + newData;
  return newData === num ? newSum : fun(num, ++newData, newSum);
}

console.log(fun());

// 方法2
function add(n) {
  if (n == 1) return 1;
  return add(n - 1) + n;
}

console.log(add(100));

获取url参数

const url = window.location.search
const urlSearchParams = new URLSearchParams(url)
const objParams = Object.fromEntries(urlSearchParams.entries())

如果要兼容IE,可以使用`url-search-params-polyfill`这个插件
安装:npm install url-search-params-polyfill --save
需要引入: import 'url-search-params-polyfill'
使用: const params = new URLSearchParams(window.location.search);

new操作符为什么能创建一个实例对象?

分析一下new的整个过程:

  • 创建一个空对象
  • 继承构造函数的原型
  • this指向对象,并调用构造函数
  • 返回对象

实现一下new:

function myNew (fn, ...args) {
    const obj = {}
    obj.__proto__ =  fn.prototype
    fn.apply(obj, args)
    return obj
}

cookies

/**
 * 存储到cookies
 * @param {*} key
 * @param {*} value
 * @param {*} date
 * 1、1d、1D一天
 * 1h、1H一小时
 * 1m、1M一分钟
 * 1s、1S一秒
 */
function setCookie(key, value, date) {
    var expires = new Date();
    date = typeof date === "string" ? date.toLowerCase() : date;
    if (
        typeof date === "number" ||
        (typeof date === "string" && date.includes("d"))
    ) {
        typeof date === "string" ?
            expires.setTime(
                expires.getTime() + date.split("d")[0] * 60 * 60 * 24 * 1000
            ) :
            expires.setTime(expires.getTime() + date * 60 * 60 * 24 * 1000);
    } else if (typeof date === "string" && date.includes("h")) {
        expires.setTime(expires.getTime() + date.split("h")[0] * 60 * 60 * 1000);
    } else if (typeof date === "string" && date.includes("m")) {
        expires.setTime(expires.getTime() + date.split("m")[0] * 60 * 1000);
    } else if (typeof date === "string" && date.includes("s")) {
        expires.setTime(expires.getTime() + date.split("s")[0] * 1000);
    }
    document.cookie =
        key +
        "=" +
        encodeURIComponent(value) +
        (date ? ";expires=" + expires.toGMTString() : "");
}
/**
 * 传key获取到单个cookies、不传获取全部
 * @param {*} key
 * @returns 获取全部和当个没有就返回数组,单个有就返回字符串
 */
function getCookie(key) {
    var arr = [];
    var val = arr;
    document.cookie &&
        document.cookie.split(";").forEach((item) => {
            arr.push([
                item.split("=")[0].trim(),
                decodeURIComponent(item.split("=")[1]),
            ]);
        });
    key &&
        arr.forEach((arrInside) => {
            if (arrInside[0] === key) {
                val = arrInside[1];
            }
        });
    return val;
}
/**
 * 查询key在cookies里是否存在
 * @param {*} key
 * @returns Boolean
 */
function checkCookie(key) {
    var arr = [];
    var flag = false;
    document.cookie &&
        document.cookie.split(";").forEach((item) => {
            arr.push(item.split("=")[0].trim());
        });
    document.cookie &&
        arr.forEach((item) => {
            if (item === key) {
                flag = true;
            }
        });
    return flag;
}
/**
 * 删除单个传key、不传删除全部
 * @param {*} key
 */
function deleteCookie(key) {
    var arr = [];
    document.cookie &&
        document.cookie.split(";").forEach((item) => {
            arr.push(item.split("=")[0].trim());
        });
    !key &&
        document.cookie &&
        arr.forEach((item) => {
            document.cookie = item + "=; expires=Thu, 01 Jan 1970 00:00:00 GMT";
        });
    if (key && document.cookie) {
        document.cookie = key + "=; expires=Thu, 01 Jan 1970 00:00:00 GMT";
    }
}

移动端

var asd = document.getElementById("asd");
        var pageX = 0;
        var pageY = 0;
        var x = 0;
        var y = 0;
        // 触摸时触发
        asd.addEventListener("touchstart", function(e) {
            console.log(e.touches); // 触摸屏幕的手指数量
            console.log(e.targetTouches); // 触摸dom元素的手指数量
            console.log(e.changedTouches); // 手指状态发生的改变,可以从无到有,从有到无
            // 实际开发中触摸元素的用的比较多就是targetTouches
            // 实现拖到元素
            // 获取手指初始坐标 、 初始位置
            pageX = e.targetTouches[0].pageX;
            pageY = e.targetTouches[0].pageY;
            x = this.offsetLeft;
            y = this.offsetTop;
        });
        // 触摸到移动触发
        asd.addEventListener("touchmove", function(e) {
            // 移动改变位置
            this.style.left = x + e.targetTouches[0].pageX - pageX + "px";
            this.style.top = y + e.targetTouches[0].pageY - pageY + "px";
            e.preventDefault(); // 阻止屏幕滚动的默认行为
        });
        // 触摸离开触发
        asd.addEventListener("touchend", (e) => {
            // e.touches、e.targetTouches 就是空的了  e.changedTouches还有
        });

swiper插件

superslide插件

视频插件zy.meida.js

css

html

谢谢