Fork me on GitHub

缤纷浏览器 —— 一键换肤,个性随心换

缤纷浏览器 —— 一键换肤,个性随心换

效果展示

想要给你的浏览器换上新装吗?来看看这个简单又实用的H5换肤效果吧!点击下方的图片,即可体验不同的浏览器皮肤,让你的浏览体验更加多彩。

线上访问地址:

缤纷浏览器换肤效果

1. 搭建网页框架

首先,我们创建一个基本的HTML文档结构,为后续的样式和脚本打下基础。

1
2
3
4
5
6
7
8
9
10
11
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>缤纷浏览器 —— 一键换肤,个性随心换</title>
</head>
<body>
<!-- 网页内容将在这里添加 -->
</body>
</html>

2. 搭建网页元素结构

<body>标签中,我们添加了一个包含多个<img>元素的<ul>列表,每个图片代表一种皮肤。

1
2
3
4
5
6
7
8
<body>
<ul class="skin-list">
<li><img src="http://cdn-hw-static2.shanhutech.cn/bizhi/staticwp/202310/245d0b716c34ec5ad25f203bad78a913--972850685.jpg" alt="Skin 1"></li>
<li><img src="http://cdn-hw-static2.shanhutech.cn/bizhi/staticwp/202310/17e05efa4e03c4a62a9ef4dc8fbeb409--2755567652.jpg" alt="Skin 2"></li>
<li><img src="http://cdn-hw-static2.shanhutech.cn/bizhi/staticwp/202310/b4384e8369039552446b4e0663c4c450--3317306650.jpg" alt="Skin 3"></li>
<li><img src="http://cdn-hw-static2.shanhutech.cn/bizhi/staticwp/202401/7653154ac8956eb8194325af063b032f--4006561019.jpg" alt="Skin 4"></li>
</ul>
</body>

3. 编写CSS样式

接下来,我们为页面添加一些样式,使其看起来更加美观。同时,我们将添加一些表情包元素,增加页面的趣味性。

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
49
50
51
52
53
54
55
56
57
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}

body {
background: url("http://cdn-hw-static2.shanhutech.cn/bizhi/staticwp/202310/245d0b716c34ec5ad25f203bad78a913--972850685.jpg") no-repeat center center / cover;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
font-family: 'Arial', sans-serif;
}

.skin-list {
text-align: center;
list-style: none;
display: inline-block;
}

.skin-list li {
display: inline-block;
margin: 10px;
cursor: pointer;
transition: transform 0.3s ease;
}

.skin-list li:hover {
transform: scale(1.1);
}

.skin-list img {
width: 100px;
border-radius: 50%;
border: 2px solid #fff;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.5);
}

/* 添加表情包样式 */
表情包 {
position: absolute;
bottom: 20px;
right: 20px;
font-size: 24px;
color: #ff7f50;
animation: float 2s ease-in-out infinite;
}

@keyframes float {
0%, 100% {
transform: translateY(0);
}
50% {
transform: translateY(-20px);
}
}

4. 编写点击事件

最后,我们为每个图片添加点击事件,当用户点击图片时,更改背景图片以实现换肤效果。

1
2
3
4
5
6
7
8
9
10
11
12
<script>
// 获取所有图片元素
var skins = document.querySelectorAll('.skin-list img');

// 循环为每个图片注册点击事件
skins.forEach(function(skin) {
skin.addEventListener('click', function() {
// 设置body的背景图片为被点击图片的src属性
document.body.style.backgroundImage = 'url(' + this.src + ')';
});
});
</script>

全部代码

将以上HTML、CSS和JavaScript代码合并,即可得到完整的换肤效果页面。

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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
<!DOCTYPE html>
<html lang="en">
<!-- Browser skin -->
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>缤纷浏览器 —— 一键换肤,个性随心换</title>
<style>
* {
margin: 0;
padding: 0;
}

body {
background: url(http://cdn-hw-static2.shanhutech.cn/bizhi/staticwp/202310/245d0b716c34ec5ad25f203bad78a913--972850685.jpg) no-repeat 0 0 / 100% 100% border-box border-box fixed;
}

li {
list-style: none;
}

.baidu {
overflow: hidden;
margin: 100px auto;
background-color: #fff;
width: 410px;
padding-top: 3px;
}

.baidu li {
float: left;
margin: 0 1px;
cursor: pointer;
}

.baidu img {
width: 100px;
}
</style>
</head>

<body>
<ul class="baidu">
<li><img
src="http://cdn-hw-static2.shanhutech.cn/bizhi/staticwp/202310/245d0b716c34ec5ad25f203bad78a913--972850685.jpg">
</li>
<li><img
src="http://cdn-hw-static2.shanhutech.cn/bizhi/staticwp/202310/17e05efa4e03c4a62a9ef4dc8fbeb409--2755567652.jpg">
</li>
<li><img
src="http://cdn-hw-static2.shanhutech.cn/bizhi/staticwp/202310/b4384e8369039552446b4e0663c4c450--3317306650.jpg">
</li>
<li><img
src="http://cdn-hw-static2.shanhutech.cn/bizhi/staticwp/202401/7653154ac8956eb8194325af063b032f--4006561019.jpg">
</li>
</ul>
<script>
// 1. 获取元素
var imgs = document.querySelector('.baidu').querySelectorAll('img');
// console.log(imgs);
// 2. 循环注册事件
for (var i = 0; i < imgs.length; i++) {
imgs[i].onclick = function () {
// this.src 就是我们点击图片的路径 images/2.jpg
// console.log(this.src);
// 把这个路径 this.src 给body 就可以了
document.body.style.backgroundImage = 'url(' + this.src + ')';
}
}
</script>
</body>

</html>

现在,你的浏览器换肤页面已经完成了!点击不同的图片,享受个性化的浏览体验吧。记得检查网络连接,确保图片资源可以顺利加载。如果你喜欢这个效果,不妨分享给你的朋友们,一起享受缤纷的网络世界!

如果对你有帮助,点赞👍、收藏💖、关注🔔是我更新的动力!👋🌟🚀

Node.js核心命令与工具:提升开发效率的实用指南

Node.js核心命令与工具:提升开发效率的实用指南

Node.js是一个基于Chrome V8引擎的开源服务器端JavaScript运行环境,它允许开发者使用JavaScript编写服务器端代码,实现高效的I/O操作和网络通信。Node.js的异步、事件驱动的特性使其非常适合构建可扩展的网络应用。除了内置模块,Node.js的强大之处在于其丰富的生态系统,通过npm(Node Package Manager)可以轻松安装和管理成千上万的第三方模块。

Node.js 提供了一系列的命令行工具和内置模块,使得开发者能够轻松地执行各种任务。以下是一些常用的 Node.js 命令和功能:

1. node 命令

这是启动 Node.js 应用程序的基本命令。它后面通常跟随要执行的 JavaScript 文件名。

1
node app.js

2. npm 命令

Node Package Manager(npm)是 Node.js 的包管理器,用于安装和管理 Node.js 模块。

  • 安装全局模块:

    1
    npm install -g <package-name>
  • 安装项目依赖:

    1
    npm install <package-name> --save
  • 更新项目依赖:

    1
    npm update
  • 卸载模块:

    1
    npm uninstall <package-name>
  • 初始化 npm 项目:

    1
    npm init

3. npx 命令

npx 是 npm 的一个工具,用于执行 Node 包的二进制文件。它允许你运行 Node.js 包的脚本,而无需全局安装它们。

1
npx create-react-app my-app

4. nodemon 命令

nodemon 是一个工具,用于在文件更改时自动重启 Node.js 应用程序。它通常用于开发过程中,以便快速看到更改的效果。

1
nodemon app.js

5. forever 命令

forever 是一个 Node.js 模块,用于确保应用程序持续运行。如果应用程序崩溃,它会自动重启。

1
forever start -l /var/log/forever -p 3000 app.js

6. pm2 命令

pm2 是一个进程管理器,用于保持应用程序的持续运行、负载均衡和日志记录。

  • 安装 pm2:

    1
    npm install -g pm2
  • 启动应用程序:

    1
    pm2 start app.js
  • 查看应用程序状态:

    1
    pm2 status
  • 停止应用程序:

    1
    pm2 stop app.js

7. eslint 命令

eslint 是一个 JavaScript 代码质量工具,用于检测代码中的错误和不一致。

1
eslint app.js

8. node-inspector 命令

node-inspector 是一个调试工具,提供了一个图形界面,用于调试 Node.js 应用程序。

1
node-inspector

9. mocha 命令

mocha 是一个流行的 JavaScript 测试框架,用于编写和运行测试。

1
mocha test.js

10. webpack 命令

webpack 是一个模块打包器,用于将多个模块和资源打包成少数几个文件,通常用于前端资源的打包。

1
webpack --watch

这些命令和工具是 Node.js 开发中常用的一部分,它们帮助开发者更高效地进行代码管理、项目构建、调试和测试。

如果对你有帮助,点赞、收藏、关注是我更新的动力!👋🌟🚀

Node.js快速入门:搭建基础Web服务器与实现CRUD及登录功能

Node.js快速入门:搭建基础Web服务器与实现CRUD及登录功能

在Node.js中,创建一个功能完备的Web服务器如同搭积木般简单。借助Node.js的http模块和一些强大的第三方库,我们可以快速搭建起一个响应灵敏的服务器。本教程将详细介绍如何使用Node.js进行数据库操作和用户认证,包括创建数据库、实现CRUD操作和登录验证等关键步骤。

技术栈介绍

Node.js

Node.js是一个跨平台的运行时环境,它允许您在服务器上运行JavaScript代码。它基于事件驱动和非阻塞I/O模型,这使得Node.js非常适合处理大量并发连接。

Express

Express是一个灵活的Node.js Web应用框架,提供了一系列强大的功能,用于构建单页、多页以及混合Web应用。它简化了路由、中间件管理和错误处理等常见Web开发任务。

mysql

mysql是一个Node.js的客户端库,用于与MySQL数据库进行交互。它提供了一个简单易用的API,用于执行SQL查询和接收数据库响应。

body-parser

body-parser是Express的一个中间件,用于解析请求体中的JSON和URL编码的数据。它使得处理POST请求和解析复杂数据变得更加容易。

cors

cors(Cross-Origin Resource Sharing)是一个Node.js的中间件,用于实现跨源资源共享。它允许您指定哪些域名可以访问您的资源,从而避免了跨域请求问题。

实现步骤

环境搭建

首先,确保您的计算机上安装了Node.js和npm(Node Package Manager),这是Node.js开发的基础工具集。

项目初始化

在您的工作目录中,创建一个新的文件夹用于存放项目文件,并在该目录下运行npm init命令来初始化一个新的Node.js项目。

安装依赖

通过运行npm install express mysql body-parser cors命令,安装项目所需的第三方库:Express用于Web框架,mysql用于数据库操作,body-parser用于解析请求体,cors用于处理跨域请求。

配置数据库

首先,我们需要设置一个名为crud_demo的数据库,其中包含一个user表,字段包括idnamesexage

编写服务器代码

在项目目录中,创建一个JavaScript文件,例如server.js,并开始编写服务器代码。使用const express = require('express')引入Express模块,并实例化一个Express应用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//引用mysql依赖
const mysql = require("mysql");
//引用express依赖
const express = require("express");
//引用body-parser 解析post传参
const bodyParser = require("body-parser");
//express实例化
const app = express();
//引用 cors
const cors = require("cors");
const { json } = require("body-parser");
//关闭Form表单传值
app.use(bodyParser.urlencoded({ extended: false }));
//使用Json传值
app.use(bodyParser.json());
//使用cors 解决跨域问题
app.use(cors());

配置数据库连接

使用mysql模块创建一个连接到MySQL数据库的客户端实例,并提供必要的连接信息。

1
2
3
4
5
6
7
8
const connection = mysql.createConnection({
host: "localhost",
user: "root",
password: "password",//修改成自己的密码
database: "crud_demo",//修改成自己的数据库名
});
// 建立数据库连接
connection.connect();

解析请求体

使用body-parser中间件来解析传入的JSON和URL编码的数据。

处理跨域请求

通过cors中间件配置,允许跨域请求访问您的服务器。

实现CRUD操作

为Express应用定义路由,实现对数据库的增删改查操作。

Select操作

创建一个GET路由,用于从数据库中检索并返回用户数据。

1
2
3
4
5
6
7
8
9
10
11
12
13
/**
* select
* http://127.0.0.1:3000/api
*/
app.get("/api", (req, res) => {
let sql = "select * from user";
connection.query(sql, function (error, results, fields) {
if (error) throw error;
console.log(results);
// return results;
return res.json(results);
});
});

Delete操作

创建一个GET路由,接受用户ID作为参数,并从数据库中删除对应记录。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
* delete
* http://127.0.0.1:3000/api/delete/4
*/
app.get("/api/delete/:id", (req, res) => {
console.log(req.params);
console.log(req.params.id);
let delSql = `DELETE FROM user where id= ${parseInt(req.params.id)}`;
console.log(delSql);
connection.query(delSql, function (error, results) {
if (error) throw error;
console.log(results);
// return results;
return res.json(results);
});
});

Insert操作

创建一个GET路由,接受用户信息作为查询参数,并将其插入数据库。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
* insert
* http://localhost:3000/api/insert?id=4&name=xiaohe&sex=%E7%94%B7&age=19
*/
app.get("/api/insert", (req, res) => {
console.log(req.query);
console.log(req.body);
console.log(req.query.id);
let insertSql = `insert into user VALUES(?,?,?,?)`;
console.log(insertSql);
let data = [req.query.id, req.query.name, req.query.sex, req.query.age];
connection.query(insertSql, data, function (error, results) {
if (error) throw error;
console.log(results);
// return results;
return res.json(results);
});
});

Update操作

创建一个GET路由,接受用户ID和更新信息作为查询参数,并更新数据库中的记录。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
* update
* http://localhost:3000/api/update?id=4&name=%E7%99%BE%E5%BA%A6&sex=%E7%94%B7&age=999
*/
app.get("/api/update", (req, res) => {
console.log(req.query);
console.log(req.body);
console.log(req.query.id);
let updateSql = `update user set name = ?, sex = ?, age = ? where id = ?`;
console.log(updateSql);
let data = [req.query.name, req.query.sex, req.query.age, req.query.id];
connection.query(updateSql, data, function (error, results) {
if (error) throw error;
console.log(results);
// return results;
return res.json(results);
});
});

实现登录功能

创建一个GET路由,用于接收登录请求,验证用户凭据,并返回登录结果。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/**
* login
* http://127.0.0.1:3000/api/login?name="1234567890"&pwd="123456"
*/
app.get("/api/login", (req, res) => {
let loginSql = `select * from user where name = ? and pwd = ?`;
console.log(loginSql);
let data = [req.query.name, req.query.pwd];
connection.query(loginSql, data, function (error, results, fields) {
if (error) throw error;
console.log(results);
// return results;
if (results.length) {
console.log("登录成功");
} else {
console.log("账号不存在");
}
return res.json(results);
});
});

启动服务器

使用app.listen()方法启动Express服务器,并指定端口号,例如3000。

全部代码

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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
//引用mysql依赖
const mysql = require("mysql");
//引用express依赖
const express = require("express");
//引用body-parser 解析post传参
const bodyParser = require("body-parser");
//express实例化
const app = express();
//引用 cors
const cors = require("cors");
const { json } = require("body-parser");
//关闭Form表单传值
app.use(bodyParser.urlencoded({ extended: false }));
//使用Json传值
app.use(bodyParser.json());
//使用cors 解决跨域问题
app.use(cors());

const connection = mysql.createConnection({
host: "localhost",
user: "root",
password: "password",//修改成自己的密码
database: "crud_demo",//修改成自己的数据库名
});
// 建立数据库连接
connection.connect();

/**
* select
* http://127.0.0.1:3000/api
*/
app.get("/api", (req, res) => {
let sql = "select * from user";
connection.query(sql, function (error, results, fields) {
if (error) throw error;
console.log(results);
// return results;
return res.json(results);
});
});

/**
* delete
* http://127.0.0.1:3000/api/delete/4
*/
app.get("/api/delete/:id", (req, res) => {
console.log(req.params);
console.log(req.params.id);
let delSql = `DELETE FROM user where id= ${parseInt(req.params.id)}`;
console.log(delSql);
connection.query(delSql, function (error, results) {
if (error) throw error;
console.log(results);
// return results;
return res.json(results);
});
});

/**
* insert
* http://localhost:3000/api/insert?id=4&name=xiaohe&sex=%E7%94%B7&age=19
*/
app.get("/api/insert", (req, res) => {
console.log(req.query);
console.log(req.body);
console.log(req.query.id);
let insertSql = `insert into user VALUES(?,?,?,?)`;
console.log(insertSql);
let data = [req.query.id, req.query.name, req.query.sex, req.query.age];
connection.query(insertSql, data, function (error, results) {
if (error) throw error;
console.log(results);
// return results;
return res.json(results);
});
});

/**
* update
* http://localhost:3000/api/update?id=4&name=%E7%99%BE%E5%BA%A6&sex=%E7%94%B7&age=999
*/
app.get("/api/update", (req, res) => {
console.log(req.query);
console.log(req.body);
console.log(req.query.id);
let updateSql = `update user set name = ?, sex = ?, age = ? where id = ?`;
console.log(updateSql);
let data = [req.query.name, req.query.sex, req.query.age, req.query.id];
connection.query(updateSql, data, function (error, results) {
if (error) throw error;
console.log(results);
// return results;
return res.json(results);
});
});

/**
* login
* http://127.0.0.1:3000/api/login?name="1234567890"&pwd="123456"
*/
app.get("/api/login", (req, res) => {
let loginSql = `select * from user where name = ? and pwd = ?`;
console.log(loginSql);
let data = [req.query.name, req.query.pwd];
connection.query(loginSql, data, function (error, results, fields) {
if (error) throw error;
console.log(results);
// return results;
if (results.length) {
console.log("登录成功");
} else {
console.log("账号不存在");
}
return res.json(results);
});
});

app.listen(3000, () => {
console.log("服务器启动成功...");
});

测试

使用Web浏览器或API测试工具(如Postman)访问服务器的路由,验证CRUD和登录功能是否按预期工作。

如果对你有帮助,点赞、收藏、关注是我更新的动力!👋🌟🚀

🚀 计算机专业学生的成长之路:超越课堂的自我提升策略 📚

🚀 计算机专业学生的成长之路:超越课堂的自我提升策略 📚

在计算机专业的学习旅程中,我们往往会发现,仅仅依靠课堂和课本的知识是远远不够的。在这个信息爆炸💥的时代,主动拓展学习边界,积极利用外部资源,对于提升我们的专业技能至关重要。以下是一些实用的建议,帮助计算机专业的学弟学妹们在校园之外,继续深化和扩展自己的计算机知识。

🌟 计算机专业学生的成长之路

1. 探索GitHub 🐙

GitHub不仅是代码托管平台,更是程序员的社区。这里有丰富的开源项目和代码,是学习和交流的宝库。通过参与项目,你可以了解实际开发流程,提升编程技能。

2. 精通Google搜索 🔍

面对问题和挑战时,学会高效使用Google搜索,寻找解决方案。这不仅能帮助你解决当前的问题,还能让你习惯于自主学习,培养解决问题的能力。

3. 自学关键技术 🛠️

掌握Docker、Linux、vim、shell脚本和版本控制(如git)等基础技能。这些是现代软件开发不可或缺的工具,对于提高开发效率和质量至关重要。

4. 学习国际公开课 🎓

利用斯坦福、普林斯顿、MIT等顶尖大学提供的在线课程,这些课程往往由领域内的专家讲授,内容深入浅出,是自我提升的优质资源。

5. 实战项目经验 🏢

通过参与计算机类项目,如阿里天池、百度之星ACM、蓝桥杯等竞赛,你可以将理论知识应用于实践,积累宝贵的实战经验。

6. 阅读经典书籍 📚

《算法导论》、《深入理解计算机系统》等经典书籍,为我们提供了计算机科学的深厚基础。阅读这些书籍,能够帮助我们构建扎实的理论体系。

7. 实习经验 👔

无论是日常实习还是暑期实习,实际的工作经验能让你在真实的工作环境中学习和成长,对于未来的职业发展大有裨益。

8. 刷题提升 💪

在LeetCode等在线平台上刷题,不仅能够锻炼你的编程能力,还能帮助你准备互联网大厂的面试。特别是在数据结构与算法、操作系统、计算机网络、计算机组成原理等核心课程上的深入学习,将为你的编程之路打下坚实的基础。

🎯 推荐的刷题网站:

结语 🎓:

计算机专业的学习是一个不断探索和实践的过程。通过上述方法,你可以有效地缩小与前沿技术之间的信息差,不断提升自己的核心竞争力。记住,计算机专业的学习不仅仅是为了应付考试,更重要的是为了在未来的职业生涯中,能够不断适应和引领技术的发展。

如果对你有帮助,点赞👍、收藏💖、关注🔔是我更新的动力!👋🌟🚀

ECMAScript核心概念与现代JavaScript特性全解析

ECMAScript核心概念与现代JavaScript特性全解析

ECMAScript(通常简称为 ES)是JavaScript的标准化规范,由Ecma International的TC39(技术委员会39)组织维护。ECMAScript定义了脚本语言的语法和行为,而JavaScript是ECMAScript规范的一种实现。以下是ECMAScript的一些核心语法特性:

基本语法

1. 变量声明

1
2
let x = 10; // 块级作用域的变量声明
const y = 20; // 常量声明,不可重新赋值

2. 数据类型

ECMAScript支持多种数据类型,包括:

  • 原始数据类型:字符串(String)、数字(Number)、布尔值(Boolean)、空值(null)、未定义(undefined)、符号(Symbol)
  • 复合数据类型:对象(Object)、数组(Array)、函数(Function)

3. 函数

1
2
3
4
5
6
function greet(name) {
return `Hello, ${name}!`;
}

// 箭头函数
const greet = (name) => `Hello, ${name}!`;

4. 条件语句

1
2
3
4
5
6
7
8
if (condition) {
// 代码块
} else {
// 另一个代码块
}

// 条件(三元)运算符
const result = condition ? expression1 : expression2;

5. 循环

1
2
3
4
5
6
7
8
9
10
11
for (let i = 0; i < 10; i++) {
// 循环体
}

while (condition) {
// 循环体
}

do {
// 循环体
} while (condition);

6. 数组

1
2
3
4
5
6
7
const fruits = ['Apple', 'Banana', 'Cherry'];

// 访问数组元素
console.log(fruits[0]); // Apple

// 修改数组元素
fruits[1] = 'Blueberry';

7. 对象

1
2
3
4
5
6
7
8
9
10
11
12
13
const person = {
name: 'Alice',
age: 25,
greet: function() {
console.log(`Hello, my name is ${this.name}.`);
}
};

// 访问对象属性
console.log(person.name); // Alice

// 调用对象方法
person.greet();

8. 类(ES6+)

1
2
3
4
5
6
7
8
9
10
11
12
13
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}

greet() {
console.log(`Hello, my name is ${this.name}.`);
}
}

const alice = new Person('Alice', 25);
alice.greet();

9. 模板字符串

1
2
3
const name = 'Alice';
const greeting = `Hello, ${name}!`;
console.log(greeting); // Hello, Alice!

10. 解构赋值

1
2
3
4
5
6
7
const [a, b] = [1, 2];
console.log(a); // 1
console.log(b); // 2

const { name, age } = { name: 'Alice', age: 25 };
console.log(name); // Alice
console.log(age); // 25

11. 异步编程(Promise和async/await)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
const fetchData = () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('Data fetched');
}, 1000);
});
};

fetchData()
.then(data => console.log(data))
.catch(error => console.error(error));

// 使用async/await
async function fetchDataAsync() {
try {
const data = await fetchData();
console.log(data);
} catch (error) {
console.error(error);
}
}

fetchDataAsync();

这些是ECMAScript语法的一些基本元素。随着ECMAScript规范的不断发展,新的语法和特性不断被添加到JavaScript中,例如模块导入(import/export)、集合(Set和Map)、异步迭代器(async iterable)等。

高级教程

12. 模块导入(import/export)

在ECMAScript 6之前,JavaScript缺乏官方的模块系统。随着ES6的引入,importexport关键字使得模块化编程成为可能。模块化允许开发者将代码分割成独立的、可重用的单元,每个模块可以独立维护和更新。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 导出单个值
export const myConstant = 'Hello, World!';

// 导出多个值
const myFunction = () => {
// ...
};

export { myFunction };

// 导出默认值
export default myFunction;

// 导入模块
import { myConstant, myFunction } from './module.js';
import myDefaultFunction from './defaultModule.js';

13. 集合(Set和Map)

SetMap是ES6中引入的两种新的数据结构,它们提供了不同于数组和对象的数据存储方式。

  • Set是一个集合,它只存储唯一的值(不允许重复)。
  • Map是一个键值对的集合,其中的键可以是任何类型,包括函数、对象或任何原始类型。
1
2
3
4
5
6
7
8
9
10
11
// 使用Set
const mySet = new Set();
mySet.add(1);
mySet.add(2);
console.log(mySet.size); // 2

// 使用Map
const myMap = new Map();
myMap.set('key1', 'value1');
myMap.set('key2', 'value2');
console.log(myMap.get('key1')); // 'value1'

14. 异步迭代器(async iterable)

ECMAScript 8引入了异步迭代器的概念,它允许开发者在for...of循环中处理异步操作,如异步请求数据。

1
2
3
4
5
6
7
8
9
async function* asyncGenerator() {
yield await Promise.resolve(1);
yield await Promise.resolve(2);
yield await Promise.resolve(3);
}

for await (const value of asyncGenerator()) {
console.log(value); // 依次打印 1, 2, 3
}

在这个例子中,asyncGenerator是一个异步生成器函数,它可以异步地产生值。for await...of循环使得我们可以等待每个异步操作完成后再进行下一次迭代。

15. 其他高级特性

除了上述特性,ECMAScript还包括其他一些高级特性,如:

  • 默认参数值:允许在函数定义时为参数指定默认值。
  • rest参数:允许我们将不定数量的参数表示为一个数组。
  • spread操作符:用于将数组或可迭代对象的元素展开。
  • 类(Class):提供了一种新的语法糖,使得对象原型的写法更加清晰和易于理解。
  • 模块顶级等待(Top-level await):在ES12中引入,允许在模块的顶层使用await,这有助于处理动态导入。

这些特性共同推动了JavaScript语言的发展,使其在构建大型、复杂的应用程序方面变得更加强大和灵活。

如果对你有帮助,点赞、收藏、关注是我更新的动力!👋🌟🚀

打造精美响应式CSS日历:从基础到高级样式

打造精美响应式CSS日历:从基础到高级样式

在这篇文章中,我们将学习如何使用HTML和CSS创建一个简洁而美观的日历样式。我们将从基础的日历结构开始,逐步添加样式,并使用CSS的媒体查询为不同屏幕尺寸进行适配。通过本教程,您将掌握如何制作一个响应式的日历,它不仅能够在桌面上展示,也能很好地适应移动设备。

效果预览:

1. 创建日历的基本结构

首先,我们需要创建日历的HTML结构。日历由三个主要部分组成:月份和年份的标题、星期的简称、以及日期列表。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<div class="month">
<ul>
<li class="prev"></li>
<li class="next"></li>
<li style="text-align:center">
August<br>
<span style="font-size:18px">2016</span>
</li>
</ul>
</div>

<ul class="weekdays">
<li>Mo</li>
<li>Tu</li>
<li>We</li>
<li>Th</li>
<li>Fr</li>
<li>Sa</li>
<li>Su</li>
</ul>

<ul class="days">
<!-- 日期列表 -->
</ul>

2. 添加CSS样式

接下来,我们将使用CSS为日历添加样式。我们将设置基本的样式,如字体、背景色、文本对齐等,并使用伪类和伪元素来添加箭头图标。

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
49
50
51
52
53
54
55
56
57
58
59
60
61
/* 基础样式 */
* {
box-sizing: border-box;
}

ul {
list-style-type: none;
margin: 0;
padding: 0;
}

body {
font-family: Verdana, sans-serif;
}

/* 月份和年份样式 */
.month {
padding: 70px 25px;
width: 100%;
background: #1abc9c;
}

.month ul li {
color: white;
font-size: 20px;
text-transform: uppercase;
letter-spacing: 3px;
}

/* 星期样式 */
.weekdays {
background-color: #ddd;
}

.weekdays li {
display: inline-block;
width: 13.6%;
color: #666;
text-align: center;
}

/* 日期样式 */
.days {
background: #eee;
}

.days li {
display: inline-block;
width: 13.6%;
text-align: center;
margin-bottom: 5px;
font-size: 12px;
color: #777;
}

/* 当前日期样式 */
.days li .active {
padding: 5px;
background: #1abc9c;
color: white !important;
}

3. 响应式设计

为了使日历在不同设备上都能良好展示,我们将使用CSS的媒体查询来调整小屏幕设备上的布局。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@media screen and (max-width: 720px) {
.weekdays li,
.days li {
width: 13.1%;
}
}

@media screen and (max-width: 420px) {
.weekdays li,
.days li {
width: 12.5%;
}

.days li .active {
padding: 2px;
}
}

@media screen and (max-width: 290px) {
.weekdays li,
.days li {
width: 12.2%;
}
}

4. 完善日历功能

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
document.addEventListener('DOMContentLoaded', function () {
var days = document.querySelectorAll('.days li span');
days.forEach(function (day) {
day.addEventListener('click', function () {
console.log('Date clicked');
// 移除其他日期的激活状态
days.forEach(function (el) {
el.classList.remove('active');
});
// 为被点击的日期添加激活状态
this.classList.add('active');
});
});
});
// 1. contextmenu 可以禁用右键菜单
document.addEventListener('contextmenu', function (e) {
e.preventDefault();
})
// 2. 禁止选中文字 selectstart
document.addEventListener('selectstart', function (e) {
e.preventDefault();
})

为了使日历更加实用,我们可以添加一些交互功能,例如点击月份和年份切换视图,以及点击日期弹出事件详情。这将需要使用JavaScript来实现,但在本教程中,我们专注于使用CSS创建样式。

5. 全部代码

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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>CSS 日历样式</title>
<style>
* {
box-sizing: border-box;
}

ul {
list-style-type: none;
}

body {
font-family: Verdana, sans-serif;
}

.month {
padding: 70px 25px;
width: 100%;
background: #1abc9c;
}

.month ul {
margin: 0;
padding: 0;
}

.month ul li {
color: white;
font-size: 20px;
text-transform: uppercase;
letter-spacing: 3px;
}

.month .prev {
float: left;
padding-top: 10px;
}

.month .next {
float: right;
padding-top: 10px;
}

.weekdays {
margin: 0;
padding: 10px 0;
background-color: #ddd;
}

.weekdays li {
display: inline-block;
width: 13.6%;
color: #666;
text-align: center;
}

.days {
padding: 10px 0;
background: #eee;
margin: 0;
}

.days li {
list-style-type: none;
display: inline-block;
width: 13.6%;
text-align: center;
margin-bottom: 5px;
font-size: 12px;
color: #777;
}

.days li .active {
padding: 5px;
background: #1abc9c;
color: white !important
}

/* Add media queries for smaller screens */
@media screen and (max-width:720px) {

.weekdays li,
.days li {
width: 13.1%;
}
}

@media screen and (max-width: 420px) {

.weekdays li,
.days li {
width: 12.5%;
}

.days li .active {
padding: 2px;
}
}

@media screen and (max-width: 290px) {

.weekdays li,
.days li {
width: 12.2%;
}
}
</style>
</head>

<body>

<h1 style="text-align: center;">CSS 日历</h1>

<div class="month">
<ul>
<li class="prev"></li>
<li class="next"></li>
<li style="text-align:center">
March<br>
<span style="font-size:18px">2024</span>
</li>
</ul>
</div>

<ul class="weekdays">
<li>Mo</li>
<li>Tu</li>
<li>We</li>
<li>Th</li>
<li>Fr</li>
<li>Sa</li>
<li>Su</li>
</ul>

<ul class="days">
<li><span>1</span></li>
<li><span>2</span></li>
<li><span>3</span></li>
<li><span>4</span></li>
<li><span>5</span></li>
<li><span>6</span></li>
<li><span>7</span></li>
<li><span>8</span></li>
<li><span>9</span></li>
<li><span class="active">10</span></li>
<li><span>11</span></li>
<li><span>12</span></li>
<li><span>13</span></li>
<li><span>14</span></li>
<li><span>15</span></li>
<li><span>16</span></li>
<li><span>17</span></li>
<li><span>18</span></li>
<li><span>19</span></li>
<li><span>20</span></li>
<li><span>21</span></li>
<li><span>22</span></li>
<li><span>23</span></li>
<li><span>24</span></li>
<li><span>25</span></li>
<li><span>26</span></li>
<li><span>27</span></li>
<li><span>28</span></li>
<li><span>29</span></li>
<li><span>30</span></li>
<li><span>31</span></li>
</ul>
<script>
document.addEventListener('DOMContentLoaded', function () {
var days = document.querySelectorAll('.days li span');
days.forEach(function (day) {
day.addEventListener('click', function () {
console.log('Date clicked');
// 只有当日期未被激活时才进行操作
// 移除其他日期的激活状态
days.forEach(function (el) {
el.classList.remove('active');
});
// 为被点击的日期添加激活状态
this.classList.add('active');
});
});
});
// 1. contextmenu 可以禁用右键菜单
document.addEventListener('contextmenu', function (e) {
e.preventDefault();
})
// 2. 禁止选中文字 selectstart
document.addEventListener('selectstart', function (e) {
e.preventDefault();
})
</script>
</body>

</html>

🎉 结语

通过本教程,您已经学会了如何使用HTML和CSS、JavaScript创建一个基本的日历样式,并使其响应式地适应不同屏幕尺寸。您可以在此基础上添加更多的功能和样式,以满足您的具体需求。记得在实际项目中测试日历在不同浏览器和设备上的兼容性,确保所有用户都能获得良好的体验。

如果对你有帮助,点赞、收藏、关注是我更新的动力!👋🌟🚀

Vue 3响应式系统详解:ref、toRefs、reactive及更多

Vue 3响应式系统详解:ref、toRefs、reactive及更多

在 Vue 3 中,reftoRefsreactive 是处理响应式数据的三种不同方式,它们各自有不同的用途和特点。

1. ref、toRefs、reactive

1. ref

ref 是用来创建响应式引用的主要方法。它通常用于基本数据类型(如字符串、数字、布尔值)的响应式包装。在模板中可以直接使用,但在 JavaScript 中需要通过 .value 属性来访问或修改它的值。

1
2
3
4
5
6
7
8
9
10
11
import { ref } from 'vue';

const count = ref(0);
const userName = '洛可可白';

// 在 JavaScript 中访问
console.log(count.value); // 0
count.value++; // 增加计数

// 在模板中访问
// <div>{{ count }}</div>

2. toRefs

toRefs 是用来将 reactive 对象中的每个属性转换为一个 ref 对象的函数。这样做的好处是,当你在组件的 setup 函数中使用 reactive 创建一个响应式对象,并希望在模板或子组件中访问这些属性时,可以直接使用 ref 而不用担心它们被意外地解构。

1
2
3
4
5
6
7
8
9
10
11
12
13
import { reactive, toRefs } from 'vue';

const state = reactive({
count: 0,
userName: '洛可可白'
});

// 在模板中使用 toRefs 转换后的属性
// <div>{{ count }}</div>
// <div>{{ userName }}</div>

// 将 reactive 对象转换为 ref 对象数组
const { count, userName } = toRefs(state);

3. reactive

reactive 是用来创建响应式对象的方法,适用于处理对象和数组。与 Vue 2 中的 data 函数类似,它允许你定义一个对象,对象中的所有属性都将是响应式的。reactive 对象的属性可以在模板和 JavaScript 中直接访问和修改,不需要 .value

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import { reactive } from 'vue';

const state = reactive({
count: 0,
userName: '洛可可白'
});

// 在 JavaScript 中访问和修改
console.log(state.count); // 0
state.count++; // 增加计数

// 在模板中直接访问
// <div>{{ state.count }}</div>
// <div>{{ state.userName }}</div>

4. 区别和作用

  • ref 适用于基本数据类型的响应式包装,需要通过 .value 访问。
  • toRefs 用于将 reactive 对象的属性转换为 ref 对象,以便在模板或子组件中使用。
  • reactive 适用于创建响应式对象,适用于对象和数组,属性可以直接访问。

在实际开发中,可以根据需要选择使用 reftoRefsreactive。例如,如果你只需要处理基本数据类型,ref 就足够了。如果你需要处理一个对象,并且想要在模板中直接访问对象的属性,那么 reactive 是更好的选择。如果你需要在子组件中访问 reactive 对象的属性,那么使用 toRefs 将这些属性转换为 ref 是必要的。

2. 更多处理响应式数据的方法

在 Vue 3 中,除了 reftoRefsreactive,还有其他几种处理响应式数据的方法和概念:

1. computed

computed 用于创建计算属性,这些属性的值是基于其他响应式数据源派生出来的。计算属性是惰性求值的,只有当它们的依赖项发生改变时才会重新计算。

1
2
3
4
import { ref, computed } from 'vue';

const count = ref(0);
const doubleCount = computed(() => count.value * 2);

2. watch

watch 用于观察响应式数据的变化,并在数据变化时执行特定的函数。这对于执行数据变化后的处理逻辑非常有用。

1
2
3
4
5
6
7
import { ref, watch } from 'vue';

const count = ref(0);

watch(count, (newValue, oldValue) => {
console.log(`Count changed from ${oldValue} to ${newValue}`);
});

3. watchEffect

watchEffect 是一个基于响应式数据源的观察者,它会立即执行一次,并且当响应式数据源变化时重新执行。它通常用于处理那些不需要立即获取值的副作用。

1
2
3
4
5
6
7
import { ref, watchEffect } from 'vue';

const count = ref(0);

watchEffect(() => {
console.log(`Count is now: ${count.value}`);
});

4. onMountedonUnmounted

onMountedonUnmounted 是生命周期钩子,分别在组件挂载后和卸载前执行。它们可以用来处理需要清理的资源或执行一次性的初始化操作。

1
2
3
4
5
6
7
8
9
import { onMounted, onUnmounted } from 'vue';

onMounted(() => {
console.log('Component is mounted!');
});

onUnmounted(() => {
console.log('Component is unmounted!');
});

5. provideinject

provideinject 是用于组件间通信的 API,允许父组件提供数据,子组件注入并使用这些数据。

1
2
3
4
5
6
7
import { provide, inject } from 'vue';

// 父组件
provide('injectedValue', 'This is provided by parent');

// 子组件
const injectedValue = inject('injectedValue');

6. nextTick

nextTick 是一个全局方法,用于在下次 DOM 更新循环结束之后执行延迟回调。在修改了响应式数据之后,通常用于等待 DOM 更新。

1
2
3
4
5
import { nextTick } from 'vue';

nextTick(() => {
console.log('DOM has been updated!');
});

这些方法和概念是 Vue 3 响应式系统的核心部分,它们提供了强大的数据管理能力,使得开发者能够构建高效且易于维护的应用程序。

🎉 往期精彩回顾

主流开发语言和开发环境、程序员如何选择职业赛道?

  • 852阅读 · 27点赞 · 9收藏

VS code搭建C/C++运行环境简单易上手

  • 2803阅读 · 5点赞 · 8收藏

Vue.2&Vue.3项目引入Element-UI教程&踩坑

  • 9284阅读 · 22点赞 · 82收藏

Vue项目引入Echarts可视化图表库教程&踩坑

  • 2209阅读 · 3点赞 · 5收藏

VirtualBox虚拟机搭建CentOS系统教程

  • 4502阅读 · 4点赞 · 32收藏

VS Code上搭建Vue开发环境

  • 10709阅读 · 13点赞 · 66收藏

Color-UI 简介及使用教程

  • 5932阅读 · 2点赞 · 13收藏

Ubuntu系统下C语言开发环境搭建与使用教程

Ubuntu系统下C语言开发环境搭建与使用教程

本指南为您提供了在Ubuntu操作系统上搭建C语言开发环境的详尽步骤。从网络配置到SSH服务安装,再到GCC编译器和Vim编辑器的配置,每一步都配有详细的命令和说明。此外,还包括了用户管理的实用技巧和C语言程序的测试示例。无论是Linux新手还是经验丰富的开发者,本教程都将助您快速上手C语言在Ubuntu上的应用开发。

教程内容

0. 序言

Ubuntu是一个用户友好的Linux发行版,以其易用性和强大的社区支持而闻名。本指南将带您了解如何在Ubuntu上安装和配置C语言开发工具,让您能够轻松编写和编译C程序。

1. 准备工作

在开始之前,确保您的Ubuntu系统已经连接到互联网。使用以下命令检查网络连接:

1
ping www.baidu.com

如果网络未连接,您可能需要重启DHCP和NAT服务。在Windows主机上,可以通过服务管理界面重启这些服务。对于虚拟机,可以使用以下快捷键重启服务:

1
# 重启VMware DHCP Service 和 VMware NAT Service

更新Ubuntu的软件源,以确保您可以访问最新的软件包:

1
sudo apt update

2. 安装SSH

SSH服务允许您远程管理Ubuntu系统。检查SSH服务是否已安装:

1
sudo ps -e | grep ssh

如果未安装,使用以下命令安装:

1
sudo apt install openssh-server

安装完成后,再次检查SSH服务是否正在运行:

1
sudo ps -e | grep ssh

3. 安装GCC和G++

GCC是GNU编译器集合,支持C语言和其他编程语言的编译。安装GCC:

1
sudo apt install gcc

为了编译C++程序,您还需要安装G++:

1
sudo apt install g++

4. 安装Vim

Vim是一个强大的文本编辑器,适合编写代码。安装Vim:

1
sudo apt install vim

5. 测试C语言程序

创建一个简单的C语言程序hello.c文件:

  • 使用vim hello.c命令
  • 键盘输入 i 键,切入到输入模式
  • 粘贴以下代码
  • 键盘输入 Esc 键,退出输入模式
  • 键盘输入 :wq 保存并退出
1
2
3
4
5
6
7
// hello.c - 一个简单的C语言程序,打印"hello world!"
#include <stdio.h>

int main(void) {
printf("hello world!\n");
return 0;
}
  • 使用GCC编译hello.c
1
gcc -Wall hello.c -o hello
  • 运行编译后的程序:
1
./hello

6. 用户管理

Ubuntu默认不允许root用户登录,但您可以设置root密码以进行管理操作:

1
sudo passwd root

切换到root用户:

1
su root

您可以添加新用户:

1
sudo adduser lkkb

或删除用户:

1
sudo deluser lkkb

查看当前系统的所有用户:

1
w

结语

通过本教程,您已经成功在Ubuntu系统上搭建了C语言的开发环境。现在,您可以开始编写和编译自己的C程序了。如果您觉得本指南对您有所帮助,请不吝点赞、收藏或关注,以支持我们继续提供更多高质量的内容。祝您在Ubuntu上的C语言开发之旅顺利!👋🌟🚀

Vue项目中使用ECharts构建交互式中国地图的详细指南

Vue项目中使用ECharts构建交互式中国地图的详细指南

效果图

在这里插入图片描述

在Vue项目中使用ECharts创建中国地图,你需要遵循以下步骤:

步骤 1: 安装 ECharts 和 ECharts 相关插件

首先,确保你的项目中已经安装了ECharts。如果没有,可以使用npm或yarn来安装:

1
npm install echarts --save

步骤 2: 安装中国地图数据

地图数据获取网站:阿里云数据可视化平台

ECharts 使用 JSON 格式的地理数据来渲染地图。你可以在上面这个网站下载中国省级行政区划的 JSON 文件。放入工程的静态文件目录下方。

步骤 3: 在 Vue 组件中引入 ECharts 和 地图数据

在你的Vue组件中,引入ECharts和中国地图数据:

1
2
import * as echarts from "echarts";
import china from "@/assets/china.json"; // 引入中国地图数据

步骤 4: 创建地图实例并配置

在你的Vue组件的mounted生命周期钩子中,创建ECharts实例并配置地图选项:

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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
import { ref, onMounted, getCurrentInstance } from "vue";
import * as echarts from "echarts";
import china from "@/assets/china.json";
const mapData: any = china;
const points = ref([
// 散点图数据
{
name: "广东",
value: [113.266887, 23.133306],
itemStyle: { color: "#00EEFF" },
}, // 广东
]);
const linesData = ref([
{
coords: [
[116.407387, 39.904179],
[113.266887, 23.133306],
],
}, // 北京->广东
]);
const planePath = // 飞机svg
"path://M1705.06,1318.313v-89.254l-319.9-221.799l0.073-208.063c0.521-84.662-26.629-121.796-63.961-121.491c-37.332-0.305-64.482,36.829-63.961,121.491l0.073,208.063l-319.9,221.799v89.254l330.343-157.288l12.238,241.308l-134.449,92.931l0.531,42.034l175.125-42.917l175.125,42.917l0.531-42.034l-134.449-92.931l12.238-241.308L1705.06,1318.313z";
onMounted(() => {
// getCurrentInstance().refs.charts 获取charts节点对象
const Instance: any = getCurrentInstance();
const refCharts: any = Instance.refs.charts;
const charts: any = echarts.init(refCharts);
initCharts(charts);
});
function initCharts(charts: any) {
const option = {
backgroundColor: "#0E2152", // 背景颜色
geo: {
// 地图配置
map: "china",
label: {
// 图形上的文本标签
normal: {
// 通常状态下的样式
show: true,
textStyle: {
color: "#fff",
},
},
emphasis: {
// 鼠标放上去高亮的样式
textStyle: {
color: "#fff",
},
},
},
itemStyle: {
// 地图区域的样式设置
normal: {
// 通常状态下的样式
borderColor: "#5089EC",
borderWidth: 1,
areaColor: {
//地图区域的颜色
type: "radial", // 径向渐变
x: 0.5, // 圆心
y: 0.5, // 圆心
r: 0.8, // 半径
colorStops: [
{
// 0% 处的颜色
offset: 0,
color: "rgba(0, 102, 154, 0)",
},
{
// 100% 处的颜色
offset: 1,
color: "rgba(0, 102, 154, .4)",
},
],
},
},
// 鼠标放上去高亮的样式
emphasis: {
areaColor: "#2386AD",
borderWidth: 0,
},
},
},
series: [
{
// 散点系列数据
type: "effectScatter", // 带有涟漪特效动画的散点(气泡)图
coordinateSystem: "geo", //该系列使用的坐标系:地理坐标系
// 特效类型,目前只支持涟漪特效'ripple',意为“涟漪”
effectType: "ripple",
// 配置何时显示特效。可选'render'和'emphasis' 。
showEffectOn: "render",
rippleEffect: {
// 涟漪特效相关配置。
period: 10, // 动画的周期,秒数。
scale: 4, // 动画中波纹的最大缩放比例。
// 波纹的绘制方式,可选 'stroke' 和 'fill'。
brushType: "fill",
},
zlevel: 1, // 所有图形的 zlevel 值。
data: points.value,
},
{
// 线条系列数据
type: "lines",
zlevel: 2,
symbol: ["none", "arrow"], // 标记的图形: 箭头
symbolSize: 10, // 标记的大小
effect: {
// 线条特效的配置
show: true,
period: 6, // 特效动画的时间,单位s
trailLength: 0, // 特效尾迹的长度。取值[0,1]值越大,尾迹越重
symbol: planePath, // 特效图形的标记 可选'circle'等
symbolSize: 15, // 特效标记的大小
},
lineStyle: {
// 线条样式
normal: {
color: "#93EBF8",
width: 2.5, // 线条宽度
opacity: 0.6, // 尾迹线条透明度
curveness: 0.2, // 尾迹线条曲直度
},
},
data: linesData.value,
},
],
};
// 地图注册,第一个参数的名字必须和option.geo.map一致
echarts.registerMap("china", /**/ mapData);
charts.setOption(option);
}

步骤 5: 在模板中添加地图容器

在你的Vue组件的模板中,添加一个容器来承载地图:

1
2
3
4
5
6
7
8
<template>
<div class="content">
<div
ref="charts"
style="width: 1200px; height: 100vh; margin: 0 auto"
></div>
</div>
</template>

步骤 6: 调整和优化

1
2
3
4
.content {
background-color: #0e2152;
height: 100%;
}

根据你的实际需求,你可以调整地图的样式、颜色、数据等。你还可以为地图添加交互,如点击事件、提示框等。

立体效果

在这里插入图片描述

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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
<template>
<div class="content">
<div class="chart-container">
<div ref="upperChartContainer" class="upper-chart"></div>
<div ref="lowerChartContainer" class="lower-chart"></div>
</div>
</div>
</template>

<script setup lang="ts">
import { ref, onMounted, onBeforeUnmount } from "vue";
import * as echarts from "echarts";
import jiangxi from "@/assets/jiangxi.json";
const mapData: any = jiangxi;
const upperChartContainer = ref<HTMLElement | null>(null);
const lowerChartContainer = ref<HTMLElement | null>(null);
let upperChart: echarts.ECharts | null = null;
let lowerChart: echarts.ECharts | null = null;

onMounted(() => {
upperChart = echarts.init(upperChartContainer.value!);
lowerChart = echarts.init(lowerChartContainer.value!);
initUpperChart();
initLowerChart();
addClickEventListener();
});

onBeforeUnmount(() => {
if (upperChart) {
upperChart.dispose();
upperChart = null;
}
if (lowerChart) {
lowerChart.dispose();
lowerChart = null;
}
});

function initUpperChart() {
echarts.registerMap("jiangxi", mapData);

const option: echarts.EChartsOption = {
backgroundColor: "transparent",
series: [
{
type: "map",
map: "jiangxi",
roam: false,
emphasis: {
label: {
show: true,
},
},
itemStyle: {
areaColor: "#0e2152", // 上层地图颜色
},
data: [],
},
],
};

if (upperChart) {
upperChart.setOption(option);
}
}

function initLowerChart() {
echarts.registerMap("jiangxi", mapData);

const option: echarts.EChartsOption = {
backgroundColor: "transparent",
title: {
text: "地图",
left: "center",
textStyle: {
color: "#000",
fontSize: 28,
},
},
tooltip: {
trigger: "item",
formatter: (params: any) => {
// const { name, center, centroid } = params;
return `地区名称: ${params.name}<br/>ID: ${params.dataIndex}`;
},
},
series: [
{
type: "map",
map: "jiangxi",
roam: false,
emphasis: {
label: {
show: true,
},
},
itemStyle: {
areaColor: "#fff", // 下层地图颜色
},
label: {
show: true,
},
data: [],
},
],
};

if (lowerChart) {
lowerChart.setOption(option);
}
}

function addClickEventListener() {
if (lowerChart) {
lowerChart.on("click", (params: any) => {
if (params.name) {
console.log("点击了上层地图区域:" + params.name);
}
});
}
}
</script>

<style scoped>
.chart-container {
width: 100%;
height: 800px;
}

.upper-chart {
width: 100%;
height: 100vh; /* 总高度为 800 像素,上下距离为 50 像素,因此上层地图高度为 750 像素 */
}

.lower-chart {
width: 100%;
height: 100vh;
transform: translateY(-101vh) translateX(-10px);
}
</style>

以上步骤展示了如何在Vue中使用ECharts创建一个基本的中国地图。你可以根据需要进一步定制地图,例如添加更多的视觉元素、交互功能或者根据实际数据动态更新地图。

米哈游一面前端开发岗面试题,你会做几道?

米哈游一面前端开发岗面试题,你会做几道?

这是一份米哈游前端开发岗位的面试题总结,涵盖了异步编程(async/await)、深拷贝问题、数组判断和手写instanceof方法、React的diff算法在DOM更新中的应用、HTTP请求携带cookie、跨域问题及其解决方案、Webpack的工作流程、使用Webpack的loader处理特定场景问题、ES5的继承和原型链、CommonJS与ES6模块的区别。这些问题旨在评估面试者的前端知识深度和广度,确保程序员具备解决实际开发问题的能力。

1. 自我介绍:

2. async/await的设计和实现:

asyncawait是JavaScript中用于简化异步编程的关键字。async声明一个函数是异步的,而await则用于等待一个Promise解决它的值。async函数隐式返回一个Promise,而await会暂停代码的执行,直到等待的Promise被解决或拒绝。这种设计使得异步代码看起来和同步代码类似,提高了代码的可读性和可维护性。

3. 深拷贝需要注意哪些问题?

深拷贝需要注意以下几个问题:

  • 性能开销:深拷贝会创建对象和其所有子对象的完整副本,这可能导致性能问题。
  • 循环引用:如果对象图中存在循环引用,深拷贝可能导致无限循环。
  • 特殊对象:对于某些特殊对象(如Date、RegExp、Function等),深拷贝可能不会按预期工作。
  • 方法和属性:深拷贝可能不会复制对象的方法和访问器属性。

4. 判断数组的方法有哪些?手写一个instanceof方法:

判断数组的方法包括:

  • Array.isArray()
  • 使用Object.prototype.toString.call()方法
    手写instanceof方法:
1
2
3
function myInstanceOf(constructor, obj) {
return obj instanceof constructor;
}

5. 如何借鉴React diff算法的思想,实现各种情况下树节点的更新:

React的diff算法通过比较新旧虚拟DOM树的差异来更新实际的DOM。借鉴这一思想,可以为树节点创建一个更新函数,该函数会比较新旧节点的数据和子节点,然后递归地更新需要变化的部分,从而实现高效的DOM操作。

6. 怎么让中间页携带上cookie?

要让中间页(例如通过JavaScript发起的HTTP请求)携带cookie,通常需要满足以下条件:

  1. 同源策略:默认情况下,浏览器出于安全考虑,只允许同源的页面携带cookie。如果中间页与请求的资源不是同源的,那么浏览器不会自动携带cookie。

  2. 设置withCredentials属性:当使用XMLHttpRequest或Fetch API发起跨域请求时,可以设置withCredentials属性为true,这样浏览器会在请求中携带cookie。这要求服务器端也设置相应的CORS策略,允许跨域请求携带cookie。

    使用XMLHttpRequest的例子:

    1
    2
    3
    4
    const xhr = new XMLHttpRequest();
    xhr.withCredentials = true;
    xhr.open('GET', 'https://example.com', true);
    xhr.send();

    使用Fetch API的例子:

    1
    2
    3
    4
    fetch('https://example.com', { credentials: 'include' })
    .then(response => response.json())
    .then(data => console.log(data))
    .catch(error => console.log(error));
  3. 服务器端设置CORS:服务器端需要设置适当的CORS(跨源资源共享)响应头,允许特定的外部域携带cookie。这通常通过设置Access-Control-Allow-OriginAccess-Control-Allow-Credentials响应头来实现。

    例如,在Express应用中,可以使用cors中间件来简化这一过程:

    1
    2
    3
    4
    5
    6
    7
    const express = require('express');
    const cors = require('cors');

    const app = express();
    app.use(cors({ origin: 'https://allowed-domain.com', credentials: true }));

    // ... 其他的路由和中间件 ...
  4. 确保cookie设置正确:如果cookie设置有误,如HttpOnly标记,那么即使满足上述条件,JavaScript也无法访问这些cookie,因此它们也不会被发送。

出于安全考虑,只有在确实需要时才应该启用跨域请求携带cookie的功能,并且要确保相关的安全措施得到妥善实施,以防止潜在的安全风险,如CSRF攻击。

7. 说说跨域问题:

跨域问题,又称为同源策略(Same-Origin Policy),是浏览器为了保护用户安全而实施的一种安全机制。当一个域(由协议、域名和端口号组成)的网页尝试请求另一个域的资源时,就会遇到跨域问题。这种限制阻止了网页在没有明确允许的情况下访问或操作其他域的数据,从而避免了潜在的安全威胁,如数据泄露和恶意操作。

跨域问题的原因:

  • 不同源的资源访问:例如,https://www.example.com 尝试访问 https://api.different.com 的资源。
  • 第三方脚本:当你的网页加载了来自其他源的JavaScript脚本时,这些脚本默认无法访问原始文档的DOM或Cookie。
  • AJAX请求:使用XMLHttpRequest或Fetch API发起的请求,如果目标URL与当前文档的URL不同源,请求会因为跨域而被浏览器拦截。

跨域问题的解决方案:

  1. JSONP(JSON with Padding)

    • 利用<script>标签没有跨域限制的特点,可以通过动态创建<script>标签来请求跨域的JSON数据。
    • 服务器返回的数据需要被包裹在一个函数调用中,客户端提供一个回调函数来接收这些数据。
  2. CORS(跨源资源共享)

    • 服务器设置特定的HTTP响应头,如Access-Control-Allow-Origin,来告诉浏览器允许跨域请求。
    • 可以通过设置Access-Control-Allow-MethodsAccess-Control-Allow-Headers来控制允许的HTTP方法和请求头。
  3. 代理服务器

    • 在服务器端设置一个代理服务器,将客户端的请求先发送到代理服务器,由代理服务器转发请求到目标服务器,并将响应返回给客户端。
    • 这样,客户端和代理服务器之间不会有跨域问题,因为它们同源。
  4. PostMessage

    • 这是HTML5引入的一种安全的跨域通信方式,允许不同源的窗口之间传递消息。
    • 通过window.postMessage方法发送消息,并在目标窗口中监听message事件来接收消息。
  5. WebSockets

    • WebSocket协议提供了浏览器和服务器之间的全双工通信渠道,不受限于同源策略。
    • 可以用于建立持久的连接,进行实时数据交换。
  6. 修改document.domain

    • 如果两个域名的主域相同(例如example1.comexample2.com),可以通过设置document.domain='example.com'来实现跨子域的访问。
  7. 使用Location Hash

    • 通过在URL的哈希部分(即URL中的#后面的部分)传递信息,可以绕过同源策略的限制。

注意事项:

  • 在使用跨域解决方案时,需要考虑到安全性,特别是当允许跨域携带Cookie时。
  • CORS是推荐使用的跨域解决方案,因为它提供了更多的控制和灵活性。

跨域问题的处理需要根据具体的应用场景和技术栈来选择合适的方法。在实施任何跨域解决方案时,都应确保遵循最佳安全实践。

8. 讲讲webpack的整个工作流程:

Webpack的工作流程包括:

  • 解析:读取配置文件,初始化参数。
  • 编译:从入口文件开始,递归地构建AST(抽象语法树)。
  • 模块解析:分析模块依赖,递归地找到所有模块。
  • 模块加载:使用对应的loader处理模块。
  • 输出:根据依赖关系和模块内容,生成最终的bundle文件。

9. 有没有用过webpack的loader解决过一些具体的场景问题?

例如使用css-loaderstyle-loader处理CSS文件,或使用babel-loader将ES6代码转换为ES5。

10. ES5怎么实现继承?讲讲对原型链的理解:

ES5中实现继承通常使用构造函数、原型链和混成继承。原型链是JavaScript中实现继承的机制,每个对象都有一个内部属性[[Prototype]],指向它的构造函数的prototype属性。继承通常是通过设置子类型构造函数的原型为父类型实例来实现的。

11. require和import的区别?

require是CommonJS规范中的模块加载方式,通常用于Node.js环境,而import是ES6模块加载的语法。require是同步加载模块,而import是异步加载,且import提供了更清晰的语法和静态分析能力。

12. 有没有什么想问我的?

  • Copyrights © 2022-2024 何福海
  • 访问人数: | 浏览次数:

请我喝杯奶茶吧~

支付宝
微信