0%

期望每次打开页面鼠标悬停的时候,悬停颜色是随机的,而不是固定的。

1
2
3
4
5
6
7
8
9
10
11
12
const randomHoverColor = () => {
// hsl(0deg 100% 96.5%);
const h = Math.floor(Math.random() * 360);
// const s = Math.floor(Math.random() * 100);
// const l = Math.floor(Math.random() * 100);
return `hsl(${h}deg 100% 99% / 85%)`;
};

const addRandomHoverColor = () => {
const elements = document.documentElement;
elements.style.setProperty("--hover-color", randomHoverColor());
};
1
2
3
4
5
6
.button {
background-color: var(--hover-color);
&:hover {
background-color: var(--hover-color);
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
const generateBoxes = (limit, parent) => {
const colors = [
"#577590",
"#43aa8b",
"#90be6d",
"#f9c74f",
"#f8961e",
"#f3722c",
"#f94144",
];
for (let i = 0; i < limit; i += 1) {
const box = document.createElement("div");
box.classList.add("box");
box.style.backgroundColor =
colors[Math.floor(Math.random() * colors.length)];
box.style.height = `${Math.floor(Math.random() * 300 + 50)}px`;
box.style.width = `${Math.floor(Math.random() * 300 + 50)}px`;
box.style.top = `${Math.floor(Math.random() * 100)}%`;
box.style.left = `${Math.floor(Math.random() * 100)}%`;
parent.appendChild(box);
}
};

这个代码真心好使

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
.box {
position: absolute;
border-radius: 4px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);
opacity: 0.2;
transition: all 0.3s ease-in-out;
z-index: -100;
// cursor: pointer;
&:hover {
transform: scale(1.1);
box-shadow: 0 0 20px rgba(0, 0, 0, 0.2);
}

&-fixed {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
pointer-events: none;
z-index: -100;

@supports (-webkit-touch-callout: none) {
height: -webkit-fill-available;
}
}
}
.box {
position: absolute;
opacity: 0.2;
border-radius: 10px;
}

IOS 有个讨厌的问题,就是 100vh 总会比屏幕高多那么一点点

看样子苹果是不打算修这个 BUG 了,不过好在大佬们也给出了解决方案

1
2
3
@supports (-webkit-touch-callout: none) {
height: -webkit-fill-available;
}

直接上代码

this.$data 获取当前状态下的data
this.$options.data() 获取该组件初始状态下的data

所以,下面就可以将初始状态的data复制到当前状态的data,实现重置效果:
Object.assign(this.$data, this.$options.data())

当然,如果你只想重置data中的某一个对象或者属性:
this.form = this.$options.data().form

转载

原文链接:https://blog.csdn.net/weixin_42054155/article/details/99889910

前言

我错误的使用了解构赋值,导致了一个 bug,所以这里记录一下。

问题

1
2
3
4
5
6
7
8
9
10
const obj = {
a: null,
b: undefined,
c: 1,
d: ""
};

const { a = 1, b = 2, c = 3, d = 4 } = obj;

console.log(a, b, c, d); // 你猜猜会输出什么?

答案是 null 2 1 ''

原因

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment#默认值

每个解构属性都可以有一个默认值。当属性不存在或值为 undefined 时,将使用默认值。如果属性的值为 null,则不使用它。

1
2
3
const [a = 1] = []; // a is 1
const { b = 2 } = { b: undefined }; // b is 2
const { c = 2 } = { c: null }; // c is null

解决

1
2
3
4
5
6
7
8
9
10
11
const obj = {
a: null,
b: undefined,
c: 1,
d: ""
};

const { a, b, c, d } = obj;

// 可以用这个方法赋值初始值
console.log(a || 1, b || 2, c || 3, d || 4);

后记

当然有个别特殊情况也要注意一下

1
2
3
const { b = console.log("hey") } = { b: 2 };
// Does not log anything, because `b` is defined and there's no need
// to evaluate the default value.

周四了,群里的大佬出了一道题

1
2
3
4
5
6
let foo = // 完成代码


if(!foo) {
console.log(foo + 1); // 2
}

答案

1
2
3
4
5
6
let foo = document.all
foo.valueOf = () => 1

if(!foo) {
console.log(foo + 1); // 2
}

这个题有四个关键点,一个是 document.all,一个是 valueOf,另外两个你猜猜是什么,在文章最后面。

因为

1
2
document.all + 1
// 返回 '[object HTMLAllCollection]1'
阅读全文 »

自从设置了git提交签名,出了一堆问题

1
2
3
4
5
error: unsupported value for gpg.format: ssh

'git log' failed with code 128:'error: unsupported value for gpg.format: ssh fatal: bad config variable 'gpg.format' in file '/Users/maotianrun/.gitconfig' at line 25

Git err:gpg failed to sign the data; fatal:failed to write commit object
1
2
3
4
5
6
git config --global --unset gpg.program
git config --global --unset user.signingkey
git config --global --unset commit.gpgsign
git config --global --unset gpg.format
git config commit.gpgsign false
git config --global commit.gpgsign false

前言

背面试题,又遇到了这个 JS 深拷贝问题了,但是这次碰到了个特别变态的。

问题

需要能正常的拷贝下面的对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
// 测试的obj对象
const obj = {
// =========== 1.基础数据类型 ===========
num: 0, // number
str: "", // string
bool: true, // boolean
unf: undefined, // undefined
nul: null, // null
sym: Symbol("sym"), // symbol
bign: BigInt(1n), // bigint

// =========== 2.Object类型 ===========
// 普通对象
obj: {
name: "我是一个对象",
id: 1,
},
// 数组
arr: [0, 1, 2],
// 函数
func: function () {
console.log("我是一个函数");
},
// 日期
date: new Date(0),
// 正则
reg: new RegExp("/我是一个正则/ig"),
// Map
map: new Map().set("mapKey", 1),
// Set
set: new Set().add("set"),
// =========== 3.其他 ===========
[Symbol("1")]: 1, // Symbol作为key
};

// 4.添加不可枚举属性
Object.defineProperty(obj, "innumerable", {
enumerable: false,
value: "不可枚举属性",
});

// 5.设置原型对象
Object.setPrototypeOf(obj, {
proto: "proto",
});

// 6.设置loop成循环引用的属性
obj.loop = obj;

评价一个深拷贝是否完善,请检查以下问题是否都实现了:

  1. 基本类型数据是否能拷贝?
  2. 键和值都是基本类型的普通对象是否能拷贝?
  3. Symbol 作为对象的 key 是否能拷贝?
  4. DateRegExp 对象类型是否能拷贝?
  5. MapSet 对象类型是否能拷贝?
  6. Function 对象类型是否能拷贝?(函数我们一般不用深拷贝)
  7. 对象的原型是否能拷贝?
  8. 不可枚举属性是否能拷贝?
  9. 循环引用是否能拷贝?

我看了之后惊了 Lodash 都不敢这么卷啊

解决

不多说,上代码

阅读全文 »

问题

公司需要我调研一下 VRAR 展示小车,我就想起 ThreeJS 了,在网上找了一下 Demo 和教程

Demo

https://threejs.org/examples/#webgl_materials_car

看到这个 Demo 我立刻知道这是我想要的了

开发过程中碰到的关键点

模型

模型可以在 https://sketchfab.com 下载,选择 glTF 格式

模型编辑器

可以用 Blender 编辑模型,但是我不会用,所以就不介绍了

模型加载

1
2
3
4
const loader = new GLTFLoader() //引入模型的loader实例
const gltf = await loadFile('src/assets/3d/2022_rolls-royce_phantom_extended_series_ii/scene.gltf')
const model = gltf.scene;
scene.add(model)

模型颜色设置

这个是设置模型颜色的代码,scene.traverse 方法可以遍历所有的模型,child.isMesh 判断是否是模型,child.name 判断模型的名称,child.material.color.set 设置模型颜色

1
2
3
4
5
6
7
8
9
10
11
const setCarColor = (index) => {
const currentColor = new Color(colorAry[index])
scene.traverse(child => {
if (child.isMesh) {
console.log(child.name)
if (child.name == 'Object_6') {
child.material.color.set(currentColor)
}
}
})
}

有趣的是我设置其中一个模型颜色的时候,其他模型的颜色也会改变,后来发现是因为这些模型的材质是共用的。如果想单独修改这个模型的颜色,可以用 child.material = child.material.clone() 克隆一个材质,然后再设置颜色

1
2
3
4
5
6
7
8
9
10
11
12
const setCarColor = (index) => {
const currentColor = new Color(colorAry[index])
scene.traverse(child => {
if (child.isMesh) {
console.log(child.name)
if (child.name == 'Object_6') {
child.material = child.material.clone()
child.material.color.set(currentColor)
}
}
})
}

模型加载进度

一般来说模型很大,最好弄个进度条

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
const loadFile = (url) => {
return new Promise(((resolve, reject) => {
loader.load(url,
(gltf) => {
resolve(gltf)
}, ({ loaded, total }) => {
let load = Math.abs(loaded / total * 100)
loadingWidth.value = load
if (load >= 100) {
setTimeout(() => {
isLoading.value = false
}, 1000)
}
console.log((loaded / total * 100) + '% loaded')
},
(err) => {
reject(err)
}
)
}))
}

模型转动

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
const setControls = () => {
controls = new OrbitControls(camera, renderer.domElement)
controls.maxPolarAngle = 0.9 * Math.PI / 2
controls.enableZoom = true
controls.addEventListener('change', render)
}

//返回坐标信息
const render = () => {
map.x = Number.parseInt(camera.position.x)
map.y = Number.parseInt(camera.position.y)
map.z = Number.parseInt(camera.position.z)
}

// 循环场景 、相机、 位置更新
const loop = () => {
requestAnimationFrame(loop)
renderer.render(scene, camera)
controls.update()
}

环境贴图

车转动的时候,需要车身有反光的效果,所以需要设置环境贴图

1
2
3
4
scene.environment = new RGBELoader().load('src/assets/textures/equirectangular/venice_sunset_1k.hdr');
scene.environment.mapping = THREE.EquirectangularReflectionMapping;
renderer.toneMapping = THREE.LinearToneMapping;
renderer.toneMappingExposure = 1;

灯光

车看上去黑不溜秋的是因为没有光,所以需要设置灯光

1
2
3
4
5
6
7
const setLight = () => {
directionalLight = new THREE.DirectionalLight( 0xffffff, 0.5 );
directionalLight.position.set( 0, 1, 0 );
scene.add( directionalLight );
hemisphereLight = new THREE.HemisphereLight( 0xffffff, 0x000000, 0.4 );
scene.add( hemisphereLight );
}

源码

人狠话不多直接上源码

阅读全文 »

网上发现了个梗,就是如果如果你看到有人给你用手笔画一个六,你就知道要赶紧打110了,问为什么?

他说因为6的二进制是110,加上你笔画一个六有点像打电话的姿势,所以是在暗示你打110。

但更有意思的是有人在控制台里面执行了下面的命令

1
2^2 + 2^1 // 返回 7

告诉我答案是7

但更有意思的是有人在控制台里面执行了下面的命令

1
2
2^2 // 返回 0
2^1 // 返回 3

看了一下输出结果,发现是0和3,0 + 3 不应该是3吗?

然后我就去查了一下发现这个叫做按位异或,也就是 XOR

MDN - XOR

剩下的就是运算符优先的问题了,按位异或的优先级是最低的,所以 2^2 + 2^1 实际上是 2^(2+2)^1 = 2^4^1 = 7

这里面考察的是计算机中符号的含义和运算符的优先级,如果你不知道这个,那么你就会认为 2^2 + 2^1 = 6 这个错误的说法

那上面的6转换成110的二进制计算到底应该怎么写呢?

1
2**2 + 2**1 // 返回 6