提高网站性能, 尽量保证首屏幕的稳定,尽量不用js来设置偏移量
lighthouse 分析工具 seo
防抖
export function debounce(func, wait, immediate) {
let timeout, args, context, timestamp, result
const later = function() {
// 据上一次触发时间间隔
const last = +new Date() - timestamp
// 上次被包装函数被调用时间间隔 last 小于设定时间间隔 wait
if (last < wait && last > 0) {
timeout = setTimeout(later, wait - last)
} else {
timeout = null
// 如果设定为immediate===true,因为开始边界已经调用过了此处无需调用
if (!immediate) {
result = func.apply(context, args)
if (!timeout) context = args = null
}
}
}
return function(...args) {
context = this
timestamp = +new Date()
const callNow = immediate && !timeout
// 如果延时不存在,重新设定延时
if (!timeout) timeout = setTimeout(later, wait)
if (callNow) {
result = func.apply(context, args)
context = args = null
}
return result
}
}
多个window.resize 冲突问题
// 监听窗口改变
window.addEventListener('resize', function() {})
//要加防抖哦!
window.addEventListener('resize', debounce(function() {}, 500))
//监听滚动方法
window.addEventListener("scroll", debounce(function() {}, 200))
只能保留两位小数点 小数点验证
export const clearNum = (value) => {
let _val = value || ''
_val = _val.replace(/[^\d.]/g,"")
_val = _val.replace(/\.{2,}/g,".")
_val = _val.replace(/^\./g,"");
_val = _val.replace(".","$#$").replace(/\./g,"").replace("$#$",".");
_val = _val.replace(/^(\-)*(\d+)\.(\d\d).*$/,'$1$2.$3');
return _val
}
保留两位小数并去掉尾数为0的数字
如果返回的是这种: 0.10, 0.200,0.33 paresFloat可以很好的处理 为0.1, 0.2, 0.33
// 四舍五入var num =2.2354234234;num = num.toFixed(2);console.log('num=', num);
Math.floor() —— 先将小数变整数,然后再保留小数位数
//不四舍五入 var num2 = Math.floor(2.2344234234 * 100) / 100
获取经纬度的距离
export function GetDistance( lat1, lng1, lat2, lng2, number){
if(!lat1 || !lng1 || !lat2 ||!lng2) {
return ''
}
var radLat1 = lat1*Math.PI / 180.0;
var radLat2 = lat2*Math.PI / 180.0;
var a = radLat1 - radLat2;
var b = lng1*Math.PI / 180.0 - lng2*Math.PI / 180.0;
var s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a/2), 2) +
Math.cos(radLat1)*Math.cos(radLat2)*Math.pow(Math.sin(b/2), 2)));
s = s *6378.137 ;// EARTH_RADIUS;
s = Math.round(s * number) / number;
return s + 'km';
}
// 解决精度方案var num5 = 8.54342345;var numStr = num5.toString();var idx = numStr.indexOf('.');var res = Number(numStr.slice(0, idx + 3));console.log('res=',res);
cookie utile
class CookieUtil {
static getItem(sKey) {
return (
unescape(
document.cookie.replace(
new RegExp(
"(?:(?:^|.*;)\\s*" +
escape(sKey).replace(/[-.+*]/g, "\\$&") +
"\\s*\\=\\s*([^;]*).*$)|^.*$"
),
"$1"
)
) || null
);
}
static setItem(sKey, sValue, vEnd, sPath, sDomain, bSecure) {
if (!sKey || /^(?:expires|max-age|path|domain|secure)$/i.test(sKey)) {
return false;
}
var sExpires = "";
if (vEnd) {
switch (vEnd.constructor) {
case Number:
sExpires =
vEnd === Infinity ?
"; expires=Fri, 31 Dec 9999 23:59:59 GMT" :
"; max-age=" + vEnd;
break;
case String:
sExpires = "; expires=" + vEnd;
break;
case Date:
sExpires = "; expires=" + vEnd.toUTCString();
break;
}
}
document.cookie =
escape(sKey) +
"=" +
escape(sValue) +
sExpires +
(sDomain ? "; domain=" + sDomain : "") +
(sPath ? "; path=" + sPath : ";path=/") +
(bSecure ? "; secure" : "");
return true;
}
static removeItem(sKey, sDomain, sPath) {
var exp = new Date();
exp.setTime(exp.getTime() - 1);
var cval = this.getItem(sKey);
if (cval != null) {
document.cookie =
escape(sKey) +
"=" +
cval +
";expires=" +
exp.toUTCString() +
(sDomain ? ";domain=" + sDomain : "") +
(sPath ? ";path=" + sPath : ";path=/");
// console.log(escape(sKey) +
// "=" +
// cval +
// ";expires=" +
// exp.toUTCString() +
// (sDomain ? ";domain=" + sDomain : "") + (sPath ? ";path=" + sPath : ";path=/"));
}
return true;
}
static hasItem(sKey) {
return new RegExp(
"(?:^|;\\s*)" + escape(sKey).replace(/[-.+*]/g, "\\$&") + "\\s*\\="
).test(document.cookie);
}
static keys() {
var aKeys = document.cookie
.replace(/((?:^|\s*;)[^=]+)(?=;|$)|^\s*|\s*(?:=[^;]*)?(?:\1|$)/g, "")
.split(/\s*(?:=[^;]*)?;\s*/);
for (var nIdx = 0; nIdx < aKeys.length; nIdx++) {
aKeys[nIdx] = unescape(aKeys[nIdx]);
}
return aKeys;
}
}
getuuid
function getUUID(len, radix) {
var chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split('')
var uuid = []
var i
radix = radix || chars.length
if (len) {
for (i = 0; i < len; i++) uuid[i] = chars[0 | Math.random() * radix]
} else {
var r
uuid[8] = uuid[13] = uuid[18] = uuid[23] = '-'
uuid[14] = '4'
for (i = 0; i < 36; i++) {
if (!uuid[i]) {
r = 0 | Math.random() * 16
uuid[i] = chars[(i === 19) ? (r & 0x3) | 0x8 : r]
}
}
}
return uuid.join('')
}
matrix(3d)
function getTransformByMatrix(translateString) {
var matrix = translateString.match(/matrix(3d)?\((.+?)\)/);
var is3D = matrix && matrix[1];
if (matrix) {
matrix = matrix[2].split(",");
if (is3D === "3d")
matrix = matrix.slice(12, 15);
else {
matrix.push(0);
matrix = matrix.slice(4, 7);
}
} else {
matrix = [0, 0, 0];
}
var result = {
x: parseFloat(matrix[0]),
y: parseFloat(matrix[1]),
z: parseFloat(matrix[2])
};
return result;
}
代码段
let translates = $('.xxxx').css('transform')
let obj = getTransformByMatrix(translates)
Math.abs()取绝对值
图片加载完成之后获取图片宽高信息 与 img src 与background-image 区别
页面元素内容最关键的一点就是,当css未加载时能看出这是什么
img src 是一个dom对象
网页加载顺序不一样
background-image 会等到dom结构加载完成才开始加载,先加载标签内容,再加载背景图片,不影响网页内容
img src在加载大图时,图片未加载完成,img后的内容都不会显示。影响浏览网页内容。
const teemoimgLoad = (v) => {
return new Promise(resolve => {
const img = new Image()
img.src = v
img.onload = () => resolve({width: img.width || '', height: img.height || ''})
})
}
获取文件
const convertFileToBase64 = (file) =>
new Promise((resolve, reject) => {
const reader = new FileReader();
reader.readAsDataURL(file.rawFile);
reader.onload = () => resolve(reader.result);
reader.onerror = reject;
});
const add = () => {
return Promise.resolve(convertFileToBase64(myFile))
.then((picture64) => ({
src: picture64,
title: `${myFile.title}`,
}))
.then((transformedMyFile) =>
requestHandler(type, resource, {
...params,
data: {
...params.data,
myFile: transformedMyFile,
},
})
);
}
获取url参数
//获取url参数
function getURLparam(key){
var qstring = window.location.search;
if (!qstring) return (!key || key == '*') ? {} : null;
qstring = qstring.replace(/%20/g, ' ');
qstring = qstring.substr(1); // remove ?
var param = qstring.split('&');
var map = new Object();
for (var i = 0, j = param.length; i < j; i++){ var pl=param[i].split('='); map[pl[0]] = pl[1]; }
return (!key || key == '*') ? map : map[key];
};
原型实例 可忽略
// 公共方法 控制弹窗延时展示展示
function changeNewsletterPopup() {
this._newsPopupId = document.querySelector('#id') || ''
this._newsPopupHead= document.querySelector("#id.heading") || ''
this._newsPopupContent= document.querySelector("#id .content") || ''
this.onlineTimes= [
{
title: "title1",
content: "content1",
},
{
title: "title2",
content: "content2",
}
]
}
changeNewsletterPopup.prototype = {
init: function (index, delayTime) { //索引 和延迟时间
if((index + 1) > this.onlineTimes.length) {
return false
}
if(this._newsPopupId) {
if(!delayTime) {
this._newsPopupHead.innerHTML = this.onlineTimes[index].title
return false
} else {
this._newsPopupId.style.visibility = "hidden";
}
if(this._newsPopupHead) {
this._newsPopupHead.innerHTML = this.onlineTimes[index].title
}
if(this._newsPopupContent) {
this._newsPopupContent.innerHTML = this.onlineTimes[index].content
}
let newsPopupTime = setTimeout(()=>{
this._newsPopupId.style.visibility = "visible";
clearTimeout(newsPopupTime)
}, delayTime);
} else {
}
}
}
// 控制弹窗的弹出 定制化
if(pathNameCalculate === "page1") {
const test1 = new changeNewsletterPopup()
changeNewsletterPopupXbike.init(0, 30000)
} else if(pathNameCalculate === "page2") {
const test2 = new changeNewsletterPopup()
changeNewsletterPopupProductsXbike.init(0, 80000)
}
H5 safri返回时无法自动播放视频
<video class="pc-video js-videoPlayer"
x-webkit-airplay="allow" webkit-playsinline="true"
playsinline="true"
autoplay="autoplay"
muted="muted"
loop="loop"
src="https://xxx.mp4?">
</video>
<script type="text/javascript">
$(function() {
$('body').on('click', '.js-slideshow-index', function (e) {
customGaEvent('home-banner-scrool', 'click', 'banner' + $(this).data('number'))
})
})
function playBySeconds () {
console.log('33333')
$('.js-videoPlayer').trigger('play')
}
function hideVedio() {
console.log('hideVedio')
console.log('$', $('.js-videoPlayer'))
$('.js-videoPlayer').trigger('pause')
}
window.addEventListener('pageshow', function() {
console.log('pageshow')
playBySeconds()
});
window.addEventListener('pagehide', function() {
console.log('pagehide')
hideVedio()
});
document.addEventListener('visibilitychange', async () => {
if (document.visibilityState == 'visible') {
console.log("visibilitychange show")
playBySeconds()
} else {
hideVedio()
console.log("visibilitychange hide")
}
})
</script>
动态插入js
this.insertScript = function (src, id) {
const script = document.createElement("script");
script.setAttribute("id", id);
script.setAttribute("src", src);
script.setAttribute("async", "async");
document.body.appendChild(script);
return _this;
};
IOS浏览器导航栏和底部工具栏 100vh正确使用方式: 100vh包括导航栏和底部底部工具栏高度,但对于fixed 属性 100vh就包含导航栏和工具栏的高度, 这个时候只要在body 后面铺一层 fixed div元素,然后获取这个真实高度, 直接放到我们场景动画高度, 完美解决 ios浏览器底部工具栏有时出现有时不会出现的问题
.fixed-animation-ios{
position: fixed;
left: 0;
top: 0;
bottom: 0;
right: 0;
width: 100%;
height: 100vh;
z-index: -100;
}
<div class="fixed-animation-ios">
</div>
var iosMaxheight= ($('.fixed-animation-ios').length > 0)? $('.fixed-animation-ios').innerHeight() : window.innerHeight
彩虹rgba颜色
1、赤色【RGB】 rgba(255,0,0,1) , rgba(255,0,0,0.1)
2、橙色【RGB】 rgba(255,165,0,1) , rgba(255,165,0,0.1)
3、黄色【RGB】 rgba(255,255,0,1) , rgba(255,255,0,0.1)
4、绿色【RGB】 rgba(0,255,0,1) , rgba(0,255,0,1 0.1)
5、青色【RGB】 rgba(0,127,255,1) , rgba(0,127,255,0.1)
6、蓝色【RGB】 rgba(0,0,255,1), rgba(0,0,255,0.1)
7、紫色【RGB】 rgba(139,0,255,1), rgba(139,0,255,0.1)
字符串倒数第二位加上小数点
var price = 109000
price = price.toString()
price = price.slice(0,price.length -2) + "." + price.slice(price.length -2) //1090.00
建立观察者模式
const initBuyButoon = {
deviceId: getPcOrMobile(),
isInit: false,
isUnbrand: false,
init: function () {
this.event()
},
scrollBtn: function ($dom) {
let xbikeAddToCart = document.getElementById('xbike-add-to-cart-main');
let observerBtn = new IntersectionObserver(function(entries){
// 监听元素是否在可视区域内
entries.forEach( function(element, index) {
if (element.isIntersecting ) {
if($dom.css('position') !== 'static') {
$dom.css('position', 'static')
$dom.removeClass('shopify-payment-button_position')
}
} else {
if($dom.css('position') !== 'fixed') {
$dom.css('position', 'fixed')
$dom.addClass('shopify-payment-button_position')
}
}
});
}, {
root: null,
threshold:[0, 1]
});
observerBtn.observe(xbikeAddToCart)
},
event: function () {
let _this = this
{% comment %} if(this.deviceId === 2 || window.innerWidth <= 640) { {% endcomment %}
const targetNode = document.getElementsByClassName('shopify-payment-button')[0];
// 当观察到突变时执行的回调函数
let callback = function(mutationsList) {
mutationsList.forEach(function(item,index){
if (item.type == 'childList') {
if($('.shopify-payment-button').find('.shopify-payment-button__button--branded').length > 0) {
if((_this.deviceId === 2 || window.innerWidth <= 640) && !_this.isInit){
_this.scrollBtn($('.shopify-payment-button').find('.shopify-payment-button__button--branded'))
}
_this.isInit = true
} else if($('.shopify-payment-button').find('.shopify-payment-button__button--unbranded').length > 0) {
if(!_this.isUnbrand) {
customGaEvent( 'buy-it-now-exposure', window.location.pathname, 'shopify-payment-button__button--unbranded')
}
_this.isUnbrand = true
}
}
});
};
// 创建一个链接到回调函数的观察者实例 由于这个元素是三方插入的,需要监听什么时候从页面出现的
const observerDom = new MutationObserver(callback);
// 开始观察已配置突变的目标节点
observerDom.observe(targetNode, { attributes: true, childList: true, subtree: true });
// 停止观察
//observer.disconnect();
{% comment %} } {% endcomment %}
}
}
initBuyButoon.init()
去掉移动端点击后的背景色
-webkit-tap-highlight-color:transparent
点击弹窗之外关闭弹窗
$(document).bind("click",function(e){
if($(e.target).closest(".js-peleton-panel-name").length == 0){
//点击id为menu之外且id不是不是open,则触发
_this.closeFunc()
}
if($(e.target).closest(".js-freebeat-panel-name").length == 0){
//点击id为menu之外且id不是不是open,则触发
_this.closeFunc2('.js-freebeat-panel-name')
}
})
短信分享
分享短信 ios的和安卓不太一样
ios 'sms:&body='+encodeURIComponent(shareText)
安卓 'sms:?body='+encodeURIComponent(encodeURIComponent(shareText))
判断是设备类型
let isIos = !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/);
// 阻止事件冒泡 停止传播
e.stopPropagation()
事件冒泡 从下到上 从子元素到父元素 bottom-> div -> body ->dom
事件捕获 从上到下 从父元素向下捕获 dom->body->div-> button
事件委托 节约性能 li标签的点击委托到 ul上
<ul>
<li></li>
<li></li>
</ul>
stopPropagation:阻止事件的冒泡和捕获。
因为事件可以在各层级的节点中传递, 不管是冒泡还是捕获, 有时我们希望事件在特定节点执行完之后不再传递, 可以使用事件对象的 stopPropagation() 方法。
preventDefault:阻止浏览器默认行为
浏览器的默认行为:对于一些特定的事件,浏览器有它默认的行为。
例如:
点击链接会进行跳转
点击鼠标右键会呼出浏览器右键菜单
填写表单时按回车会自动提交到服务器等
return false; 当你调用它时会做 3 件事:
event.preventDefault() – 它停止浏览器的默认行为。
event.stopPropagation() – 它阻止事件传播(或“冒泡”)DOM。
停止回调执行并立即返回。
监听点击事件的方法 包括 a标签跳转
if (window.innerWidth > 768) {
attachEventsabHreoImage()
}
function eventDelegateCallbackabHeroImage(selector, callback, e) {
const elements = Array.from(document.querySelectorAll(selector));
for (let i = 0, len = elements.length; i < len; i++) {
const el = elements[i];
if ([e.target, e.target.closest(selector)].includes(el)) {
callback.call(el, e);
break;
}
}
}
function registerEventHreoImage(eventName) {
console.log("eventName", eventName)
window._fpEvent = window._fpEvent || [];
window._fpEvent.push(["eventConversion", {value: eventName}]);
}
var lastTimeHeroImage=0
function attachEventsabHreoImage() {
document.addEventListener('click', function (e) {
if (new Date().getTime() - lastTimeHeroImage < 1000) {
return;
}
lastTimeHeroImage = new Date().getTime();
eventDelegateCallbackabHeroImage('.figpii-img-banner .js-public-gtm-btn', function () {
if(this){
registerEventHreoImage('hreo_image_click_explore_bikes')
}
}, e)
}, true)
}
控制频繁操作video播放和暂停
function playVideo (videodom){
if(videodom.length > 0) {
videodom.each(function(index,elemet) {
let _isrc = $(elemet).attr('src')
if(_isrc && elemet.paused) {
let playPromise = elemet.play()
if (playPromise !== undefined) {
playPromise.then(() => {
elemet.play()
}).catch(()=> {
})
}
// elemet.play()
}
})
}
}
function pausedVideo (videodom) {
if(videodom.length > 0) {
videodom.each(function(index, elemet) {
let _isrc= $(elemet).attr('src')
if(_isrc && !elemet.paused) {
elemet.pause()
}
})
}
}
let video_all = $(`.js-homebanner-slid[data-type=video_banner]`)
let _video2 = video_all.find('video')
pausedVideo(_video2)
获取宽度
let content = $("div").width();//只是获取content宽度
let contentWithPadding = $("div").innerWidth();//获取content+padding的宽度
let withoutMargin = $("div"). outerWidth();//获取content+padding+border的宽度
let full = $("div"). outerWidth(true);//获取content+padding+border+margin的宽度