Fork me on GitHub

H5实现3D旋转照片墙教程

H5实现3D旋转照片墙教程

在本文中,我们将学习如何使用HTML5、CSS3和JavaScript来创建一个3D旋转照片墙的效果。我们将介绍CSS的transform属性,以及如何使用JavaScript DOM API来实现这个效果。

实现效果

CSS transform属性

CSS的transform属性允许我们对元素进行2D或3D的转换。这包括旋转、缩放、移动和倾斜等操作。在3D转换中,rotateXrotateYtranslateZ是常用的函数,它们分别用于围绕X轴和Y轴旋转以及沿Z轴移动。

实现步骤

1. 创建HTML结构

首先,我们需要创建一个包含图片的HTML结构。

1
2
3
4
5
6
7
<div class="perspective">
<div class="wrap" id="imgwrap">
<img src="image1.jpg" />
<img src="image2.jpg" />
<!-- 更多图片 -->
</div>
</div>

2. 编写CSS样式

接下来,我们使用CSS来设置照片墙的样式。我们给.perspective类添加perspective属性来定义3D空间的深度,给.wrap类添加transform属性来设置初始的3D旋转。

1
2
3
4
5
6
7
8
9
10
.perspective {
perspective: 800px;
}

.wrap {
width: 240px;
height: 140px;
transform: rotateX(-20deg) rotateY(0deg);
transform-style: preserve-3d;
}

3. 使用JavaScript进行动画

现在我们需要使用JavaScript来动态地为每张图片添加3D旋转效果,并使其能够响应用户的鼠标操作。

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
window.onload = function() {
var oImg = document.getElementsByTagName("img");
var len = oImg.length;
var deg = 360 / len;
Array.prototype.forEach.call(oImg, function(ele, index) {
ele.style.transform = "rotateY(" + deg * index + "deg) translateZ(565px)";
ele.style.transition = "1s " + (len - index) * 0.1 + "s";
});
};

document.onmousedown = function(e) {
var oWrap = document.getElementById("imgwrap");
var newX, newY, lastX, lastY, minusX, minusY, rotX = -20, rotY = 0;
lastX = e.clientX;
lastY = e.clientY;
oWrap.onmousemove = function(e) {
newX = e.clientX;
newY = e.clientY;
minusX = newX - lastX;
minusY = newY - lastY;
rotX -= minusY * 0.2;
rotY += minusX * 0.1;
oWrap.style.transform = "rotateX(" + rotX + "deg) rotateY(" + rotY + "deg)";
lastX = newX;
lastY = newY;
}
oWrap.onmouseup = function(e) {
oWrap.onmousemove = null;
}
};

在上述JavaScript代码中,我们首先在页面加载完成后为每张图片设置了一个初始的旋转角度和过渡时间。然后,我们监听mousedown事件来开始旋转,并在mousemove中实时更新旋转角度,从而实现3D旋转的效果。

全部代码

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
<!DOCTYPE html>
<html lang="en" ondragstart="false">

<head>
<meta charset="UTF-8">
<meta name="Keywords" content="">
<meta name="Description" content="">
<title>洛可可白😊3D旋转照片墙</title>
<!-- 层叠样式表 -->
<style type="text/css">
/* 去掉默认效果 */

* {
margin: 0;
padding: 0;
}

body {
transform: scale(0.6);
background: #222;
overflow: hidden;
/* 取消选中 */
user-select: none;
}

.perspective {
/*子元素透视 场景深度*/
perspective: 800px;
}

.wrap {
/* 3d */
width: 240px;
height: 140px;
margin: 100px auto;
position: relative;
/* border: 1px solid red; */
transform: rotateX(-20deg) rotateY(0deg);
transform-style: preserve-3d;
}

.wrap img {
display: block;
/* 绝对定位 */
position: absolute;
width: 100%;
height: 100%;
transform: rotateY(0deg) translateZ(0px);
background: transparent;
box-shadow: 0 0 4px #fff;
border-radius: 5px;
/* webkit */
}
/* 照片底座 */

.wrap p {
width: 1200px;
height: 1200px;
background: -webkit-radial-gradient(center center, 600px 600px, rgba(122, 122, 122, .5), rgba(0, 0, 0, 0));
position: absolute;
border-radius: 50%;
left: 50%;
top: 100%;
margin-left: -600px;
margin-top: -600px;
/* 沿着x轴按倒 */
transform: rotateX(90deg);
}
</style>
</head>

<body>
<!-- 盒子容器 -->
<div class="perspective">
<div class="wrap" id="imgwrap">
<!-- 引入图片值页面 -->
<img src="http://cdn-hw-static2.shanhutech.cn/bizhi/staticwp/202209/bec005059c961095de116266433609ad.jpg" />
<img src="http://cdn-hw-static2.shanhutech.cn/bizhi/staticwp/202209/1d9e79967a0e9ef1bb6869f8d2d27d56.jpg" />
<img src="http://cdn-hw-static2.shanhutech.cn/bizhi/staticwp/202208/40f1faa375cb09993ac56d0100247169--1155426306.jpg" />
<img src="http://cdn-hw-static2.shanhutech.cn/bizhi/staticwp/202208/15383340a19d5e66858afec909e8376a--143226042.jpg" />
<img src="http://cdn-hw-static2.shanhutech.cn/bizhi/staticwp/202208/f80a3cf13ed922ae56c295b6e1750b9f--862862084.jpg" />
<img src="http://cdn-hw-static2.shanhutech.cn/bizhi/staticwp/202208/03e3215ba41e9dda4b612d435dc33749--4017768935.jpg" />
<img src="http://cdn-hw-static2.shanhutech.cn/bizhi/staticwp/202208/e46db6533224e5f49e5a0187c46f5f74--583756240.jpg" />
<img src="http://cdn-hw-static2.shanhutech.cn/bizhi/staticwp/202208/c052bcaad5831e744d80408c7f18309e--1643858281.jpg" />
<img src="http://cdn-hw-static2.shanhutech.cn/bizhi/staticwp/202208/097af3d9e33c26ed741a8df79445f2e9--3623425165.jpg" />
<img src="http://cdn-hw-static2.shanhutech.cn/bizhi/staticwp/202208/fb48e4405d33675142f1f96bf5d13433--1464361656.jpg" />
<img src="http://cdn-hw-static2.shanhutech.cn/bizhi/staticwp/202208/47648ad8b435d8c865a0e1720d67f19e--2484210946.jpg" />
<img src="http://cdn-hw-static2.shanhutech.cn/bizhi/staticwp/202211/1908da2b1afec00022ad3b22c02da692--4079323895.jpg" />
<img src="http://cdn-hw-static2.shanhutech.cn/bizhi/staticwp/202211/dc954cdfc5aac06f8e26c1cdc6d02349--1494553420.jpg" />
<img src="http://cdn-hw-static2.shanhutech.cn/bizhi/staticwp/202211/30d74773eeb77bfc4cf9db10e62a80f2--3057522847.jpg" />
<img src="http://cdn-hw-static2.shanhutech.cn/bizhi/staticwp/202210/b07fa9c46502bbb1d715a7034a3a7c42--77324329.jpg" />
<!-- <p></p> -->
</div>
</div>
<!-- src="JS/photo.js" -->
<script type="text/javascript">
var oImg = document.getElementsByTagName("img")
var len = oImg.length;
console.log(len)
var deg = 360 / len;

var oWrap = document.getElementById("imgwrap");
// var oWrap=document.querySelector('.wrap');

//页面加载完毕在执行的代码
window.onload = function() {
Array.prototype.forEach.call(oImg, function(ele, index, self) {
// 旋转并沿Z轴平移
ele.style.transform = "rotateY(" + deg * index + "deg) translateZ(565px)";
//过渡时间1s
ele.style.transition = "1s " + (len - index) * 0.1 + "s";
});
}
//翻动3D相册
var newX, newY, lastX, lastY, minusX, minusY, rotX = -20,
rotY = 0;

document.onmousedown = function(e) {
// 点击设置初值
lastX = e.clientX;
lastY = e.clientY;

this.onmousemove = function(e) {
newX = e.clientX;
newY = e.clientY;
minusX = newX - lastX;
minusY = newY - lastY;

rotX -= minusY * 0.2;
rotY += minusX * 0.1;
oWrap.style.transform = "rotateX(" + rotX + "deg) rotateY(" + rotY + "deg)";
lastX = newX;
lastY = newY;

}
this.onmouseup = function(e) {
//鼠标松开
this.onmousemove = null; //清除鼠标移动
}
}
</script>
</body>

</html>

结语

通过上述步骤,我们成功地创建了一个3D旋转照片墙的效果。这个实例展示了如何结合HTML、CSS和JavaScript来实现复杂的3D动画效果。通过学习和实践,你可以更深入地理解这些技术,并将其应用到你的项目中。

Element-Plus 实现动态渲染图标教程

Element-Plus 实现动态渲染图标教程

Element-Plus 是 Element UI 的 Vue 3 版本,它提供了一套完整的组件库,用于快速构建企业级的后台产品。在 Element-Plus 中,我们可以使用 <component> 标签来动态渲染组件,这使得在菜单中根据条件动态显示不同的图标成为可能。本文将介绍如何使用 Element-Plus 和 Vue.js 来实现动态渲染图标的功能。

Element-Plus 简介

Element-Plus 是基于 Vue 3 的组件库,它继承了 Element UI 的设计思想和组件结构,同时充分利用了 Vue 3 的新特性,如 Composition API,以提供更加灵活和强大的组件使用体验。Element-Plus 支持自定义主题,提供了丰富的文档和示例,使得开发者能够快速上手并构建高质量的用户界面。

Vue.js 简介

Vue.js 是一个渐进式的 JavaScript 框架,用于构建用户界面。Vue 的核心库只关注视图层,易于上手,同时也能够配合其他库或现有项目使用。Vue 的响应式数据绑定和虚拟 DOM 技术使得状态管理和视图更新变得简单高效。

实现效果

实现步骤

1. 安装 Element-Plus

首先,确保你的项目已经安装了 Vue 3,然后通过 npm 或 yarn 安装 Element-Plus:

1
2
3
npm install element-plus --save
# 或者
yarn add element-plus

2. 引入 Element-Plus

在你的主文件(通常是 main.jsmain.ts)中引入 Element-Plus 并注册为全局可用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import {createApp} from 'vue'
import {createPinia} from 'pinia'

import App from './App.vue'
import router from './router'
const app = createApp(App)

import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import 'dayjs/locale/zh-cn'
import zhCn from 'element-plus/dist/locale/zh-cn.mjs'

app.use(ElementPlus, {locale: zhCn})
app.use(createPinia())
app.use(router)
app.mount('#app')

3. 安装导入图标组件

在你的项目中定义 SVG 图标组件,例如:

1
2
3
4
5
6
7
8
# 选择一个你喜欢的包管理器

# NPM
$ npm install @element-plus/icons-vue
# Yarn
$ yarn add @element-plus/icons-vue
# pnpm
$ pnpm install @element-plus/icons-vue
1
2
3
4
5
const app = createApp(App)
import * as ElementPlusIconsVue from '@element-plus/icons-vue'
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
app.component(key, component)
}

4. 使用动态渲染图标

在你的 Vue 组件中使用 Element-Plus 提供的 <el-sub-menu> 组件来创建下拉菜单,并使用 <component> 标签来动态渲染图标。

1
2
3
4
5
6
7
8
9
10
11
12
<!--  item.id+'' 解决Invalid prop: type check failed for prop "index". Expected String with value "1", got Number with value 1.   -->
<el-sub-menu v-for="(item,index) in menuAsc" :index="item.id+''">
<template #title>
<!-- 关键代码 -->
<component class="icons" :is="item.icon"></component>
<span>{{ item.name }}</span>
</template>
<el-menu-item v-for="(i,num) in menuAsc[index].children" :index="menuAsc[index].children[num].id+''"
@click="routerTo(i)">
{{ i.name }}
</el-menu-item>
</el-sub-menu>

在这个例子中,menuAsc 是一个数组,包含了菜单项和它们的子菜单。每个菜单项都有一个 icon 属性,该属性是一个组件的名称,用于指定要渲染的图标。<component> 标签的 :is 属性用于动态绑定组件名称,从而实现根据条件渲染不同的图标。

5. 样式调整

为了确保图标正确显示,我们可以添加一些 CSS 样式:

1
2
3
4
5
svg {
width: 20px;
height: 20px;
margin-right: 5px;
}

结语

通过上述步骤,我们成功地在 Element-Plus 的菜单中实现了动态渲染图标的功能。这个实例展示了如何使用 Element-Plus 和 Vue.js 来动态渲染组件,并自定义菜单项的图标。通过学习和实践,你可以更深入地理解 Element-Plus 和 Vue.js 的强大功能,以及如何将它们应用到实际的开发工作中。

MyBatis-Plus分页接口实现教程:Spring Boot中如何编写分页查询

MyBatis-Plus分页接口实现教程:Spring Boot中如何编写分页查询

MyBatis-Plus 是一个 MyBatis 的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。它提供了强大的分页插件,可以轻松实现分页查询的功能。在 Spring Boot 项目中使用 MyBatis-Plus 可以大大简化分页逻辑的编写。本文将介绍如何在 Spring Boot 项目中使用 MyBatis-Plus 实现分页接口。

MyBatis-Plus 简介

MyBatis-Plus(简称 MP)是 MyBatis 的一个增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。它提供了代码生成器、分页插件、性能分析插件、全局通用操作、MetaObject 等一系列功能,使得 MyBatis 变得更加易用。

Spring Boot 简介

Spring Boot 是 Spring 的一个模块,用于简化新 Spring 应用的初始搭建以及开发过程。Spring Boot 旨在简化配置,通过约定大于配置的原则,提供了大量的默认配置,使得开发者能够快速启动和部署 Spring 应用。

实现步骤

1. 添加 MyBatis-Plus 依赖

pom.xml 文件中添加 MyBatis-Plus 的依赖:

1
2
3
4
5
6
<!--mybatis-plus-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.3.1</version>
</dependency>

image-20240327015151458

Springboot只能使用3.1.5及以下版本!!!

2. 配置分页插件

在 Spring Boot 的配置类中添加分页插件的配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
//@MapperScan("com.example.demo.mapper")
public class MybatisPlusConfig {

/**
* 新增分页拦截器,并设置数据库类型为mysql
*
* @return
*/
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
}

3. 创建服务层接口

创建一个服务层接口,用于定义分页查询的方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@Service
public class UserServiceImpl implements UserService {

@Autowired
private UserMapper userMapper;

@Override
public Result listPageUser(@RequestParam Integer page, @RequestParam Integer pageSize) {
//分页参数
Page<UserEntity> rowPage = new Page<>(page, pageSize);
//queryWrapper组装查询where条件
LambdaQueryWrapper<UserEntity> queryWrapper = new LambdaQueryWrapper<>();
rowPage = userMapper.selectPage(rowPage, queryWrapper);
return Result.success("数据列表", rowPage);
}
}

4. 创建控制器

创建一个控制器,用于处理 HTTP 请求并调用服务层的分页查询方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
@RestController
@RequestMapping("/user")
public class UserController {

@Autowired
private UserServiceImpl userServiceImpl;

@PostMapping("/listPage")
@Operation(summary = "列表分页")
public Result listPageUser(@RequestParam Integer page, @RequestParam Integer pageSize) {
return userServiceImpl.listPageUser(page, pageSize);
}
}

5. 运行应用并测试

启动 Spring Boot 应用,并通过 Postman 或其他 API 测试工具发送 POST 请求到 /user/listPage 端点,传递 pagepageSize 参数,即可测试分页查询功能。

6.全部代码

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
import com.alibaba.excel.EasyExcel;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.common.req.IdParam;
import com.example.common.resp.Result;
import com.example.system.entity.UserEntity;
import com.example.system.mapper.UserMapper;
import com.example.system.resp.LoginResp;
import com.example.system.service.UserService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.Objects;

/**
* <p>
* 用户表 前端控制器
* </p>
*
* @author he
* @since 2024-03-23
*/
@Tag(name = "用户")
@RestController
@RequestMapping("/userEntity")
public class UserController {

@Autowired
private UserMapper userMapper;
@Autowired
private UserService userService;
private final String id = "User_id";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

@Operation(summary = "列表")
@PostMapping("/list")
public Result listUser() {
return Result.success("数据列表", userService.list());
}

@Operation(summary = "存在")
@PostMapping("/exist")
public Result existUser(@RequestBody @Validated IdParam param) {
QueryWrapper<UserEntity> wrapper = new QueryWrapper<>();
wrapper.eq(id.toLowerCase(Locale.ROOT), param.getId());
long count = userService.count(wrapper);
if (count == 0) return Result.success("ID不存在", false);
return Result.success("ID已存在", true);
}

@Operation(summary = "保存")
@PostMapping("/insert")
public Result insertUser(@RequestBody @Validated UserEntity param) {
QueryWrapper<UserEntity> wrapper = new QueryWrapper<>();
wrapper.eq(id.toLowerCase(Locale.ROOT), param.getId());
if (userService.count(wrapper) != 0) return Result.failure("ID已存在", sdf.format(new Date()));
if (userService.save(param)) return Result.success("保存成功", sdf.format(new Date()));
return Result.failure("保存失败", sdf.format(new Date()));
}

@Operation(summary = "删除")
@PostMapping("/delete")
public Result deleteUser(@RequestBody @Validated IdParam param) {
QueryWrapper<UserEntity> wrapper = new QueryWrapper<>();
wrapper.eq(id.toLowerCase(Locale.ROOT), param.getId());
if (userService.count(wrapper) == 0) return Result.failure("ID不存在", param.getId());
if (userService.remove(wrapper)) return Result.success("删除成功", param.getId());
return Result.failure("删除失败", param.getId());
}

@Operation(summary = "修改")
@PostMapping("/update")
public Result updateUser(@RequestBody @Validated UserEntity param) {
QueryWrapper<UserEntity> wrapper = new QueryWrapper<>();
wrapper.eq(id.toLowerCase(Locale.ROOT), param.getId());
if (userService.count(wrapper) == 0) return Result.failure("ID不存在", sdf.format(new Date()));
if (userService.updateById(param)) return Result.success("修改成功", sdf.format(new Date()));
return Result.failure("修改失败", sdf.format(new Date()));
}

@Operation(summary = "查询")
@PostMapping("/select")
public Result selectUser(@RequestBody @Validated IdParam param) {
QueryWrapper<UserEntity> wrapper = new QueryWrapper<>();
wrapper.eq(id.toLowerCase(Locale.ROOT), param.getId());
if (userService.count(wrapper) == 0) return Result.failure("ID不存在", param.getId());
return Result.success(userService.getOne(wrapper));
}

@Operation(summary = "查询byAcc")
@PostMapping("/selectByAcc/{param}")
public Result selectUserByAcc(@PathVariable @Validated String param) {
QueryWrapper<UserEntity> wrapper = new QueryWrapper<>();
String acc = "User_acc";
wrapper.eq(acc.toLowerCase(Locale.ROOT), param);
if (userService.count(wrapper) == 0) return Result.failure("账号不存在", sdf.format(new Date()));
return Result.success(userService.getOne(wrapper));
}

@Operation(summary = "列表分页")
@PostMapping("/listPage")
public Result listPageUser(@RequestParam Integer page, @RequestParam Integer pageSize) {
//分页参数
Page<UserEntity> rowPage = new Page(page, pageSize);
//queryWrapper组装查询where条件
LambdaQueryWrapper<UserEntity> queryWrapper = new LambdaQueryWrapper<>();
rowPage = userMapper.selectPage(rowPage, queryWrapper);
return Result.success("数据列表", rowPage);
}

@Operation(summary = "导出数据")
@PostMapping("exportExcel")
public void exportExcelUser(HttpServletResponse response) throws IOException {
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setCharacterEncoding("utf-8");
String fileName = URLEncoder.encode("轮播图", StandardCharsets.UTF_8).replaceAll("\\+", "%20");
List<UserEntity> list = userService.list();
response.setHeader("Content-disposition", "attachment;filename*=" + fileName + ".xlsx");
EasyExcel.write(response.getOutputStream(), UserEntity.class).sheet("轮播图").doWrite(list);
}

@Operation(summary = "导入数据")
@PostMapping("/importExcel")
public Result importExcelUser(MultipartFile file) {
try {
//获取文件的输入流
InputStream inputStream = file.getInputStream();
List<UserEntity> list = EasyExcel.read(inputStream) //调用read方法
//注册自定义监听器,字段校验可以在监听器内实现
//.registerReadListener(new UserListener())
.head(UserEntity.class) //对应导入的实体类
.sheet(0) //导入数据的sheet页编号,0代表第一个sheet页,如果不填,则会导入所有sheet页的数据
.headRowNumber(1) //列表头行数,1代表列表头有1行,第二行开始为数据行
.doReadSync();//开始读Excel,返回一个List<T>集合,继续后续入库操作
//模拟导入数据库操作
for (UserEntity entity : list) {
userService.saveOrUpdate(entity);
}
return Result.success("导入成功", sdf.format(new Date()));
} catch (IOException exception) {
throw new RuntimeException(exception);
}
}

}

结语

通过上述步骤,我们在 Spring Boot 项目中使用 MyBatis-Plus 实现了一个分页查询接口。MyBatis-Plus 提供的分页插件极大地简化了分页逻辑的编写,使得开发者能够更专注于业务逻辑的实现。通过学习和实践,你可以更深入地理解 MyBatis-Plus 和 Spring Boot 的强大功能,以及如何将它们应用到实际的开发工作中。

Element-Plus下拉菜单边框去除教程

Element-Plus下拉菜单边框去除教程

好久没更新关于Vue的内容了,正好记录一下今天开发中遇到的一个小Bug😁😊😊

去除边框前:

去除边框后:

Element-Plus 是 Element UI 的 Vue 3 版本,它提供了一套完整的组件库,用于快速构建企业级的后台产品。在使用 Element-Plus 进行开发时,我们可能会遇到需要自定义组件样式的情况,比如去除下拉框在聚焦时的默认边框。本文将介绍如何使用 CSS 来去除 Element-Plus 下拉框的边框,并简要介绍 Element-Plus 以及 Vue 的相关概念。

Element-Plus 简介

Element-Plus 是基于 Vue 3 的组件库,它继承了 Element UI 的设计思想和组件结构,同时充分利用了 Vue 3 的新特性,如 Composition API,以提供更加灵活和强大的组件使用体验。Element-Plus 支持自定义主题,提供了丰富的文档和示例,使得开发者能够快速上手并构建高质量的用户界面。

Vue.js 简介

Vue.js 是一个渐进式的 JavaScript 框架,用于构建用户界面。Vue 的核心库只关注视图层,易于上手,同时也能够配合其他库或现有项目使用。Vue 的响应式数据绑定和虚拟 DOM 技术使得状态管理和视图更新变得简单高效。

实现步骤

1. 安装 Element-Plus

首先,确保你的项目已经安装了 Vue 3,然后通过 npm 或 yarn 安装 Element-Plus:

1
2
3
npm install element-plus --save
# 或者
yarn add element-plus

2. 引入 Element-Plus

在你的主文件(通常是 main.jsmain.ts)中引入 Element-Plus 并注册为全局可用:

1
2
3
4
5
6
7
import { createApp } from 'vue';
import ElementPlus from 'element-plus';
import 'element-plus/dist/index.css';

const app = createApp(App);
app.use(ElementPlus);
app.mount('#app');

3. 使用 Element-Plus 组件

在你的 Vue 组件中使用 Element-Plus 提供的下拉框(Select)组件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<template>
<el-dropdown>
<el-avatar :size="45" shape="square" src="https://cube.elemecdn.com/0/88/03b0d39583f48206768a7534e55bcpng.png"/>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item>个人中心</el-dropdown-item>
<el-dropdown-item>修改信息</el-dropdown-item>
<el-dropdown-item>安全退出</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</template>

<script>
export default {
data() {
return {
value: '',
};
},
};
</script>

4. 去除边框样式

为了去除下拉框在聚焦时的边框,我们需要在项目的样式文件中添加 CSS 规则。Vue 3 引入了 :deep() 伪类,它可以用来穿透组件的样式作用域,修改子组件的样式。

1
2
3
:deep(.el-tooltip__trigger:focus-visible) {
outline: unset;
}

上述样式规则将移除 el-tooltip__trigger 类(通常是下拉框的触发元素)在聚焦时的默认边框。:focus-visible 伪类确保只有在用户通过键盘聚焦元素时才会应用样式,这样鼠标聚焦时的默认样式不会被影响。

结语

通过上述步骤,我们成功地去除了 Element-Plus 下拉框在聚焦时的边框样式。这个简单的实例展示了如何在 Vue 3 项目中使用 Element-Plus 组件库,并自定义组件的样式。通过学习和实践,你可以更深入地理解 Vue 和 Element-Plus 的强大功能,以及如何将它们应用到实际的开发工作中。

Web实现猜数字游戏:JavaScript DOM基础与实例教程

Web实现猜数字游戏:JavaScript DOM基础与实例教程

猜数字游戏是一个简单而经典的游戏,玩家需要猜测由系统随机生成的一个数字。在本教程中,我们将学习如何使用JavaScript和DOM来实现这个网页版的猜数字游戏,并介绍相关的JavaScript DOM基础知识。

JavaScript DOM基础

DOM(Document Object Model)是HTML文档的编程接口,它允许我们通过JavaScript访问和操作网页的元素。在JavaScript中,我们可以使用DOM API来选取元素、更改内容、绑定事件等。

体验地址

http://8.210.131.139/GuessNumber.html

实例:猜数字游戏

创建HTML结构

首先,我们需要创建一个包含游戏输入区域、结果显示和再玩一次按钮的HTML结构。

1
2
3
4
5
6
7
8
9
10
11
<div class="container">
<h1>猜数字游戏</h1>
<div class="input-group">
<label for="guess">请猜一个1~100的整数:</label>
<input type="text" id="guess" />
<button id="submit">提交</button>
</div>
<div class="result"></div>
<div class="message"></div>
<button id="play-again" class="play-again" style="display: none">再玩一次</button>
</div>

美化样式

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
* {
font-family: Arial, sans-serif;
box-sizing: border-box;
}

.container {
margin: 50px auto;
max-width: 600px;
text-align: center;
background-color: #d1d1d1;
padding: 30px;
border-radius: 10px;
}

h1 {
font-size: 32px;
margin-bottom: 20px;
}

.input-group {
margin-bottom: 20px;
}

label {
display: block;
margin-bottom: 5px;
}

input[type="text"] {
font-size: 18px;
padding: 5px;
width: 200px;
border: 1px solid #ccc;
}

button {
font-size: 18px;
padding: 5px 10px;
background-color: #007bff;
color: #fff;
border: none;
cursor: pointer;
}

button:hover {
background-color: #0062cc;
}

.result {
font-size: 24px;
margin-bottom: 20px;
}

.message {
font-size: 18px;
margin-bottom: 20px;
}

.play-again {
font-size: 18px;
padding: 5px 10px;
background-color: #007bff;
color: #fff;
border: none;
cursor: pointer;
margin: 0 auto;
}

.play-again:hover {
background-color: #0062cc;
}

编写JavaScript逻辑

初始化游戏

在JavaScript中,我们首先定义一个变量来存储随机生成的答案。

1
var answer = Math.floor(Math.random() * 100) + 1;

获取页面元素

使用document.getElementByIddocument.querySelector来获取页面上的元素。

1
2
3
4
5
var input = document.getElementById("guess");
var submitBtn = document.getElementById("submit");
var result = document.querySelector(".result");
var message = document.querySelector(".message");
var playAgainBtn = document.getElementById("play-again");

处理提交事件

为提交按钮绑定点击事件,获取用户输入的数字,并与答案比较。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
submitBtn.addEventListener("click", function () {
var guess = parseInt(input.value);
if (isNaN(guess) || guess < 1 || guess > 100) {
result.textContent = "";
message.textContent = "请输入1~100之间的整数!";
} else {
if (guess === answer) {
result.textContent = "恭喜你,猜对了!";
message.textContent = "";
playAgainBtn.style.display = "block";
submitBtn.disabled = true;
} else {
result.textContent = "";
if (guess < answer) {
message.textContent = "太小了,请继续猜!";
} else {
message.textContent = "太大了,请继续猜!";
}
}
}
});

处理再玩一次事件

为再玩一次按钮绑定点击事件,重置游戏状态并允许用户重新开始游戏。

1
2
3
4
5
6
7
8
playAgainBtn.addEventListener("click", function () {
answer = Math.floor(Math.random() * 100) + 1;
input.value = "";
result.textContent = "";
message.textContent = "";
playAgainBtn.style.display = "none";
submitBtn.disabled = false;
});

全部代码

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
<!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>洛可可白😁猜数字</title>
<style>
* {
font-family: Arial, sans-serif;
box-sizing: border-box;
}

.container {
margin: 50px auto;
max-width: 600px;
text-align: center;
background-color: #d1d1d1;
padding: 30px;
border-radius: 10px;
}

h1 {
font-size: 32px;
margin-bottom: 20px;
}

.input-group {
margin-bottom: 20px;
}

label {
display: block;
margin-bottom: 5px;
}

input[type="text"] {
font-size: 18px;
padding: 5px;
width: 200px;
border: 1px solid #ccc;
}

button {
font-size: 18px;
padding: 5px 10px;
background-color: #007bff;
color: #fff;
border: none;
cursor: pointer;
}

button:hover {
background-color: #0062cc;
}

.result {
font-size: 24px;
margin-bottom: 20px;
}

.message {
font-size: 18px;
margin-bottom: 20px;
}

.play-again {
font-size: 18px;
padding: 5px 10px;
background-color: #007bff;
color: #fff;
border: none;
cursor: pointer;
margin: 0 auto;
}

.play-again:hover {
background-color: #0062cc;
}
</style>
</head>

<body>
<div class="container">
<h1>猜数字游戏</h1>
<div class="input-group">
<label for="guess">请猜一个1~100的整数:</label>
<input type="text" id="guess" />
<button id="submit">提交</button>
</div>
<div class="result"></div>
<div class="message"></div>
<button id="play-again" class="play-again" style="display: none">
再玩一次
</button>
</div>

<script>
// 生成随机数(1~100之间)
var answer = Math.floor(Math.random() * 100) + 1;

// 获取页面元素
var input = document.getElementById("guess");
var submitBtn = document.getElementById("submit");
var result = document.querySelector(".result");
var message = document.querySelector(".message");
var playAgainBtn = document.getElementById("play-again");

// 处理提交事件
submitBtn.addEventListener("click", function () {
// 获取用户输入的数字
var guess = parseInt(input.value);

// 验证用户输入的数字是否合法
if (isNaN(guess) || guess < 1 || guess > 100) {
result.textContent = "";
message.textContent = "请输入1~100之间的整数!";
return;
}

// 比较用户输入的数字和答案
if (guess === answer) {
result.textContent = "恭喜你,猜对了!";
message.textContent = "";
playAgainBtn.style.display = "block";
submitBtn.disabled = true;
} else if (guess < answer) {
result.textContent = "";
message.textContent = "太小了,请继续猜!";
} else {
result.textContent = "";
message.textContent = "太大了,请继续猜!";
}
});

// 处理再玩一次事件
playAgainBtn.addEventListener("click", function () {
// 重新生成随机数
answer = Math.floor(Math.random() * 100) + 1;

// 清空输入框和提示信息
input.value = "";
result.textContent = "";
message.textContent = "";

// 隐藏再玩一次按钮,启用提交按钮
playAgainBtn.style.display = "none";
submitBtn.disabled = false;
});
</script>
</body>
</html>

结语

通过上述步骤,我们实现了一个简单的猜数字游戏。这个实例展示了如何使用JavaScript DOM API来操作HTML元素,并响应用户事件。通过这个项目,你可以更好地理解DOM操作的基本概念和方法,以及如何在实际项目中应用它们。猜数字游戏是一个入门级的编程项目,适合初学者练习和提升编程技能。

Web实现名言生成器:JavaScript DOM基础与实例教程

Web实现名言生成器:JavaScript DOM基础与实例教程

名言生成器是一个简单而有趣的Web应用,它可以随机显示历史上著名人物的名言。通过这个教程,我们将学习如何使用JavaScript DOM API来实现这个功能,并介绍相关的JavaScript DOM基础知识。

JavaScript DOM基础

DOM(Document Object Model)是HTML文档的编程接口,它允许我们通过JavaScript访问和操作网页元素。在JavaScript中,我们可以使用DOM API来获取元素、修改内容、绑定事件等。

实例:名言生成器

实现效果

体验地址:

http://8.210.131.139/QuoteGenerator.html

创建HTML结构

首先,我们需要创建一个包含名言显示区域和生成按钮的HTML结构。

1
2
3
4
5
6
<div class="quote-box">
<p class="text">这是名言部分</p>
<p class="author">我是作者</p>
<button id="new-quote">生成名言</button>
<a class="tweet-quote" href="https://blink.csdn.net/">分享到 CSDN&Blink</a>
</div>

编写JavaScript逻辑

初始化名言列表

在JavaScript中,我们首先定义一个包含名言和作者的数组。

1
2
3
4
5
6
7
8
9
10
11
const quotes = [
{
quote: "生命不止,奋斗不息。",
author: "方志敏",
},
{
quote: "知识就是力量。",
author: "李约瑟",
},
// ... 更多名言和作者列表 ...
];

获取随机名言

定义getRandomQuote函数来从名言列表中随机获取一条名言。

1
2
3
4
function getRandomQuote() {
const index = Math.floor(Math.random() * quotes.length);
return quotes[index];
}

更新名言显示

定义一个事件监听器,当用户点击“生成名言”按钮时,调用getRandomQuote函数获取新的名言,并更新页面上的内容。

1
2
3
4
5
6
7
document.querySelector("#new-quote").addEventListener("click", function () {
const quote = getRandomQuote();
const textElement = document.querySelector(".text");
const authorElement = document.querySelector(".author");
textElement.innerText = quote.quote;
authorElement.innerText = `- ${quote.author}`;
});

样式美化

为了让名言生成器看起来更美观,我们可以添加一些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
/* ... 样式代码 ... */
.quote-box {
width: 500px;
margin: 100px auto;
padding: 30px;
border-radius: 5px;
box-shadow: 0px 0px 10px 2px rgba(0, 0, 0, 0.2);
}

.text {
font-size: 24px;
font-style: italic;
margin-bottom: 20px;
}

.author {
font-size: 18px;
text-align: right;
}

#new-quote {
background-color: #4caf50;
color: #fff;
border: none;
padding: 10px 20px;
margin-top: 20px;
border-radius: 5px;
cursor: pointer;
}

.tweet-quote {
display: block;
text-align: right;
margin-top: 10px;
color: #4caf50;
}

全部代码

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
<!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>洛可可白😁名言生成器</title>
<style>
.quote-box {
width: 500px;
margin: 100px auto;
padding: 30px;
border-radius: 5px;
box-shadow: 0px 0px 10px 2px rgba(0, 0, 0, 0.2);
}

.text {
font-size: 24px;
font-style: italic;
margin-bottom: 20px;
}

.author {
font-size: 18px;
text-align: right;
}

#new-quote {
background-color: #4caf50;
color: #fff;
border: none;
padding: 10px 20px;
margin-top: 20px;
border-radius: 5px;
cursor: pointer;
}

.tweet-quote {
display: block;
text-align: right;
margin-top: 10px;
color: #4caf50;
}
</style>
</head>

<body>
<div class="quote-box">
<p class="text">这是文言部分</p>
<p class="author">我是作者</p>
<button id="new-quote">生成名言</button>
<a class="tweet-quote" href="https://blink.csdn.net/"
>分享到 CSDN&Blink</a
>
</div>
</body>

<script>
const quotes = [
{
quote: "生命不止,奋斗不息。",
author: "方志敏",
},
{
quote: "知识就是力量。",
author: "李约瑟",
},
{
quote: "先苦后甜,后苦变甜;先甜后苦,后甜变苦。",
author: "林语堂",
},
{
quote: "成功是一份耕耘,而非一次得手。",
author: "贾平凹",
},
{
quote: "宝剑锋从磨砺出,梅花香自苦寒来。",
author: "陆游",
},
{
quote: "宝剑不磨,其锋不利;人不学习,其智不明。",
author: "李光耀",
},
{
quote: "一份耕耘,一份收获;一份付出,一份回报。",
author: "王阳明",
},
{
quote: "只要功夫深,铁杵磨成针。",
author: "李白",
},
{
quote: "有志者事竟成。",
author: "龚自珍",
},
{
quote: "天道酬勤。",
author: "韩愈",
},
{
quote: "千里之行始于足下。",
author: "老子",
},
{
quote: "路漫漫其修远兮,吾将上下而求索。",
author: "屈原",
},
{
quote: "读书破万卷,下笔如有神。",
author: "李白",
},
{
quote: "吃一堑,长一智。",
author: "佚名",
},
{
quote: "先天下之忧而忧,后天下之乐而乐。",
author: "范仲淹",
},
{
quote: "一寸光阴一寸金,寸金难买寸光阴。",
author: "陈毅",
},
{
quote: "不积跬步,无以至千里;不积小流,无以成江海。",
author: "荀子",
},
{
quote: "前事不忘,后事之师。",
author: "司马迁",
},
{
quote: "生命中最大的浪费是把时间浪费在了等待上。",
author: "李开复",
},
];

function getRandomQuote() {
const index = Math.floor(Math.random() * quotes.length);
return quotes[index];
}
document.querySelector("#new-quote").addEventListener("click", function () {
const quote = getRandomQuote();
const textElement = document.querySelector(".text");
const authorElement = document.querySelector(".author");
textElement.innerText = quote.quote;
authorElement.innerText = `- ${quote.author}`;
});
</script>
</html>

结语

通过上述步骤,我们实现了一个简单的名言生成器。这个实例展示了如何使用JavaScript DOM API来操作HTML元素,并响应用户事件。通过这个项目,你可以更好地理解DOM操作的基本概念和方法,以及如何在实际项目中应用它们。名言生成器是一个入门级的编程项目,适合初学者练习和提升编程技能。

Web实现井字棋游戏:JavaScript DOM基础与实例教程

Web实现井字棋游戏:JavaScript DOM基础与实例教程

井字棋(Tic-Tac-Toe)是一款经典的两人对战游戏,适合作为学习JavaScript DOM操作的实践项目。本文将通过一个简单的实例,介绍如何使用JavaScript和DOM API来实现一个井字棋游戏,并讲解相关的JavaScript DOM基础知识。

JavaScript DOM基础

DOM(Document Object Model)是HTML和XML文档的编程接口。在JavaScript中,DOM提供了一种结构化的方式来表示和操作网页内容。通过DOM,我们可以获取元素、修改样式、绑定事件等。

实例:井字棋游戏

实现效果

体验地址:

http://8.210.131.139/Tictactoe.html

创建HTML结构

首先,我们需要创建一个包含游戏板和结果显示的HTML结构。

1
2
3
4
5
6
<div class="board">
<!-- 游戏格子 -->
<div class="cell"></div>
<!-- ... 其他格子 ... -->
</div>
<div id="result"></div>

编写JavaScript逻辑

初始化游戏

在JavaScript中,我们首先定义游戏板的状态、玩家当前回合以及游戏是否结束的状态。

1
2
3
const board = ["", "", "", "", "", "", "", "", ""];
let currentPlayer = "X";
let gameEnded = false;

事件绑定

为每个游戏格子绑定点击事件,以便在玩家点击时更新游戏状态。

1
2
3
4
const cells = document.querySelectorAll(".cell");
cells.forEach((cell, index) => {
cell.addEventListener("click", () => updateGameState(index));
});

更新游戏状态

定义updateGameState函数来处理玩家的每一步操作,包括更新棋盘状态、检查胜利条件、切换玩家回合以及在适当的时候结束游戏。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// ... 更新棋盘逻辑 ...
function updateGameState(cellIndex) {
if (!gameEnded && board[cellIndex] === "") {
board[cellIndex] = currentPlayer;
renderBoard();
if (checkWin(currentPlayer)) {
endGame("Player " + currentPlayer + " wins!");
} else if (checkDraw()) {
endGame("It's a draw!");
} else {
currentPlayer = currentPlayer === "X" ? "O" : "X";
if (currentPlayer === "O") {
setTimeout(makeComputerMove, 500);
}
}
}
}

检查胜利条件和平局

在每一步操作后,使用checkWincheckDraw函数来检查是否有玩家获胜或游戏是否平局。

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
// ... 检查胜利逻辑 ...
function checkWin(player) {
const winningCombinations = [
[0, 1, 2],
[3, 4, 5],
[6, 7, 8],
[0, 3, 6],
[1, 4, 7],
[2, 5, 8],
[0, 4, 8],
[2, 4, 6],
];

for (let i = 0; i < winningCombinations.length; i++) {
const [a, b, c] = winningCombinations[i];
if (board[a] === player && board[b] === player && board[c] === player) {
return true;
}
}
return false;
}

// ... 检查平局逻辑 ...
function checkDraw() {
return board.every((cell) => cell !== "");
}

电脑AI移动

在玩家为”O”时,电脑AI需要进行自动移动。makeComputerMove函数负责实现这一逻辑。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// ... 电脑AI移动逻辑 ...
function makeComputerMove() {
const emptyCells = board.reduce((acc, cell, index) => {
if (cell === "") {
acc.push(index);
}
return acc;
}, []);
if (emptyCells.length > 0) {
const randomIndex = Math.floor(Math.random() * emptyCells.length);
const computerMove = emptyCells[randomIndex];
updateGameState(computerMove);
}
}

渲染棋盘

使用renderBoard函数将棋盘状态更新到页面上。

1
2
3
4
5
6
// ... 渲染棋盘逻辑 ...
function renderBoard() {
for (let i = 0; i < cells.length; i++) {
cells[i].textContent = board[i];
}
}

重置游戏

提供一个重置游戏的函数,以便玩家可以重新开始新游戏。

1
2
3
4
5
6
7
8
// ... 重置游戏逻辑 ...
function resetGame() {
board.fill("");
currentPlayer = "X";
gameEnded = false;
resultElement.textContent = "";
renderBoard();
}

全部代码

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
<!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>洛可可白😁井字棋游戏</title>

<style>
.board {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-template-rows: repeat(3, 1fr);
gap: 5px;
width: 300px;
height: 300px;
margin: 0 auto;
border: 1px solid #ccc;
padding: 5px;
}

.cell {
display: flex;
align-items: center;
justify-content: center;
font-size: 24px;
font-weight: bold;
background-color: #f2f2f2;
cursor: pointer;
}

#result {
text-align: center;
font-size: 24px;
margin-top: 20px;
}
</style>
</head>

<body>
<div class="board">
<div class="cell"></div>
<div class="cell"></div>
<div class="cell"></div>
<div class="cell"></div>
<div class="cell"></div>
<div class="cell"></div>
<div class="cell"></div>
<div class="cell"></div>
<div class="cell"></div>
</div>
<div id="result"></div>
</body>

<script>
const board = ["", "", "", "", "", "", "", "", ""];
const cells = document.querySelectorAll(".cell");
const resultElement = document.getElementById("result");
let currentPlayer = "X";
let gameEnded = false;

function updateGameState(cellIndex) {
if (!gameEnded && board[cellIndex] === "") {
board[cellIndex] = currentPlayer;
renderBoard();
if (checkWin(currentPlayer)) {
endGame("Player " + currentPlayer + " wins!");
} else if (checkDraw()) {
endGame("It's a draw!");
} else {
currentPlayer = currentPlayer === "X" ? "O" : "X";
if (currentPlayer === "O") {
setTimeout(makeComputerMove, 500);
}
}
}
}

function checkWin(player) {
const winningCombinations = [
[0, 1, 2],
[3, 4, 5],
[6, 7, 8],
[0, 3, 6],
[1, 4, 7],
[2, 5, 8],
[0, 4, 8],
[2, 4, 6],
];

for (let i = 0; i < winningCombinations.length; i++) {
const [a, b, c] = winningCombinations[i];
if (board[a] === player && board[b] === player && board[c] === player) {
return true;
}
}
return false;
}

function checkDraw() {
return board.every((cell) => cell !== "");
}

function endGame(message) {
gameEnded = true;
resultElement.textContent = message;
}

function makeComputerMove() {
const emptyCells = board.reduce((acc, cell, index) => {
if (cell === "") {
acc.push(index);
}
return acc;
}, []);
if (emptyCells.length > 0) {
const randomIndex = Math.floor(Math.random() * emptyCells.length);
const computerMove = emptyCells[randomIndex];
updateGameState(computerMove);
}
}

function renderBoard() {
for (let i = 0; i < cells.length; i++) {
cells[i].textContent = board[i];
}
}

function resetGame() {
board.fill("");
currentPlayer = "X";
gameEnded = false;
resultElement.textContent = "";
renderBoard();
}

cells.forEach((cell, index) => {
cell.addEventListener("click", () => updateGameState(index));
});

resetGame();
</script>
</html>

结语

通过上述步骤,我们实现了一个简单的井字棋游戏。这个实例展示了如何使用JavaScript DOM API来操作HTML元素,并响应用户事件。通过这个项目,你可以更好地理解DOM操作的基本概念和方法,以及如何在实际项目中应用它们。井字棋游戏是一个入门级的编程项目,适合初学者练习和提升编程技能。

Web实现表格单选全选与反选操作:JavaScript DOM基础与实例教程

Web实现表格单选全选与反选操作:JavaScript DOM基础与实例教程

在Web开发中,处理表格数据时,全选与反选功能是常见的交互需求。本文将通过一个简单的实例,介绍如何使用JavaScript DOM API来实现表格中的全选与反选操作,并讲解相关的JavaScript DOM基础知识。

实现效果

JavaScript DOM基础

DOM(Document Object Model)是文档对象模型的缩写,它将HTML或XML文档视为树结构,每个节点都是文档的一部分,可以是文档本身、元素、属性或文本内容。JavaScript中的DOM API提供了大量的方法和属性,允许开发者动态地访问和更新文档的内容、结构和样式。

实例:表格全选与反选操作

创建HTML表格结构

首先,我们需要创建一个包含商品信息的表格,并在表头添加一个全选复选框。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<div class="wrap">
<table>
<thead>
<tr>
<th><input type="checkbox" id="j_cbAll" /></th>
<th>商品</th>
<th>价钱</th>
</tr>
</thead>
<tbody id="j_tb">
<!-- 商品列表 -->
</tbody>
</table>
</div>

使用JavaScript实现全选与反选

单选操作

1
2
3
4
5
6
7
8
9
10
11
// 获取元素
var j_cbAll = document.getElementById('j_cbAll'); // 全选按钮
var j_tbs = document.getElementById('j_tb').getElementsByTagName('input'); // 下面所有的复选框
// 注册事件
j_cbAll.onclick = function() {
// this.checked 它可以得到当前复选框的选中状态如果是true 就是选中,如果是false 就是未选中
console.log(this.checked);
for (var i = 0; i < j_tbs.length; i++) {
j_tbs[i].checked = this.checked;
}
}

全选操作

全选操作的目标是当用户点击全选复选框时,所有商品的复选框都应该被选中。

1
2
3
4
5
6
7
8
9
10
11
12
// 获取全选复选框元素
var j_cbAll = document.getElementById('j_cbAll');
// 获取所有商品复选框元素
var j_tbs = document.getElementById('j_tb').getElementsByTagName('input');

// 为全选复选框绑定点击事件
j_cbAll.onclick = function() {
// 遍历所有商品复选框,设置与全选复选框相同的选中状态
for (var i = 0; i < j_tbs.length; i++) {
j_tbs[i].checked = this.checked;
}
};

反选操作

反选操作的目标是当任何一个商品复选框的状态发生变化时,检查所有复选框的状态,并据此更新全选复选框的选中状态。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 为每个商品复选框绑定点击事件
for (var i = 0; i < j_tbs.length; i++) {
j_tbs[i].onclick = function() {
// 定义一个变量flag来标记是否所有复选框都被选中
var flag = true;
// 遍历所有商品复选框,如果发现有未选中的,设置flag为false
for (var i = 0; i < j_tbs.length; i++) {
if (!j_tbs[i].checked) {
flag = false;
break; // 只要发现一个未选中的,就可以终止循环
}
}
// 根据flag的值更新全选复选框的选中状态
j_cbAll.checked = flag;
}
}

全部代码

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
<!DOCTYPE html>
<html>

<head lang="en">
<meta charset="UTF-8">
<title>单选全选反选</title>
<style>
* {
padding: 0;
margin: 0;
}

.wrap {
width: 300px;
margin: 100px auto 0;
}

table {
border-collapse: collapse;
border-spacing: 0;
border: 1px solid #c0c0c0;
width: 300px;
}

th,
td {
border: 1px solid #d0d0d0;
color: #404060;
padding: 10px;
}

th {
background-color: #09c;
font: bold 16px "微软雅黑";
color: #fff;
}

td {
font: 14px "微软雅黑";
}

tbody tr {
background-color: #f0f0f0;
}

tbody tr:hover {
cursor: pointer;
background-color: #fafafa;
}
</style>

</head>

<body>
<div class="wrap">
<table>
<thead>
<tr>
<th>
<input type="checkbox" id="j_cbAll" />
</th>
<th>商品</th>
<th>价钱</th>
</tr>
</thead>
<tbody id="j_tb">
<tr>
<td>
<input type="checkbox" />
</td>
<td>iPhone8</td>
<td>8000</td>
</tr>
<tr>
<td>
<input type="checkbox" />
</td>
<td>iPad Pro</td>
<td>5000</td>
</tr>
<tr>
<td>
<input type="checkbox" />
</td>
<td>iPad Air</td>
<td>2000</td>
</tr>
<tr>
<td>
<input type="checkbox" />
</td>
<td>Apple Watch</td>
<td>2000</td>
</tr>

</tbody>
</table>
</div>
<script>
// 1. 全选和取消全选做法: 让下面所有复选框的checked属性(选中状态) 跟随 全选按钮即可
// 获取元素
var j_cbAll = document.getElementById('j_cbAll'); // 全选按钮
var j_tbs = document.getElementById('j_tb').getElementsByTagName('input'); // 下面所有的复选框
// 注册事件
j_cbAll.onclick = function() {
// this.checked 它可以得到当前复选框的选中状态如果是true 就是选中,如果是false 就是未选中
console.log(this.checked);
for (var i = 0; i < j_tbs.length; i++) {
j_tbs[i].checked = this.checked;
}
}
// 2. 下面复选框需要全部选中, 上面全选才能选中做法: 给下面所有复选框绑定点击事件,每次点击,都要循环查看下面所有的复选框是否有没选中的,如果有一个没选中的, 上面全选就不选中。
for (var i = 0; i < j_tbs.length; i++) {
j_tbs[i].onclick = function() {
// flag 控制全选按钮是否选中
var flag = true;
// 每次点击下面的复选框都要循环检查者4个小按钮是否全被选中
for (var i = 0; i < j_tbs.length; i++) {
if (!j_tbs[i].checked) {
flag = false;
break; // 退出for循环 这样可以提高执行效率 因为只要有一个没有选中,剩下的就无需循环判断了
}
}
j_cbAll.checked = flag;
}
}
</script>
</body>

</html>

结语

通过上述代码,我们实现了表格中的全选与反选功能。这个实例展示了如何使用JavaScript DOM API来操作HTML元素,并响应用户事件。全选与反选功能是表格交互中的基础,掌握这种操作对于开发复杂的数据表格应用至关重要。希望本文能帮助你更好地理解DOM操作,并将其应用到你的Web项目中。

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

H5实现Web ECharts教程:轻松创建动态数据图表

H5实现Web ECharts教程:轻松创建动态数据图表

实现效果

资源地址:

数据可视化之旅:探索ECharts在H5中的丰富示例与应用

简介

ECharts是一款由百度前端团队开发的开源可视化库,它提供了丰富的图表类型和灵活的配置选项,使得开发者能够轻松地在Web页面上创建交互式的图表。无论是简单的柱状图、折线图,还是复杂的关系图、地图,ECharts都能够提供强大的支持。

ECharts概述

ECharts的核心理念是“让数据可视化变得简单”,它不仅支持多种数据格式,还提供了丰富的API接口和详细的配置项,使得开发者可以根据需求定制图表。ECharts的另一个亮点是其优秀的交互性能,包括数据缩放、拖拽、值域漫游等,为用户提供了丰富的交互体验。

ECharts官网与资源下载

ECharts的官方网站是 ECharts GitHub,你可以在这里找到最新的开发文档、示例代码以及源代码。ECharts的使用非常简单,你可以直接通过CDN引入,或者下载源文件进行本地部署。

CDN引入

通过CDN是引入ECharts最快捷的方式,只需在HTML文件的<head>标签中添加以下代码:

1
<script src="https://cdn.jsdelivr.net/npm/echarts@5.3.3/dist/echarts.js"></script>

源文件下载

如果你需要对ECharts进行更深入的定制或者贡献代码,可以在ECharts的GitHub仓库中下载最新的源文件。

创建第一个ECharts图表

以下是一个简单的ECharts图表示例,展示了如何在H5页面中创建一个基本的柱状图。

  1. 创建HTML结构

首先,我们需要创建一个具有确定宽高的<div>元素,用于放置ECharts图表。

1
<div id="main" style="width: 600px;height:400px;"></div>
  1. 引入ECharts库

在页面中通过<script>标签引入ECharts库。

1
<script src="echarts.js"></script>
  1. 初始化ECharts实例

<script>标签内,通过echarts.init方法初始化一个ECharts实例,并将其绑定到我们之前创建的<div>元素上。

1
var myChart = echarts.init(document.getElementById('main'));
  1. 配置图表选项

定义一个option对象,包含图表的类型、标题、轴、提示框等配置信息。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
var option = {
title: {
text: 'ECharts 入门示例'
},
tooltip: {},
legend: {
data: ['销量']
},
xAxis: {
data: ['衬衫', '羊毛衫', '雪纺衫', '裤子', '高跟鞋', '袜子']
},
yAxis: {},
series: [
{
name: '销量',
type: 'bar',
data: [5, 20, 36, 10, 10, 20]
}
]
};
  1. 渲染图表

使用setOption方法将配置项应用到ECharts实例上,渲染图表。

1
myChart.setOption(option);

全部代码

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
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>ECharts</title>
<!-- 引入刚刚下载的 ECharts 文件 -->
<script src="echarts.js"></script>
<!-- cdn引入 -->
<!-- <script src="https://cdn.jsdelivr.net/npm/echarts@5.3.3/dist/echarts.js"></script> -->
</head>
<body>
<!-- 为 ECharts 准备一个定义了宽高的 DOM -->
<div id="main" style="width: 600px;height:400px;"></div>
<script type="text/javascript">
// 基于准备好的dom,初始化echarts实例
var myChart = echarts.init(document.getElementById('main'));

// 指定图表的配置项和数据
var option = {
//标题
title: {
text: 'ECharts 入门示例'
},
//提示框
tooltip: {},
//柱状元素名字
legend: {
data: ['销量']
},
//X轴
xAxis: {
data: ['衬衫', '羊毛衫', '雪纺衫', '裤子', '高跟鞋', '袜子']
},
//Y轴
yAxis: {},
series: [
{
name: '销量',
type: 'bar',
data: [5, 20, 36, 10, 10, 20]
}
]
};

// 使用刚指定的配置项和数据显示图表。
myChart.setOption(option);
</script>
</body>
</html>

结语

通过上述步骤,我们成功地在H5页面中创建了一个简单的柱状图。ECharts的强大功能和灵活性使得数据可视化变得简单而高效。无论是数据分析师、前端开发者还是普通用户,都可以利用ECharts快速地将数据转化为直观、美观的图表,从而更好地理解和传达信息。

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

浏览器DOM操作基础:禁用右键菜单与阻止文字选中

浏览器DOM操作基础:禁用右键菜单与阻止文字选中

在Web开发中,有时我们需要对用户的默认行为进行限制,以保护网站内容或提供更定制化的用户体验。两个常见的例子是禁止用户通过右键菜单访问上下文选项,以及阻止用户选中页面上的文字。本文将介绍如何使用JavaScript来实现这两个功能,以及它们背后的原理和可能的应用场景。

体验地址

洛可可白:

禁用右键菜单与阻止文字选中

禁用右键菜单

在Web页面中,用户可以通过点击鼠标右键来调出浏览器的上下文菜单(右键菜单),这里可以包含多种选项,如“复制”、“粘贴”、“另存为”等。在某些情况下,出于版权保护、防止内容盗用或避免不当操作的考虑,开发者可能希望禁用这个菜单。

要禁用右键菜单,我们可以通过监听contextmenu事件,并使用preventDefault()方法来阻止其默认行为。以下是一个简单的代码示例:

1
2
3
document.addEventListener('contextmenu', function (e) {
e.preventDefault();
});

当用户尝试在页面上点击右键时,这个事件监听器会被触发,随后preventDefault()方法会阻止浏览器显示默认的右键菜单。

阻止文字选中

同样地,用户可以通过鼠标拖动来选中页面上的文字,这可能会导致内容被复制或不小心被拖动到其他位置。如果开发者希望防止这种情况发生,可以通过监听selectstart事件来实现。

selectstart事件在用户开始选中文本时触发。通过在事件监听器中调用preventDefault()方法,我们可以阻止文本被选中。以下是相应的代码示例:

1
2
3
document.addEventListener('selectstart', function (e) {
e.preventDefault();
});

这样,无论用户如何尝试,都无法在页面上选中任何文字。

代码示例

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
<!DOCTYPE html>
<html lang="en">

<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>
</head>

<body>
禁用右键菜单与阻止文字选中
<script>
// 1. contextmenu 禁用右键菜单
document.addEventListener('contextmenu', function (e) {
e.preventDefault();
})
// 2. 禁止选中文字 selectstart
document.addEventListener('selectstart', function (e) {
e.preventDefault();
})
</script>
</body>

</html>

应用场景

  • 版权保护:对于包含原创内容或版权材料的网站,禁用右键菜单和阻止文字选中可以作为一种基本的保护措施,防止用户轻易复制内容。
  • 用户体验:在某些应用或游戏中,可能不希望用户与页面交互的方式受到限制,因此禁用这些功能可以提供更流畅的用户体验。
  • 防止误操作:在触摸板或触摸屏设备上,用户有时会无意中选中文字或触发右键菜单,禁用这些功能可以减少误操作的可能性。

注意事项

虽然禁用右键菜单和阻止文字选中可以在一定程度上限制用户的行为,但这并不是一个完全可靠的安全措施。有经验的用户仍然可以通过浏览器插件、开发者工具或其他技术手段来绕过这些限制。因此,这些方法应该被视为基本的辅助手段,而不是安全策略的全部。

通过上述介绍,使用简单的JavaScript代码,我们可以对用户的DOM操作进行一定程度的控制。这为Web开发者提供了更多的自由度,以创建符合特定需求的网页环境。

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

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

请我喝杯奶茶吧~

支付宝
微信