防抖
/*
* debounce:实现函数的防抖(目的是频繁触发中只执行一次)
* @params
* func:需要执行的函数
* wait:检测防抖的间隔频率
* immediate:是否是立即执行(如果为TRUE是控制第一次触发的时候就执行函数,默认FALSE是以最后一次触发为准)
* @return
* 可被调用执行的函数
*/
function debounce(func, wait = 100, immediate = false) {
let timer = null;
return function anonymous(...params) {
let now = immediate && !timer;
clearTimeout(timer);
timer = setTimeout(() => {
timer = null;
// 执行函数:注意保持THIS和参数的完整度
!immediate ? func.call(this, ...params) : null;
}, wait);
now ? func.call(this, ...params) : null;
};
}
节流
/*
* throttle:实现函数的节流(目的是频繁触发中缩减频率)
* @params
* func:需要执行的函数
* wait:自己设定的间隔时间(频率)
* @return
* 可被调用执行的函数
*/
function throttle(func, wait = 100) {
let timer = null,
previous = 0; //记录上一次操作时间
return function anonymous(...params) {
let now = new Date(), //当前操作的时间
remaining = wait - (now - previous);
if (remaining <= 0) {
// 两次间隔时间超过频率:把方法执行即可
clearTimeout(timer);
timer = null;
previous = now;
func.call(this, ...params);
} else if (!timer) {
// 两次间隔时间没有超过频率,说明还没有达到触发标准呢,设置定时器等待即可(还差多久等多久)
timer = setTimeout(() => {
clearTimeout(timer);
timer = null;
previous = new Date();
func.call(this, ...params);
}, remaining);
}
};
}
获取元素距离BODY的偏移值
/*
* 获取元素距离BODY的偏移值
*/
function offset(element) {
let parent = element.offsetParent,
top = element.offsetTop,
left = element.offsetLeft;
while (parent) {
if (!/MSIE 8/.test(navigator.userAgent)) {
left += parent.clientLeft;
top += parent.clientTop;
}
left += parent.offsetLeft;
top += parent.offsetTop;
parent = parent.offsetParent;
}
return {
top,
left
};
}
定时器动画
两套代码实现方式比较
/* setInterval
clearInterval
setTimeout
clearTimeout
弊端
容易出现卡顿 抖动现象
定时器设定的
*/
(function () {
let Box = document.querySelector(".box");
console.log(
"[ Box ]",
Box,
parseFloat(getComputedStyle(Box)["width"]),
getComputedStyle(Box)["left"]
);
let curl = parseFloat(getComputedStyle(Box)["left"]),
timer = null,
minL = 0,
maxL = document.documentElement.clientWidth - Box.offsetWidth,
step = 10,
direction = "right";
function move() {
if (direction === "right") {
curl += step;
if (curl >= maxL) {
curl = maxL;
direction = "left";
}
} else {
curl -= step;
if (curl <= minL) {
curl = minL;
direction = "right";
}
}
Box.style.left = curl + "px";
}
timer = setInterval(move, 16.7);
})();
//
(function () {
let Box = document.querySelector(".box2");
console.log(
"[ Box ]",
Box,
parseFloat(getComputedStyle(Box)["width"]),
getComputedStyle(Box)["left"]
);
let curl = parseFloat(getComputedStyle(Box)["left"]),
timer = null,
minL = 0,
maxL = document.documentElement.clientWidth - Box.offsetWidth,
step = 10,
direction = "right";
function move() {
if (direction === "right") {
curl += step;
if (curl >= maxL) {
curl = maxL;
direction = "left";
}
} else {
curl -= step;
if (curl <= minL) {
curl = minL;
direction = "right";
}
}
Box.style.left = curl + "px";
timer = requestAnimationFrame(move);
// console.log('[ timer ]', timer)
}
// timer = setInterval(move, 17.6);
timer = requestAnimationFrame(move);
})();
js捕获冒泡使用理解
/*
事件的捕获和冒泡机制你了解多少
1. 基本概念
捕获:自顶向下
冒泡:自底向上
2.监听那个阶段的事件?
window.addEventListener('click',()=>{
})
第三个参数 Beallen
默认 false 冒泡阶段 true 的捕获阶段
3.平常那些场景用到啦这个机制?
4.有一个历史页面,上面若干个按钮,每个按钮都有自己的click事件
新的需求:当你给每个访问用户都加一个属性,banned=true,此用户点击点击按钮任何元素都不能响应原来的函数,而是直接alert 提示,你被封禁啦
就是在最顶层绑定一个捕获事件,最先触发,判断用户是否有权限 弹出提示信息
window.addEventListener("click", (e) => {
if (bananed === true) {
e.target.stopPropagation();
}
})
*/
(function () {
let ulo = document.querySelector(".ulist");
ulo.addEventListener("click", function (e) {
const target = e.target;
if (target.tagName.toLowerCase() === "li") {
console.log("[ this ]", this);
const lilist = this.querySelectorAll("li");
const i = Array.prototype.indexOf.call(lilist, target);
alert(`内容为${target.innerHTML},索引为${i}`);
}
});
console.log("[ ulo ]", ulo);
/*
事件委托利用啦事件的冒泡
*/
})();
js发布订阅事件池
let pools = (function () {
let pond = {};
let on = function on(type, cb) {
!pond.hasOwnProperty(type) ? (pond[type] = []) : null;
let arr = pond[type];
// 去重操作
let index = 0;
for (; index < arr.length; index++) {
if (arr[index] == cb) {
return;
}
}
// 然后再添加
arr.push(cb);
};
let off = function off(type, cb) {
let arr = pond[type] || [];
let index = 0;
for (; index < arr.length; index++) {
if (arr[index] == cb) {
// 防止数组塌陷
arr[index] = null;
return;
}
}
};
let emit = function emit(type, ...params) {
let arr = pond[type] || [];
let index = 0;
for (; index < arr.length; index++) {
if (arr[index] == null) {
arr.splice(index, 1);
index--;
continue;
}
arr[index](...params);
}
};
return {
on,
emit,
off,
};
})();
let fn1 = (...params) => console.log("[ params 1]", params);
let fn2 = (...params) => console.log("[ params 2]", params);
pools.on("zhufeng", fn1);
pools.on("zhufeng", fn1);
pools.on("zhufeng", fn2);
pools.off("zhufeng", fn2);
setTimeout(() => {
pools.emit("zhufeng", 1, 2, 3);
}, 300);
对比操作
(function () {
function EventEmitter() {
this._events = Object.create(null);
}
// {'失恋':[]}
EventEmitter.prototype.on = function (eventName, callback) {
// 判断实例是否有此属性
if (!this._events) this._events = Object.create(null);
if (eventName !== "newListener") {
let listeners = this._events["newListener"];
if (listeners) {
// 如果有newLister就触发newListener对应的事件
this.emit("newListener", eventName);
}
}
let stack = this._events[eventName] || [];
stack.push(callback);
this._events[eventName] = stack;
};
EventEmitter.prototype.once = function (eventName, callback) {
// 先绑定 绑定完触发后 去删除掉
const one = (...args) => {
callback(...args); // 原函数 ,原函数执行后 将自己删除掉即可
this.off(eventName, one);
};
one.l = callback;
this.on(eventName, one);
};
// 删除数组中的某一项
EventEmitter.prototype.off = function (eventName, callback) {
if (this._events[eventName]) {
this._events[eventName] = this._events[eventName].filter((item) => {
// 如果绑定的one 和要关闭 的回调一样我也要删除掉这个函数
return item !== callback && item.l !== callback;
});
}
};
EventEmitter.prototype.emit = function (eventName, ...args) {
if (this._events[eventName]) {
this._events[eventName].forEach((fn) => {
fn(...args);
});
}
};
module.exports = EventEmitter;
})();
- 图片的加载速度往往影响着网站整体的用户体验,尤其对于包含大量图片的网站。
- 对图片进行预加载,不失为一个高效的解决方案。如何实现预加载?
- 预加载图片是提高用户体验的一个很好方法。图片预先加载到浏览器中,
访问者便可顺利地在你的网站上冲浪,并享受到极快的加载速度。
这对图片画廊及图片占据很大比例的网站来说十分有利,它保证了图片快速、无缝地发布,也可帮助用户在浏览你网站内容时获得更好的用户体验。
首先将需要加载的图片放置到一个数组中
export default {
data() {
return {
preloadImgs : [
require('图片路径'),
require('图片路径'),
require('图片路径'),
],
num: 0
}
},
computed: {
percent() {
//计算图片加载的百分进度
return parseInt((this.num / this.preloadImgs.length) * 100)
}
},
mounted() {
this.preload()
},
methods: {
preload() {
for (let i = 0; i < this.preloadImgs.length; i++) {
const img = new Image()
img.src = this.preloadImgs[i]
img.onload = (e) => {
this.num++
this.loaded()
}
img.onerror = () => {
this.num++
this.loaded()
}
}
},
loaded() {
if (this.num === this.preloadImgs.length) {
//此时是所有图片加载完成的时候要做事情
}
}
},
事件冒泡捕获api
/*
事件的捕获和冒泡机制你了解多少
1. 基本概念
捕获:自顶向下
冒泡:自底向上
2.监听那个阶段的事件?
window.addEventListener('click',()=>{
})
第三个参数 Beallen
默认 false 冒泡阶段 true 的捕获阶段
3.平常那些场景用到啦这个机制?
4.有一个历史页面,上面若干个按钮,每个按钮都有自己的click事件
新的需求:当你给每个访问用户都加一个属性,banned=true,此用户点击点击按钮任何元素都不能响应原来的函数,而是直接alert 提示,你被封禁啦
就是在最顶层绑定一个捕获事件,最先触发,判断用户是否有权限 弹出提示信息
window.addEventListener("click", (e) => {
if (bananed === true) {
e.target.stopPropagation();
}
})
*/
(function () {
let ulo = document.querySelector(".ulist");
ulo.addEventListener("click", function (e) {
const target = e.target;
if (target.tagName.toLowerCase() === "li") {
console.log("[ this ]", this);
const lilist = this.querySelectorAll("li");
const i = Array.prototype.indexOf.call(lilist, target);
alert(`内容为${target.innerHTML},索引为${i}`);
}
});
console.log("[ ulo ]", ulo);
/*
事件委托利用啦事件的冒泡
*/
})();
Symbol
/* let arr = [1, 2, 3, 4, 5, 6];
arr[Symbol.iterator] = function iterator(params) {
console.log("[ kok ]");
let index = 0,
self = this;
return {
next() {
if (index >= self.length) {
return {
done: true,
value: undefined,
};
}
return {
done: false,
value: self[index++] * 100,
};
},
};
};
for (const item of arr) {
console.log("[ item ]", item);
} */
/* let obj = {
name: "zhufeng",
age: 12,
0: 100,
1: 200,
// [Symbol('AA')]:300
};
obj[Symbol.iterator] = function iterator(params) {
let index = 0,
self = this,
keys = Reflect.ownKeys(self);
return {
next() {
if (index >= keys.length) {
return {
done: true,
value: undefined,
};
}
return {
done: false,
value: self[keys[index++]],
};
},
};
};
for (const iterator of obj) {
console.log("[ iterator ]", iterator);
} */
// 函数前的加*就是生成器函数
// function *generator(params) {
// }
// let intor=generator()
// console.log('[ intor ]', intor)
const fn1 = function () {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(1);
}, 1000);
});
};
const fn2 = function () {
return Promise.resolve(2);
};
const fn3 = (function () {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(3);
}, 3000);
});
})
(async () => {
let obj = {};
obj[Symbol.asyncIterator] = async function* iterator() {
console.log(1);
yield 1;
console.log(2);
yield 2;
console.log(3);
yield 3;
};
for await (let iterator of obj) {
console.log("[ iterator ]", iterator);
}
})();
柯力化
function fn(a, b, c, d) {
console.log("[ ]", a + b + c + d);
return a + b + c + d;
}
function isType(type,val){
return Object.prototype.toString.call(val)===`[object ${type}]`
}
function curring(cb) {
const inner = (...args) => {
return args.length === cb.length ? cb(...args) : (arg) => inner(...args, arg);
};
return inner;
}
let type = curring(isType);
let isString=type('String')
let isNumber=type('Number')
let isArray=type('Array')
let isObject=type('Object')
let isFunction=type('Function')
let isNull=type('Null')
console.log('[ isNumber(122) ]', isNumber(null))
console.log('[ isString(122) ]', isString('122'))
// fn2(1,2, 3, 4);
// fn2(1)(1)(1,2)
// fn2(2)(3)
// fn2(4)(5)
// console.log("[ ]", fn2(1)(2, 3, 4, 5));