文章目录
- 判断多个时间区间是否有交叉
- A追逐B(点A向点B靠近)
- 获取随机数区间
- 角度b趋向角度a
- 简单的碰撞检测
- el中是否包含classname
- 判断el上有没有className,有的话就移除,没有的话就添加上
- xpath获取单个element
- xPath获取element集合
- 反向获取xPath路径
- 父节点parent中是否存在子节点 child
- 隐藏element
- 获取一个元素内的所有图像
- 添加一个元素的事件侦听器
- 移除一个元素的事件侦听器
- 在给定元素上触发特定事件,且可选传递自定义数据
- 确认指定元素是否在视口可见
- 获取当前页面的滚动位置
- 平滑滚动到页面顶部
- 平滑的滚动到指定位置
- requestAnimationFrame一定时间内累加累减
- 获取浏览器的 URL
- 创建一个包含当前 URL 参数的对象
- 对传递的 URL 进行 GET 请求
- 对传递的 URL 进行 POST 请求
- 分辨设备是移动设备还是桌面设备
- 获取两个日期之间的天数间隔
- 将一组表单元素编码为一个对象
- 从对象中检索给定选择器指示的一组属性
- 在等待一定时间后调用提供的函数(单位毫秒)
- 获得给定毫秒数的可读格式
- 为指定选择器创建具有指定范围、步长和持续时间的计时器
- 将一个字符串复制到剪贴板
- 确定页面的浏览器选项卡是否处于前台活跃状态
- 当其选项卡的内容变得可见或被隐藏
- 数组里面对象去重
- 将tree深层嵌套结构的数据,重新组织或者拉平
- 拼接树目录结构,添加层级索引
- 根据子元素的guid获取所有父级的guid
- 根据id获取当前架构信息以及下级信息
- get set
- http-server搭建本地服务器
- 编辑serialize()
- css小箭头
- css滤镜,将页面设置成黑白色
- 获取ie浏览器版本
- 判断当前环境(PC/mobile/微信/企业微信/微信mobile/微信pc/企业微信mobile/企业微信pc)
- 无刷新替换浏览器地址栏参数
- 浏览器打开发送短信界面/打开拨打电话界面
- 替换Html
- vue slide动画
- 三角函数( Math.sin/Math.cos)
- Math.atan2(y2-y1,x2-x1)
- dom跟随鼠标移动,每次四舍五入移动25个像素
- 获取随机颜色
- 获取元素某一事件上绑定的所有Listener
- 给字符串中的某一段字符添加样式,包头不包尾
- localstorage.setItem设置监听事件
- 数字生成数字数组,对象转数组
- 滑动过程中,模拟惯性
- 已知两个点求其三等分点
- 已知两个点,两点中心点到(0,0,0)的中心点
- 非法调试
- 外部使用js获取/更改vue3实例中的变量以及组件中的变量
- 文本框输入格式化手机号码或银行卡号
判断多个时间区间是否有交叉
// 基于moment
function iscover(dates){
for (var i = 0; i < dates.length; i++) {
for (var j = 0; j < dates.length; j++) {
if (i != j) {
if (
moment(dates[j][0]).isBetween(dates[i][0], dates[i][1]) ||
moment(dates[j][0]).isSame(dates[i][0]) ||
moment(dates[j][0]).isSame(dates[i][1]) ||
moment(dates[j][1]).isBetween(dates[i][0], dates[i][1]) ||
moment(dates[j][1]).isSame(dates[i][0]) ||
moment(dates[j][1]).isSame(dates[i][1])
) {
return { i:i, j:j };
}
}
}
}
return true;
}
var dateArr = [
['2021-06-03','2021-06-05'],
['2021-06-06','2021-06-08'],
['2021-06-04','2021-06-05']
]
var c = iscover(dateArr)
if(c!==true){
console.log(`${c.i}和${c.j}交叉哦!`); // 0和2交叉哦!
}
A追逐B(点A向点B靠近)
// aim趋向cur,一般用来做鼠标跟随.
function lerpDistance(aim, cur, ratio) {
var delta = cur - aim;
return aim + delta * ratio;
}
document.addEventListener('mousemove',mouseMove)
var x = 350,y = 350;
function mouseMove(e) {
if (e.offsetX || e.layerX) {
var px = e.offsetX == undefined ? e.layerX : e.offsetX;
var py = e.offsetY == undefined ? e.layerY : e.offsetY;
if(px>=0 && px<=700&& py>=0 && py<=700) {
x = lerpDistance(x, px, 0.3);
y = lerpDistance(y, py, 0.3);
}
}
}
获取随机数区间
function rangeRandom (m,n){
return Math.floor(Math.random()*(m - n) + n);
}
// 获取100-600中间的随机数
console.log(rangeRandom(100, 600))
角度b趋向角度a
function lerpAngle(a, b, t) {
var d = b - a;
if (d > Math.PI) d = d - 2 * Math.PI;
if (d < -Math.PI) d = d + 2 * Math.PI;
return a + d * t;
}
document.addEventListener('mousemove',mouseMove)
var x = 350,y = 350,angle = 0;
function mouseMove(e) {
if(e.layerX>=0 && e.layerX<=700&& e.layerY>=0 && e.layerY<=700) {
var _angle = Math.atan2(y-e.layerY ,x-e.layerX); // 计算(x,y)点到鼠标当前的点的角度
angle = lerpAngle( _angle, angle , .3); // angle向_angle靠拢
rotate(angle); // 旋转这个角
}
}
简单的碰撞检测
// 点(x1,y2)和点(x2,y2)之间的距离的平方
function calLength(x1, y1, x2, y2) {
return Math.pow(x1 - x2, 2) + Math.pow(y1 - y2, 2);
}
// 以点(1,1)为中心画了个圆圈,半径为2,以点(5,6)为中心画了个圆圈,半径为3
var len = calLength(1, 1, 5, 6);
if(len <= (2+3) * (2+3)){ console.log('碰撞到一起啦!') }
el中是否包含classname
const hasClass = (el: Element, className: string) => el.classList.contains(className);
判断el上有没有className,有的话就移除,没有的话就添加上
const toggleClass = (el: Element, className: string) => el.classList.toggle(className);
xpath获取单个element
const getElementByPath = (path: string) => return document.evaluate(path, document).iterateNext();
xPath获取element集合
const getElementsByPath = (path: string) => {
const result = document.evaluate(path, document, null, XPathResult.ANY_TYPE, null);
const ret = [];
let nodes = result.iterateNext();
if (nodes) {
ret.push(nodes)
}
while (nodes) {
nodes = result.iterateNext();
if (nodes) {
ret.push(nodes)
}
}
return ret;
}
反向获取xPath路径
function readXPath(element) {
if (element.id !== "") {
return '//*[@id="' + element.id + '"]';
}
if (element == document.body) {
return "/html/" + element.tagName.toLowerCase();
}
let x = 1, siblings = element.parentNode.childNodes; //同级的子元素
for (let i = 0, l = siblings.length; i < l; i++) {
const sibling = siblings[i];
if (sibling == element) {
if (element.parentNode) {
return readXPath(element.parentNode) + "/" + element.tagName.toLowerCase() + "[" + x + "]"
}
} else if ( sibling.nodeType == 1 && sibling.tagName == element.tagName ) {
x++;
}
}
}
父节点parent中是否存在子节点 child
const inNode = (child: Element, parent: Element) => parent !== child && parent.contains(child);
隐藏element
const hideEl = (...el) => [...el].forEach(e => (e.style.display = 'none'));
hideEl(document.querySelectorAll('span'));
获取一个元素内的所有图像
const getImages = (el, includeDuplicates = false) => {
const images = [...el.getElementsByTagName('img')].map(img => img.getAttribute('src'));
return includeDuplicates ? images : [...new Set(images)];
};
getImages(document, true); // ['image1.jpg', 'image2.png', 'image1.png', '...']
getImages(document, false); // ['image1.jpg', 'image2.png', '...']
添加一个元素的事件侦听器
const addEvent = (el, eventType, fn) => el.addEventListener(eventType, fn)
移除一个元素的事件侦听器
const removeEvent = (el, evt, fn, opts = false) => el.removeEventListener(evt, fn, opts);
const fn = () => console.log('!');
addEvent(document.getElementById('box'), 'left', fn)
removeEvent(document.getElementById('box'), 'left', fn);
在给定元素上触发特定事件,且可选传递自定义数据
const triggerEvent = (el, eventType, detail) => el.dispatchEvent(new CustomEvent(eventType, { detail }));
//document.getElementById('box').addEventListener('left', (e) => {});
triggerEvent(document.getElementById('box'), 'left');
triggerEvent(document.getElementById('box'), 'left', { arg: 'hehe' });
确认指定元素是否在视口可见
const elementIsVisibleInViewport = (el, partiallyVisible = false) => {
const { top, left, bottom, right } = el.getBoundingClientRect();
const { innerHeight, innerWidth } = window;
return partiallyVisible
? ((top > 0 && top < innerHeight) || (bottom > 0 && bottom < innerHeight)) &&
((left > 0 && left < innerWidth) || (right > 0 && right < innerWidth))
: top >= 0 && left >= 0 && bottom <= innerHeight && right <= innerWidth;
};
elementIsVisibleInViewport(el); // (不完全可见)
elementIsVisibleInViewport(el, true); // (部分可见)
获取当前页面的滚动位置
const getScroll = (el = window) => ({
x: el.pageXOffset !== undefined ? el.pageXOffset : el.scrollLeft,
y: el.pageYOffset !== undefined ? el.pageYOffset : el.scrollTop
});
平滑滚动到页面顶部
const animateScrollToTop = () => {
const c = document.documentElement.scrollTop || document.body.scrollTop;
if (c > 0) {
window.requestAnimationFrame(animateScrollToTop);
window.scrollTo(0, c - c / 8);
}
};
平滑的滚动到指定位置
调用:
// 滚动Y方向滚动条高度到5000,1000毫秒滚动,浏览器滚动
scrollToDistance(document.documentElement && document.documentElement.scrollLeft,5000,1000,null);
// 滚动X方向滚动条高度到0,1000毫秒滚动,el内滚动
scrollToDistance(0,document.documentElement && document.documentElement.scrollTop,1000,document.querySelector(".el"));
// X,Y同时滚动,1000毫秒滚动,浏览器滚动
scrollToDistance(300,800,1000,null)
function scrollToDistance(toXDistance, toYDistance,duration, el) {
const start = performance.now();
let disX = toXDistance - Number(document.documentElement && document.documentElement.scrollLeft);
let disY = toYDistance - Number(document.documentElement && document.documentElement.scrollTop);
if (el) {
disX = toXDistance - el.scrollLeft;
disY = toYDistance - el.scrollTop;
}
function animateScrollToTop(timestamp) {
const elapsed = timestamp - start;
const progress = elapsed / duration;
const dsX = Math.abs(disX) > 0 ? disX - disX*progress : 0;
const dsY = Math.abs(disY) > 0 ? disY - disY*progress :0;
const retX = toXDistance - dsX;
const retY = toYDistance - dsY;
console.log(progress.toFixed(2),dsY.toFixed(2),retY.toFixed(2))
if (elapsed < duration && (Math.abs(disX) > 0 || Math.abs(dsY) > 0)) {
window.requestAnimationFrame(animateScrollToTop);
if (el) {
el.scrollTop = retY;
el.scrollLeft = retX;
} else {
window.scrollTo(retX, retY);
}
}
}
requestAnimationFrame(animateScrollToTop);
}
requestAnimationFrame一定时间内累加累减
rotateFn(0.1,10,100) // 从0.1到19,100毫秒内计数完
function rotateFn(current,target,duration) {
const start = performance.now();
current = current || 0;
let type = target>current?1:0
function update(timestamp) {
const elapsed = timestamp - start;
const progress = elapsed / duration;
if(type==1){
current += (Math.abs(target - current) * progress);
}
if(type==0){
current -= (Math.abs(target - current) * progress);
}
// 当当前值小于目标值时,继续更新
if (elapsed < duration &&( (current < target && type==1) || (current > target&& type==0))) {
requestAnimationFrame(update);
}
// 打印当前值
console.log(current);
}
// 开始更新
requestAnimationFrame(update);
}
获取浏览器的 URL
#### 获取浏览器的 URL
```js
window.location.href; // 'https://baidu.com'
创建一个包含当前 URL 参数的对象
const getURLParameters = url =>
(url.match(/([^?=&]+)(=([^&]*))/g) || []).reduce(
(a, v) => ((a[v.slice(0, v.indexOf('='))] = v.slice(v.indexOf('=') + 1)), a),
{}
);
getURLParameters('http://fanjiaxing.com/home?a=age&s=sex'); // {a: 'age', s: 'sex'}
getURLParameters('baidu.com'); // {}
对传递的 URL 进行 GET 请求
const httpGet = (url, callback, err = console.error) => {
const request = new XMLHttpRequest();
request.open('GET', url, true);
request.onload = () => callback(request.responseText);
request.onerror = () => err(request);
request.send();
};
httpGet(
'https://jsonplaceholder.typicode.com/posts/1',
console.log
);
// Logs: {"userId": 1, "id": 1, "title": "sample title", "body": "my text"}
对传递的 URL 进行 POST 请求
const httpPost = (url, data, callback, err = console.error) => {
const request = new XMLHttpRequest();
request.open('POST', url, true);
request.setRequestHeader('Content-type', 'application/json; charset=utf-8');
request.onload = () => callback(request.responseText);
request.onerror = () => err(request);
request.send(data);
};
const newPost = {
userId: 1,
id: 1337,
title: 'Foo',
body: 'bar bar bar'
};
const data = JSON.stringify(newPost);
httpPost(
'https://jsonplaceholder.typicode.com/posts',
data,
console.log
);
// Logs: {"userId": 1, "id": 1337, "title": "Foo", "body": "bar bar bar"}
分辨设备是移动设备还是桌面设备
const detectDeviceType = () =>
/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)
? 'Mobile'
: 'Desktop';
detectDeviceType(); // "Mobile" or "Desktop"
获取两个日期之间的天数间隔
const getDaysDiffBetweenDates = (dateInitial, dateFinal) =>
(dateFinal - dateInitial) / (1000 * 3600 * 24);
getDaysDiffBetweenDates(new Date('2017-12-13'), new Date('2017-12-22')); // 9
将一组表单元素编码为一个对象
const formToObject = form =>
Array.from(new FormData(form)).reduce(
(acc, [key, value]) => ({
...acc,
[key]: value
}),
{}
);
formToObject(document.querySelector('#form')); // { email: 'test@email.com', name: 'Test Name' }
从对象中检索给定选择器指示的一组属性
const get = (from, ...selectors) =>
[...selectors].map(s =>
s
.replace(/\[([^\[\]]*)\]/g, '.$1.')
.split('.')
.filter(t => t !== '')
.reduce((prev, cur) => prev && prev[cur], from)
);
const obj = { selector: { to: { val: 'val to select' } }, target: [1, 2, { a: 'test' }] };
get(obj, 'selector.to.val', 'target[0]', 'target[2].a'); // ['val to select', 1, 'test']
在等待一定时间后调用提供的函数(单位毫秒)
const delay = (fn, wait, ...args) => setTimeout(fn, wait, ...args);
delay(
function(text) {
console.log(text);
},
1000,
'later'
);
// 一秒后记录 'later' 。
获得给定毫秒数的可读格式
const formatDuration = ms => {
if (ms < 0) ms = -ms;
const time = {
day: Math.floor(ms / 86400000),
hour: Math.floor(ms / 3600000) % 24,
minute: Math.floor(ms / 60000) % 60,
second: Math.floor(ms / 1000) % 60,
millisecond: Math.floor(ms) % 1000
};
return Object.entries(time)
.filter(val => val[1] !== 0)
.map(([key, val]) => `${val} ${key}${val !== 1 ? 's' : ''}`)
.join(', ');
};
formatDuration(1001); // '1 second, 1 millisecond'
formatDuration(34325055574); // '397 days, 6 hours, 44 minutes, 15 seconds, 574 milliseconds'
为指定选择器创建具有指定范围、步长和持续时间的计时器
const counter = (selector, start, end, step = 1, duration = 2000) => {
let current = start,
_step = (end - start) * step < 0 ? -step : step,
timer = setInterval(() => {
current += _step;
document.querySelector(selector).innerHTML = current;
if (current >= end) document.querySelector(selector).innerHTML = end;
if (current >= end) clearInterval(timer);
}, Math.abs(Math.floor(duration / (end - start))));
return timer;
};
counter('#my-id', 1, 1000, 5, 2000); // 为 id="my-id" 的元素创建一个两秒的计时器
将一个字符串复制到剪贴板
const copyToClipboard = str => {
const el = document.createElement('textarea');
el.value = str;
el.setAttribute('readonly', '');
el.style.position = 'absolute';
el.style.left = '-9999px';
document.body.appendChild(el);
const selected =
document.getSelection().rangeCount > 0 ? document.getSelection().getRangeAt(0) : false;
el.select();
document.execCommand('copy');
document.body.removeChild(el);
if (selected) {
document.getSelection().removeAllRanges();
document.getSelection().addRange(selected);
}
};
copyToClipboard('Lorem ipsum'); // 'Lorem ipsum' copied to clipboard.
确定页面的浏览器选项卡是否处于前台活跃状态
const isBrowserTabFocused = () => !document.hidden;
isBrowserTabFocused(); // true
当其选项卡的内容变得可见或被隐藏
function fn(){
console.log('哎呀,你刚才是不是按了手机物理键退出啦!')
}
window.addEventListener('visibilitychange', fn);
window.removeEventListener('visibilitychange', fn);
数组里面对象去重
let newobj = {};
arr = arr .reduce((preVal, curVal) => {
newobj[curVal.id] ? '' : newobj[curVal.id] = preVal.push(curVal);
return preVal
}, [])
将tree深层嵌套结构的数据,重新组织或者拉平
export class FileNode {
treeChildren: FileNode[];
treeFilename: string;
treeType: any;
[key: string]: any;
}
export class FileFlatNode {
[key: string]: any;
constructor(
public treeExpandable: boolean,
public treeFilename: string,
public treeLevel: number,
public treeType: any
) {
}
}
// 将数据重新组织成一个嵌套的tree
export const buildFileTree = (arr: any[]): FileNode[] => {
return arr.reduce((pre, cur, index, arr) => {
const node = new FileNode();
node.treeFilename = cur.Name;
for (const key in cur) {
if (key !== 'ChildNode') {
node[key] = cur[key];
}
}
if (cur.ChildNode && cur.ChildNode.length) {
node.treeChildren = buildFileTree(cur.ChildNode);
}
return pre.concat(node); // 将node合并到上一个pre数组中
}, []); // pre 的初始值为[]
};
// 将数据重新组织,将子节点取出来放在和父节点平衡的数组里面,拉平成一个不嵌套的tree
export const buildFileFlatTree = (arr: any[], level: number, type: any = null): FileFlatNode[] => {
return arr.reduce((pre, cur, index, arr) => {
const node = new FileFlatNode(!!cur.ChildNode, cur.name, level, type);
node.treeLevel = level;
for (const key in cur) {
if (key !== 'ChildNode') {
node[key] = cur[key];
}
}
let _pre = pre.concat(node);
if (cur.ChildNode && cur.ChildNode.length) {
_pre = _pre.concat(buildFileFlatTree(cur.ChildNode, level + 1, cur.name));
}
return _pre;
}, []);
};
拼接树目录结构,添加层级索引
function deepDeptree(data, pac) {
var str = '<div class="root">'
var pac = pac || 0
for (var i = 0; i < data.length; i++) {
str += '<div sy=' + pac+ ' style="padding-left:' + (pac* 15)+'px">' + data[i].Name + ',' + pac+'</div>';
if (data[i].ChildNode) {
pac= pac + 1;
str += deepDeptree(data[i].ChildNode, pac)
pac--;
}
}
str += '</div>'
return str;
}
var str = deepDeptree(data)
根据子元素的guid获取所有父级的guid
// 逆序,获取当前部门的所有父元素的guid
function getParentsId(arr, PK_Guid) {
var idArr = [];
var fns = function(arr){
for (const item of arr) {
if (item.PK_Guid == PK_Guid) {
idArr.push(item.PK_Guid);
break;
}
if (item.ChildNode) {
if (JSON.stringify(item.ChildNode).match(PK_Guid)) {
idArr.push(item.PK_Guid);
}
fns(item.ChildNode);
}
}
}
fns(arr)
return idArr;
}
// 获取当前部门的所有父元素的Name
function treeFindPath(tree, func, path) {
path = path || [];
if (!tree) return []
for (var data of tree) {
//这里按照你的需求来存放最后返回的内容吧
path.push(data.Name)
if (func(data)) return path
if (data.ChildNode) {
var findChildren = treeFindPath(data.ChildNode, func, path)
if (findChildren.length) return findChildren
}
path.pop()
}
return []
}
treeFindPath(treeArr, function (data) { return data.PK_Guid == '12345678' })
根据id获取当前架构信息以及下级信息
function getOneInfo(data,id){
let obj = null;
function fn(data,id){
for(const item of data){
if(item.PK_Guid === id){
obj = item;
break;
}
if(item.ChildNode&&item.ChildNode.length){
fn(item.ChildNode,id)
}
}
}
fn(data,id);
return obj;
}
get set
function City() {
this._open= false;
}
Object.defineProperty(City.prototype, "open", {
get: function () { return this._open; },
set: function (val) {
this._open = val;
},
enumerable: true,
configurable: true
});
http-server搭建本地服务器
1. npm install http-server -g
2. 进入目录,运行http-server即可
编辑serialize()
// 转成json数据;
var data = getURLParameters(unescape(decodeURI($("#form").serialize()))) || {}
css小箭头
<div id="test"></div>
#test{
position: relative;
}
#test:after {
border: 10px solid transparent;
border-left: 10px solid #f00;
width: 0;
height: 0;
position: absolute;
content: ' '
}
//clip-path: polygon(27% 0, 92% 0, 6% 89%, 0% 100%); 也可以画箭头
css滤镜,将页面设置成黑白色
body{
filter: grayscale(100%);
}
获取ie浏览器版本
// 获取IE版本
export const IEVersion = () => {
// 取得浏览器的userAgent字符串
const userAgent = navigator.userAgent;
// 判断是否为小于IE11的浏览器
const isLessIE11 = userAgent.indexOf('compatible') > -1 && userAgent.indexOf('MSIE') > -1;
// 判断是否为IE的Edge浏览器
const isEdge = userAgent.indexOf('Edge') > -1 && !isLessIE11;
// 判断是否为IE11浏览器
const isIE11 = userAgent.indexOf('Trident') > -1 && userAgent.indexOf('rv:11.0') > -1;
if (isLessIE11) {
const IEReg = new RegExp('MSIE (\\d+\\.\\d+);');
// 正则表达式匹配浏览器的userAgent字符串中MSIE后的数字部分,,这一步不可省略!!!
IEReg.test(userAgent);
// 取正则表达式中第一个小括号里匹配到的值
const IEVersionNum = parseFloat(RegExp['$1']);
if (IEVersionNum === 7) {
// IE7
return 7
} else if (IEVersionNum === 8) {
// IE8
return 8
} else if (IEVersionNum === 9) {
// IE9
return 9
} else if (IEVersionNum === 10) {
// IE10
return 10
} else {
// IE版本<7
return 6
}
} else if (isEdge) {
// edge
return 'edge'
} else if (isIE11) {
// IE11
return 11
} else {
// 不是ie浏览器
return -1
}
}
判断当前环境(PC/mobile/微信/企业微信/微信mobile/微信pc/企业微信mobile/企业微信pc)
function envjudge() {
var isMobile = window.navigator.userAgent.match(/(phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone)/i); // 是否手机端
var isWx = /micromessenger/i.test(navigator.userAgent); // 是否微信
var isComWx = /wxwork/i.test(navigator.userAgent); // 是否企业微信
if (isComWx && isMobile) { //手机端企业微信
return 'com-wx-mobile'
}
else if (isComWx && !isMobile) { //PC端企业微信
return 'com-wx-pc'
}
else if (isWx && isMobile) { // 手机端微信
return 'wx-mobile';
}
else if (isWx && !isMobile) { // PC端微信
return 'wx-pc';
}
else {
return 'other';
}
}
无刷新替换浏览器地址栏参数
pushState:在浏览器history中有记录
replaceState:直接替换掉当前url,不会在history中留下记录
window.history.pushState(data, title, targetURL);
window.history.replaceState(data, title, targetURL);
var href = window.location.href;
href = href + '&city=北京'
if (window.history) {
// 支持History API
window.history.replaceState(null, "", href)
}
浏览器打开发送短信界面/打开拨打电话界面
<a href="sms:15117777777?body=我喜欢你很久了">去发短信</a>
<a href="tel:15117777777">给他打电话</a>
<!-- window.location.href='tel:400-600-9666';-->
替换Html
function replaceHtml(Content, ContentFormat, className) {
var ret = '';
className = className || ''
$.each(ContentFormat,function (index, item) {
var centerstr = Content.substr(item.Start, item.Length)
ret += '<span class="' + className+'" style="font-weight:' + (item.Bold ? 'bold' : '500') + ';color:' + item.Color + '">' + centerstr + '</span>'
});
return ret;
}
var Content = '原行程(杭州-重庆)与申请单行程(杭州-重庆)不一致,需退订原行程后,再重新预订新的行程。'
var format = [
{Start: 0, Length: 4, Color: "#333333", Bold: false},
{Start: 4, Length: 5, Color: "#FF6E00", Bold: false},
{Start: 9, Length: 8, Color: "#333333", Bold: false},
{Start: 17, Length: 5, Color: "#2A86E8", Bold: false},
{Start: 22, Length: 23, Color: "#333333", Bold: false}
]
replaceHtml(Content,format);
vue slide动画
参考 动画
<transition name="detail">
<div class="detail-box" v-show="toggle">
<Component/>
</div>
</transition >
<style>
.detail-box{ overflow: hidden; transition: all .2s;}
.detail-enter-from{height: 0px;}
/* .detail-enter-active{} */
.detail-enter-to {height: 300px; }
.detail-leave-from{height: 300px;}
/* .detail-leave-active{} */
.detail-leave-to{height: 0px;}
</style>
三角函数( Math.sin/Math.cos)
-1到1之间
设置一个点在800 x 600 的盒子里面做曲线运动
var num = 0,speed = 3;
var dom = document.querySelector('.btn-publish')
var timer = setInterval(function(){
if(num >= 5){clearInterval(timer)}
num += 0.5; // 累加的值可随意调节
var disx = 400 - Math.cos(num ) * 400; // 0 - 800之间
var disy = 300 - Math.sin(num * speed) * 300; // 0 - 600之间
dom.style.top = disy +'px'
dom.style.left= disx +'px';
},1000)
弧度 = 角度 * Math.PI / 180
角度 = 弧度 * 180 / Math.PI
for(var angle = 0; angle < 360; angle += 30) // 360°,一圈,每次累加30°
{
var hd = angle * Math.PI / 180; // 由于sin和cos参数是弧度,所以转成弧度
var x = Math.cos(hd) * 300; // 由于cos、sin的值在-1到1之间,所以可以适当增大半径
var y = Math.sin(hd) * 300 + 400; // 默认原心是(0,0),将圆心的y坐标增加400
points.push([x,y])
}
console.log(points); // 所有点坐标都在圆心为(0,400)的弧上
Math.atan2(y2-y1,x2-x1)
返回从原点(0,0)到(x,y)点的线段与x轴正方向之间的平面角度(弧度值),也就是Math.atan2(y,x)
atan2 方法返回一个 -pi 到 pi 之间的数值,表示点 (x, y) 对应的偏移角度。这是一个逆时针角度,以弧度为单位,正X轴和点 (x, y) 与原点连线 之间。注意此函数接受的参数:先传递 y 坐标,然后是 x 坐标。
atan2 接受单独的 x 和 y 参数,而 atan 接受两个参数的比值。
Math.atan2(90, 15) // 1.4056476493802699
dom跟随鼠标移动,每次四舍五入移动25个像素
dom.top= Math.round(moveY/25) *25
dom.left = Math.round(moveX/25) *25
获取随机颜色
0xff6600: 是16进制,显示橘黄色,转成10进制 parseInt(‘ff6600’,16), 结果是 16737792
所以 0xff6600 和16737792是同一个颜色
黑色0x000000 => 0
白色0xffffff => 16777215
16777215 转 0xffffff 也很简单
(16777215 ).toString(16)
// 随机获取一个颜色
var color1 = '#' + (rangeRandom(0, 16777215)).toString(16)
var color2 = '0x' + (rangeRandom(0, 16777215)).toString(16)
function rangeRandom (m,n){
return Math.floor(Math.random()*(m - n) + n);
}
获取元素某一事件上绑定的所有Listener
浏览器console命令行里面输入下面代码
getEventListeners(document.querySelector('.item'))
给字符串中的某一段字符添加样式,包头不包尾
function resetContent(Content, Styles) {
const o = []
let tagIndex = 0;
Styles.forEach((t, index) => {
if (tagIndex !== t.Begin) {
o.push({
Content: Content.substr(tagIndex, t.Begin - tagIndex),
Style: null
})
tagIndex = t.End;
}
o.push({
Content: Content.substr(t.Begin, t.End - t.Begin),
Style: { color: t.Color }
})
if (index === Styles.length - 1) {
if (t.End <= Content.length - 1) {
o.push({
Content: Content.substr(t.End, Content.length - t.End),
Style: null
})
}
}
})
return o;
}
调用:
const con = "服务车型(商务型)不符合差标(经济型、优享型、品质专车)"
const styles = [{Color: "#FF6E00", Begin: 5, End: 8},{Color: "#2A86E8", Begin: 15, End: 23}]
resetContent(con ,styles)
localstorage.setItem设置监听事件
const localStorageSetItem = localStorage.setItem
localStorage.setItem = function (key, val) {
const event = new Event('localStorageSetItem');
event.storageKey = key;
event.storageVal = val;
window.dispatchEvent(event)
localStorageSetItem.apply(this, arguments)
}
window.addEventListener('localStorageSetItem', (e) => {
console.log(e);
})
数字生成数字数组,对象转数组
const count = 5;
const arr = [...Array(count).keys()]
const o = {a:1,b:2,c:3}
Object.keys(o); // ['a', 'b', 'c']
Object.values(o); // [1, 2, 3]
滑动过程中,模拟惯性
let deltaYTime = 0;
let deltaDistance = 0;
let MoveY = 0;
const onTouchStart = (e) => {
deltaYTime = Date.now();
deltaDistance = 0;
}
const onTouchMove = (e) => {
// 滑动的过程中,如果超过200毫秒就重置deltaDistance,
// 最后一次滑动,到手指抬起,时间不超过200毫秒的话,就当做是在快速滑动
MoveY = e.touches[0].clientY
const now = Date.now();
if (now - deltaYTime > 200) {
deltaYTime = now;
deltaDistance = e.touches[0].clientY;
}
}
const onTouchEnd = () => {
// speed 越大,速度越快
const speed = Math.abs(MoveY - deltaDistance) / (Date.now() - deltaYTime)
offsetY = speed > 2 ? dixY * speed : dixY ;
}
已知两个点求其三等分点
设A1(X1,Y1,Z1),A2(X2,Y2,Z2)
三等分点为A3(X3,Y3,Z3),A4(X4,Y4,Z4)
X3=(X2+2X1)/3,Y3=(Y2+2Y1)/3,Z3=(Z2+2Z1)/3
X4=(2X2+X1)/3,Y4=(2Y2+Y1)/3,z4=(2Z2+Z1)/3
const bulge = 1.48; // 中间部分弧往外凸出
const dn = 7; // 8分之一处的点
const dbulge = 1.15; // 两边的点弧往外凸出
const curve = new THREE.CatmullRomCurve3([
// 起始点
new THREE.Vector3(
this.fromPosition.x,
this.fromPosition.y,
this.fromPosition.z
),
// 八分之一出的点
new THREE.Vector3(
((dn * this.fromPosition.x + this.toPosition.x) / (dn + 1)) * dbulge,
((dn * this.fromPosition.y + this.toPosition.y) / (dn + 1)) * dbulge,
((dn * this.fromPosition.z + this.toPosition.z) / (dn + 1)) * dbulge
),
// 中心点
new THREE.Vector3(
((this.fromPosition.x + this.toPosition.x) / 2) * bulge,
((this.fromPosition.y + this.toPosition.y) / 2) * bulge,
((this.fromPosition.z + this.toPosition.z) / 2) * bulge
),
// 八分之七处的点
new THREE.Vector3(
((this.fromPosition.x + dn * this.toPosition.x) / (dn + 1)) * dbulge,
((this.fromPosition.y + dn * this.toPosition.y) / (dn + 1)) * dbulge,
((this.fromPosition.z + dn * this.toPosition.z) / (dn + 1)) * dbulge
),
// 结束点
new THREE.Vector3(
this.toPosition.x,
this.toPosition.y,
this.toPosition.z
),
]);
已知两个点,两点中心点到(0,0,0)的中心点
设A1(X1,Y1,Z1),A2(X2,Y2,Z2)
// 两点之间的中点
const center = {
x: (X1 + X2) / 2,
y: (Y1 + Y2) / 2,
z: (Z1 + Z2) / 2,
};
// (0,0,0)到center之间的中点
const originTocenter = {
x: (0 + center.x) / 2,
y: (0 + center.y) / 2,
z: (0 + center.z) / 2,
};
非法调试
function getLocationHrefParams(name) {
var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)");
var r = window.location.search.substr(1).match(reg);
if (r != null) return unescape(r[2]); return null;
}
(function () {
var notdebugger = !getLocationHrefParams("notdebugger"); //有notdebugger标识可以调试
var origin = location.origin.indexOf("xxx.xxx.com") != -1;// 非正式环境,可以调试
if (notdebugger && origin) {
(() => {
function block() {
if (window.outerHeight - window.innerHeight > 200 || window.outerWidth - window.innerWidth > 200) {
document.body.innerHTML = "检测到非法调试,请关闭调试后重新刷新页面!";
}
setInterval(() => {
(function () {
return false;
}
['constructor']('debugger')
['call']());
}, 50);
}
try {
block();
} catch (err) { }
})();
}
})()
外部使用js获取/更改vue3实例中的变量以及组件中的变量
<div id="app">
username:{{username}}<br/>
<download-com ref="downloadCenterCom"></download-com>
</div>
<script>
const downloadCom = {
name: "download-com",
props: ['pageparams'],
template: `<div>fdfdfd:{{childusername}}</div>`,
setup(props) {
var state = Vue.reactive({childusername: "zs",})
return { ...Vue.toRefs(state),}
}
}
const publicModuleRoot = Vue.createApp({
components: { downloadCom: downloadCom },
setup(props) {
var state = Vue.reactive({username: "asd",})
return { ...Vue.toRefs(state),}
}
})
var publicModuleRootInstance = publicModuleRoot.mount('#app');
console.log(publicModuleRootInstance.username);// 当前实例中的变量username
const downloadCenterComInstance = publicModuleRootInstance.$refs.downloadCenterCom;//获取组件
const childusername = downloadCenterComInstance.childusername;// 当前组件中的变量childusername
console.log(childusername); // 输出:zs
downloadCenterComInstance.childusername = "ls";// 改变变量
console.log(downloadCenterComInstance.childusername); // 输出:ls
</script>
文本框输入格式化手机号码或银行卡号
function numSplitspace(numstr, numarr, maxlength) { //maxlength最大输入个数
console.log(numstr);
let str = numstr.toString();
numarr = numarr || [3, 4]
const spaceleng = str.match(/\s/g)?.length || 0;// 空格的个数
if ((str.replace(/\s/g, "")).length > maxlength) {
str = str.substr(0, maxlength + spaceleng);
}
if (numarr.length == 1) {
const reg = new RegExp(".{1," + numarr[0] + "}", 'g');
return (str.replace(/\s/g, "").match(reg) || []).join(" ");
}
else if (numarr.length == 2) {
str = str.replace(/\s/g, "");
let s1 = str.substr(0, numarr[0])
let s2 = str.substr(numarr[0], str.length);
const reg = new RegExp(".{1," + numarr[1] + "}", 'g');
return [s1, ...(s2.match(reg) || [])].join(" ")
} else {
return str
}
}
// 格式化手机号码numSplitspace("15117999999",[3,4],11) 结果:151 1799 9999
// 格式化银行卡numSplitspace("6214985612552658",[4],16) 结果:6214 9856 1255 2658