一、从字符串中提取数字
1、利用 parseFloat() 方法提取字符串中的数字。
parseFloat() 方法提取字符串中的数字,有很多的限制。它只能提取开头为数字的字符串中的数字,如果字符串的开头第一个字符为非数字,则会提取失败。
例:
console.log(parseFloat('1234feiniaomy.com')) //1234
console.log(parseFloat('123.4feiniaomy.com')) // 123.4
console.log(parseFloat('feiniaomy.com1234')); // NaN
console.log(parseFloat('m123.5')); //NaN
2、JS 使用正则提取字符串中的数字
例1:
可以利用正则的方法将字符串中非数字的字符给去掉,留下的就是数字。但要注意,如果是要想提取数字中有非整数的部份(带有小数点的数),则无法提取小数点。
var num = '1234feiniaomy.com'.replace(/[^\d]/g, "");
console.log(num); //1234
var num2 = '123.4feiniaomy.com'.replace(/[^\d]/g, "");
console.log(num2); //1234
var num3 = 'feiniaomy.com1234'.replace(/[^\d]/g, "");
console.log(num3); //1234
var num4 = 'm123.5'.replace(/[^\d]/g, "");
console.log(num4); //1235
例2:
通过上面的示例,我们可以修改一下正则表达式,并使用 match 方法来调用它。
var num = '1234feiniaomy.com'.match(/\d+(\.\d+)?/g);
console.log(num); //['1234']
var num2 = '123.4feiniaomy.com'.match(/\d+(\.\d+)?/g);
console.log(num2); //['123.4']
var num3 = 'feiniaomy.com1234'.match(/\d+(\.\d+)?/g);
console.log(num3); //['1234']
var num4 = 'm123.5'.match(/\d+(\.\d+)?/g);
console.log(num4); //['123.5]
var num4 = 'm123.55sd58sdf56sdf85sdf6e8f5sd6f'.match(/\d+(\.\d+)?/g);
console.log(num4); //['123.55', '58', '56', '85', '6', '8', '5', '6']
二、js数组、数组嵌套根据某个字段排序(sort)
1、根据某个字段排序:
var arr = [
{name:'张三',age:15},
{name:'李四',age:18},
{name:'王五',age:28}
];
function compare(property){
return function(a,b){
var value1 = a[property];
var value2 = b[property];
return value1 - value2; //降序只需要 return value2- value1
}
}
console.log(arr.sort(compare('age')))
2、根据某两个字段
var arr = [
{name:'张三',age:15,num:13},
{name:'李四',age:15,num:16},
{name:'王五',age:28,num:18},
{name:'木子李',age:18,num:18}
];
compare (property, p2) {
return function (a, b) {
var value1 = a[property];
var value2 = b[property];
if (value1 != value2) {
return value1 - value2;
} else {
return a[p2] - b[p2];
}
}
}
console.log(arr.sort(compare('age','num')))
2
三、浮点数精度问题
首先在控制台分别打印 0.1 + 0.2, 和 0.1, 会发现如下图:
或者有些面试会问到:
0.1 + 0.2 === 0.3 //false
像这种就是Javascript 数字精度丢失的问题,造成这个问题的原因:
在javascript
语言中,0.1 和 0.2 都是转化成二进制后再进行运算的
// 0.1 + 0.2转化成二进制后再进行运算
0.00011001100110011001100110011001100110011001100110011010 +
0.0011001100110011001100110011001100110011001100110011010 =
0.0100110011001100110011001100110011001100110011001100111
// 转成十进制 0.30000000000000004
解决方案:
- 数据要展示时, 使用
toPrecision
凑整并parseFloat
转成数字后再显示
function strip(num, precision = 12) {
return +parseFloat(num.toPrecision(precision));
}
- 运算类操作, 把小数转成整数后再运算。
function add(num1, num2) {
const num1Digits = (num1.toString().split('.')[1] || '').length;
const num2Digits = (num2.toString().split('.')[1] || '').length;
const baseNum = Math.pow(10, Math.max(num1Digits, num2Digits));
return (num1 * baseNum + num2 * baseNum) / baseNum;
}
四、防抖和节流
-
函数防抖(debounce):触发高频事件后n秒内函数只会执行一次,如果n秒内高频事件再次被触发,则重新计算时间。
// 防抖 立即执行版本
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
}
}
// 处理函数
function handle() {
console.log('防抖:', Math.random());
}
// 应用: 滚动事件
window.addEventListener('scroll', debounce(handle, 500, false));
-
函数节流(throttle):高频事件触发,但在n秒内只会执行一次,所以节流会稀释函数的执行频率。
//节流 定时器版本:
function throttle(fn,delay) {
let canRun = true; // 通过闭包保存一个标记
return function () {
// 在函数开头判断标记是否为true,不为true则return
if (!canRun) return;
// 立即设置为false
canRun = false;
// 将外部传入的函数的执行放在setTimeout中
setTimeout(() => {
// 最后在setTimeout执行完毕后再把标记设置为true(关键)表示可以执行下一次循环了。
// 当定时器没有执行的时候标记永远是false,在开头被return掉
fn.apply(this, arguments);
canRun = true;
}, delay);
};
}
function sayHi(e) {
console.log('节流:', e.target.innerWidth, e.target.innerHeight);
}
/*
应用
1.射击游戏的 mousedown/keydown 事件(单位时间只能发射一颗子弹)
2.搜索联想(keyup)
3.监听滚动事件判断是否到页面底部自动加载更多:
4.给 scroll 加了 debounce (防抖动函数)后,只有用户停止滚动后,才会判断是否到了页面底部;
如果是 throttle(节流函数) 的话,只要页面滚动就会间隔一段时间判断一次
*/
五、深拷贝
1. 满足一般使用场景,但无法实现对象中方法(function)的深拷贝
JSON.parse(JSON.stringify(obj))
2. Object.assign(obj1, obj2)只有一级属性为深拷贝,二级属性后就是浅拷贝
let obj = {
id: 1,
name: '张三',
age: 10,
}
let newObj = Object.assign({}, obj)
3.扩展运算符 只有一级属性为深拷贝,二级属性后就是浅拷贝
// 对象
let pager = {
size: 10,
current: 1
}
let params = {
name:'123',
...pager
};
// 数组
let arr1 = [{name: "小明", age: 18}, {name: "小芳", age: 20}];
let arr2 = [...arr1];
4. 递归
export function deepClone(source) {
if (!source && typeof source !== 'object') {
throw new Error('error arguments', 'deepClone')
}
const targetObj = source.constructor === Array ? [] : {}
Object.keys(source).forEach(keys => {
if (source[keys] && typeof source[keys] === 'object') {
targetObj[keys] = deepClone(source[keys])
} else {
targetObj[keys] = source[keys]
}
})
return targetObj
}
5. 数组使用数组方法进行深拷贝(concat、slice),只有一级属性为深拷贝,二级属性后就是浅拷贝,如[1,2,3,[1,2,3]]
let arr1 = [1, 2, 3, 4]
let arr2 = arr1.concat()
let arr3 = arr1.slice(1)
6. 使用Vue提供的观察者模式实现数组深度复制
let arr1 = [{name: "小明", age: 18}, {name: "小芳", age: 20}];
let arr2 = Vue.util.extend([], arr1);
六、文字向右滚动(网站公告信息滚动显示), vue3.0
const state: State = reactive({
message: '学习,创新,铸造优良产品',
marqueeVar: null,
speed1: 0,
speed2: 0
});
// 消息公告
const moveMarquee = () => {
// 获取内容区宽度
let width1: any = (document.getElementById('marquee1')?.getBoundingClientRect().width)
//width为第二个span标签尾部到盒子尾部的距离,500为外层盒子的宽度
let width = width1 - 424
let marquee1: any = document.getElementById("marquee1");
state.speed1 = state.speed1 - 2;
state.speed2 -= 1;
// 如果speed2的尾部移到盒子的尾部并且speed1的移动距离不超过文字的距离
if ( -state.speed2 >= width && -state.speed1 >= width1 ) {
//让speed1重新在原位置移动
state.speed1 = 424;
}
if (-state.speed2 >= width1) {
//如果speed2的尾部移动到盒子的头部,让speed2跟在speed1之后移动
state.speed2 = 0
}
if (marquee1){
marquee1.style.transform = "translateX(" + state.speed1 / 20 + "rem)";
}
}
const runMarquee = () => {
let marquee1: any = document.getElementById("marquee1");
state.marqueeVar = setInterval(() => moveMarquee(), 30);
//监听鼠标移入,清空定时器
marquee1.addEventListener('mouseenter', () => {
clearInterval(state.marqueeVar);
state.marqueeVar = null
})
//监听鼠标移开,重启定时器
marquee1.addEventListener('mouseleave', () => {
state.marqueeVar = setInterval(() => moveMarquee(), 30);
}
)
}
onMounted(() => {
// 消息公告
nextTick(()=>{
runMarquee()
})
})
七、文字持续向上滚动
网页上一块相同相似的内容的区域放在一个层里,然后将内容从下往上滚动,一般用于网页公告或新闻展示。
<div class="content_right_top_box_t" id="scroll-container">
<p id="scroll-dom1">豫章故郡,洪都新府。星分翼轸,地接衡庐。襟三江而带五湖,
控蛮荆而引瓯越。物华天宝,龙光射牛斗之墟;人杰地灵,徐孺下陈蕃之榻。雄州雾列,俊采
星驰。台隍枕夷夏之交,宾主尽东南之美。都督阎公之雅望,棨戟遥临;宇文新州之懿范,襜
帷暂驻。十旬休假,胜友如云;千里逢迎,高朋满座。腾蛟起凤,孟学士之词宗;紫电青霜,
王将军之武库。家君作宰,路出名区;童子何知,躬逢胜饯。</p>
<p id="scroll-dom2" style="margin-top: 5rem;"></p>
</div>
let MyMarTimer: NodeJS.Timer | undefined;
// 文字向上滚动
const scrollText = () => {
let container: any = document.getElementById('scroll-container')
let dom1: any = document.getElementById('scroll-dom1')
let dom2: any = document.getElementById('scroll-dom2')
dom2.innerHTML = dom1.innerHTML //复制第一个容器内容到第二个容器,形成滚动的状态
function Marquee() {
// 增加容器的scrolltop 文字向上滚动
// 当滚动到第二个容器文字时, 重新滚动scrollTop = 0, 无缝衔接
console.log(container.scrollTop, dom1.offsetHeight + (rowH * 20 * 5))
if (container.scrollTop >= dom1.offsetHeight + (rowH * 20 * 5)) {
container.scrollTop = 0
} else {
container.scrollTop = container.scrollTop + 1 * rowH
}
}
MyMarTimer = setInterval(Marquee, 80)
container.onmouseover = () => {
MyMarTimer && clearInterval(MyMarTimer) // 鼠标停止时暂停滚动
}
container.onmouseout = () => {
MyMarTimer = setInterval(Marquee, 80) // 鼠标停止时暂停滚动
}
}
八、3d-词云(直接上代码)
<template>
<div class="wordCloud">
<div id="cloud" ref="cloudRef">
<span class="cloud-item" v-for="(item, index) in state.nameArr" :key="'ciyun_' + index">{{ item.name }}</span>
</div>
</div>
</template>
<script setup lang="ts">
import { onMounted, onBeforeUnmount, reactive, ref } from "vue";
declare const window: any;
const cloudRef = ref()
const rowH = window.rowH
let ciyunTimer: NodeJS.Timer | undefined;
const state: any = reactive({
nameArr: [
{
name: '理想汽车',
value: 1,
},
{
name: '中兴汽车',
value: 2,
},
{
name: '蔚来汽车',
value: 3,
},
{
name: '上海大通',
value: 4,
},
{
name: '威马汽车',
value: 5,
},
{
name: '菲亚特',
value: 6,
},
{
name: '华人运通',
value: 7,
},
{
name: '马自达',
value: 8,
},
{
name: '北京现代',
value: 9,
},
{
name: '极氮汽车',
value: 10,
},
{
name: '长城汽车',
value: 11,
},
{
name: '吉利汽车',
value: 12,
},
{
name: '洛轲汽车',
value: 13,
},
{
name: '上海汽车',
value: 14,
},
{
name: '宝马',
value: 15,
},
{
name: '小鹏汽车',
value: 16,
},
{
name: '奔驰',
value: 17,
},
{
name: '大众奥迪',
value: 18,
},
{
name: '铃木',
value: 19,
},
{
name: '沃尔沃',
value: 20,
},
{
name: '福特',
value: 21,
},
{
name: '通用',
value: 22,
},
],
// -- 动态词云 --
radius: 100 * rowH,
dtr: Math.PI / 180,
d: 300 * rowH,
mcList: [],
active: true,
lasta: 1,
lastb: 1,
distr: true,
tspeed: 1,
size: 200,
mouseX: 0,
mouseY: 0,
howElliptical: 1,
aA: null,
oDiv: null,
sa: null,
ca: null,
sb: null,
cb: null,
sc: null,
cc: null
})
onMounted(() => {
init()
})
onBeforeUnmount(() => {
ciyunTimer && clearInterval(ciyunTimer);
});
const init = () => {
let oTag = null;
state.oDiv = cloudRef.value;
state.aA = document.querySelectorAll('.cloud-item')
for (let i = 0; i < state.aA.length; i++) {
oTag = {
offsetWidth: null,
offsetHeight: null,
name: null
};
oTag.offsetWidth = state.aA[i].offsetWidth;
oTag.offsetHeight = state.aA[i].offsetHeight;
oTag.name = state.aA[i].innerHTML;
state.mcList.push(oTag);
}
sineCosine(0, 0, 0);
positionAll();
state.oDiv.onmouseover = function () {
state.active = false;
};
state.oDiv.onmouseout = function () {
state.active = true;
};
autoplay()
ciyunTimer = setInterval(update, 30);
}
const autoplay = () => {
state.mouseX = state.oDiv.offsetLeft + state.oDiv.offsetWidth / 2;
state.mouseY = state.oDiv.offsetTop + state.oDiv.offsetHeight / 2
state.mouseX /= 20;
state.mouseY /= 20;
}
const update = () => {
let a: any;
let b: any;
if (state.active) {
a = (-Math.min(Math.max(-state.mouseY, -state.size), state.size) / state.radius) * state.tspeed;
b = (Math.min(Math.max(-state.mouseX, -state.size), state.size) / state.radius) * state.tspeed;
} else {
a = state.lasta * 0.98;
b = state.lastb * 0.98;
}
state.lasta = a;
state.lastb = b;
if (Math.abs(a) <= 0.01 && Math.abs(b) <= 0.01) {
return;
}
let c = 0;
sineCosine(a, b, c);
for (let j = 0; j < state.mcList.length; j++) {
let rx1 = state.mcList[j].cx;
let ry1 = state.mcList[j].cy * state.ca + state.mcList[j].cz * (-state.sa);
let rz1 = state.mcList[j].cy * state.sa + state.mcList[j].cz * state.ca;
let rx2 = rx1 * state.cb + rz1 * state.sb;
let ry2 = ry1;
let rz2 = rx1 * (-state.sb) + rz1 * state.cb;
let rx3 = rx2 * state.cc + ry2 * (-state.sc);
let ry3 = rx2 * state.sc + ry2 * state.cc;
let rz3 = rz2;
state.mcList[j].cx = rx3;
state.mcList[j].cy = ry3;
state.mcList[j].cz = rz3;
let per = state.d / (state.d + rz3);
state.mcList[j].x = (state.howElliptical * rx3 * per) - (state.howElliptical * 2);
state.mcList[j].y = ry3 * per;
state.mcList[j].scale = per;
state.mcList[j].alpha = per;
state.mcList[j].alpha = (state.mcList[j].alpha - 0.6) * (10 / 6);
}
doPosition();
depthSort();
}
const depthSort = () => {
let aTmp = [];
for (let i = 0; i < state.aA.length; i++) {
aTmp.push(state.aA[i]);
}
aTmp.sort((vItem1, vItem2) => {
if (vItem1.cz > vItem2.cz) {
return -1;
} else if (vItem1.cz < vItem2.cz) {
return 1;
} else {
return 0;
}
});
for (let j = 0; j < aTmp.length; j++) {
aTmp[j].style.zIndex = j;
}
}
const positionAll = () => {
let phi = 0;
let theta = 0;
let max = state.mcList.length;
let aTmp = [];
let oFragment = document.createDocumentFragment();
//随机排序
for (let i = 0; i < state.aA.length; i++) {
aTmp.push(state.aA[i]);
}
aTmp.sort(() => {
return Math.random() < 0.5 ? 1 : -1;
});
for (let l = 0; l < aTmp.length; l++) {
oFragment.appendChild(aTmp[l]);
}
state.oDiv.appendChild(oFragment);
for (let j = 1; j < max + 1; j++) {
if (state.distr) {
phi = Math.acos(-1 + (2 * j - 1) / max);
theta = Math.sqrt(max * Math.PI) * phi;
} else {
phi = Math.random() * (Math.PI);
theta = Math.random() * (2 * Math.PI);
}
//坐标变换
state.mcList[j - 1].cx = state.radius * Math.cos(theta) * Math.sin(phi) * 1.5;
state.mcList[j - 1].cy = state.radius * Math.sin(theta) * Math.sin(phi);
state.mcList[j - 1].cz = state.radius * Math.cos(phi);
// state.aA[j - 1].style.left = (state.mcList[j - 1].cx + state.oDiv.offsetWidth / 2 - state.mcList[j - 1].offsetWidth / 2) / 20 + 'rem';
// state.aA[j - 1].style.top = (state.mcList[j - 1].cy + state.oDiv.offsetHeight / 2 - state.mcList[j - 1].offsetHeight / 2) / 20 +'rem';
state.aA[j - 1].style.left = state.mcList[j - 1].cx + state.oDiv.offsetWidth / 2 - state.mcList[j - 1].offsetWidth / 2 + 'px';
state.aA[j - 1].style.top = state.mcList[j - 1].cy + state.oDiv.offsetHeight / 2 - state.mcList[j - 1].offsetHeight / 2 + 'px';
}
}
const doPosition = () => {
let l = state.oDiv.offsetWidth / 2;
let t = state.oDiv.offsetHeight / 2;
for (let i = 0; i < state.mcList.length; i++) {
// state.aA[i].style.left = (state.mcList[i].cx + l - state.mcList[i].offsetWidth / 2) / 20+'rem';
// state.aA[i].style.top = (state.mcList[i].cy + t - state.mcList[i].offsetHeight / 2) / 20+'rem';
state.aA[i].style.left = state.mcList[i].cx + l - state.mcList[i].offsetWidth / 2 + 'px';
state.aA[i].style.top = state.mcList[i].cy + t - state.mcList[i].offsetHeight / 2 + 'px';
state.aA[i].style.fontSize = (Math.ceil(12 * state.mcList[i].scale / 2) + 8) / 15 + 'rem';
// state.aA[i].style.fontSize = Math.ceil(12 * state.mcList[i].scale / 2) + 8 + 'px';
// state.aA[i].style.filter = "alpha(opacity=" + 100 * state.mcList[i].alpha + ")";
state.aA[i].style.opacity = state.mcList[i].alpha;
}
}
const sineCosine = (a: any, b: any, c: any) => {
state.sa = Math.sin(a * state.dtr);
state.ca = Math.cos(a * state.dtr);
state.sb = Math.sin(b * state.dtr);
state.cb = Math.cos(b * state.dtr);
state.sc = Math.sin(c * state.dtr);
state.cc = Math.cos(c * state.dtr);
}
</script>
<style lang="scss" scoped>
.wordCloud {
width: 100%;
height: 100%;
#cloud {
height: 100%;
width: 100%;
position: relative;
cursor: pointer;
span {
position: absolute;
top: 0;
left: 0;
color: #fff;
font-weight: bold;
font-size: 1rem;
padding: .187rem .375rem;
text-shadow: .05rem .05rem .1rem #1F4BEA;
// #
}
}
// #div1 a {
// }
// #div1 a:hover {
// border: 1px solid #eee;
// background: #000;
// border-radius: 5px;
// }
}
</style>
持续更新中.......