前端基础

前端

用来记录一下自己的前端入门阶段

html

我用的vscode写的html,这里推荐安装一款插件,可以实时看到网页效果(HTML preview)

image-20251118084723711

image-20251118084956640

html和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
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">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div class="todo-app">
<div class="title">
jade's Todo list
</div>

<div class="todo-from">
<input class="todo-input"type="text" placeholder="Add a todo">
<div class="todo-buttom">add todo</div>
</div>

<div class="item completed">
<div>
<input type="checkbox">
<!--span避免换行,横着排的。吃饭只是文本内容,不需要块级元素的属性-->
<span class="name">吃饭</span>
</div>

<div class="del">del</div>
</div>

<div class="item ">
<div>
<input type="checkbox">
<span class="name">睡觉</span>
</div>

<div class="del">del</div>
</div>

<div class="item ">
<div>
<input type="checkbox">
<span class="name">打游戏</span>
</div>

<div class="del">del</div>
</div>
</div>


<style>
.completed{
/*字上划线*/
text-decoration: line-through;
/*透明度*/
opacity: 0.4;
}
.item{
.del{
color: #0aa76ee1;
}
display: flex;
/*垂直时居中*/
align-items: center;
/*框中元素平分空间*/
justify-content: space-between;
box-sizing: border-box;
width:80%;
height: 60px;
padding: 16px;
/*margin可以有四个参数,左上开始顺时针。两个参数时第一个表示上下,第二个左右,auto表示自适应*/
margin: 8px auto;
border-radius: 20px;
background-color: white;
box-shadow: rgba(15, 131, 247, 0.2)8px 8px 20px;
}
.todo-buttom{
/* 左侧内边距*/
padding-left: 10px;
/*圆角*/
border-radius: 0 20px 20px 0;
/*去除轮廓*/
outline:none;
/*宽度*/
width: 10%;
/*高度*/
height: 50px;
/*背景颜色*/
background-color: aqua;
/*横向排列*/
display: flex;
/*居中*/
align-items: center;
/*鼠标悬停变小手.表示可点击*/
cursor: pointer;
user-select: none;
}
.todo-input{
margin-bottom: 10px;
padding-left: 10px;
box-sizing: border-box;
border-radius: 20px 0 0 20px;
outline:none;
width: 60%;
height: 50px;
border:1px solid rgb(0, 145, 255);
}
.todo-from{
display: flex;
padding-left: 20px;
}
body{
background-image: linear-gradient(to right,rgb(0, 145, 255), #51c69b);
min-height: 100vh;
margin:0;
}
.todo-app{
width: 98%;
height: 700px;
background-color: white;
border-radius: 10px;
margin-top: 40px;
margin-left: 1%;
}
.title{
/* 字体大小 */
font-size: 30px;
/* 字体颜色 */
color: #51c69b;
/* 字体粗细 */
font-weight: 600;
/* 字体居中 */
text-align: center;
/* 字体间距 */
letter-spacing: 2px;
/* 字体行高 */
line-height: 50px;



}
</style>


</body>
</html>

vue

到此一份静态网页就成功了,为了让他可交互的动起来,我们需要用vue

在此之前,需要了解一些知识。

基础知识

1. Vue 3 Composition API 基础

1.1 <script setup>语法

  • 这是Vue 3的编译时语法糖,简化了组件编写
  • 无需显式返回数据和方法,更简洁的代码结构
  • 自动将顶层变量/函数暴露给模板

1.2 ref响应式数据

1
2
3
4
import { ref } from 'vue'

const value = ref('') // 创建响应式数据
const list = ref([...]) // 响应式数组

注意点:

  • ref用于创建响应式的基本类型或对象类型数据
  • 访问值时需要使用 .value(在模板中自动解包,无需.value)
  • 修改值时必须通过 .value修改

2. 数据定义与响应式原理

2.1 数据初始化

1
2
3
4
5
6
const value = ref('') // 输入框的当前值
const list = ref([
{ value: '吃饭', isCompleted: true },
{ value: '睡觉', isCompleted: false },
{ value: '打豆豆', isCompleted: false },
])

关键理解:

  • list是一个响应式数组,数组变化会自动更新视图
  • 每个待办项是对象,包含内容值和完成状态(名称可以自定义,比如value这些可以随意更改名字)

3. 方法实现逻辑

3.1 添加待办事项 (add函数)

1
2
3
4
5
6
7
function add() {
list.value.push({
value: value.value,
isCompleted: false,
})
value.value = '' // 清空输入框
}

(这里要实现的功能是,把输入框的当前值放入数组,所以用到list.value.push(){},然后用完输入框中的值要清空)

实现原理:

  1. value.value获取输入框的当前值
  2. list.value数组添加新对象
  3. 清空输入框,准备下一次输入

3.2 删除待办事项 (del函数)

1
2
3
function del(index) {
list.value.splice(index, 1)
}

(删除不能随意删除,每次只能删除一个,所以需要传入下标,每次删除对应下标的)

实现原理:

  • 通过 splice(index, 1)从数组中删除指定位置的元素
  • 视图会自动更新,删除对应的DOM元素

4. 模板语法详解

4.1 列表渲染 (v-for)

1
2
3
<div v-for="(item, index) in list" :key="index">
<!-- 循环内容 -->
</div>

重要概念:

  • v-for用于循环渲染数组或对象
  • :key是必须的,帮助Vue识别每个节点的身份,提高渲染性能
  • 这里使用 index作为key(简单场景可用,但数据顺序变化时可能有性能问题)

4.2 动态类名绑定 (:class)

1
<div :class="[item.isCompleted ? 'completed' : 'item']">

语法解析:

  • 数组语法:根据条件返回不同的类名
  • item.isCompleted为true时应用 completed
  • 为false时应用 item

4.3 双向数据绑定 (v-model)

1
2
<input v-model="value" type="text">
<input v-model="item.isCompleted" type="checkbox">

工作原理:

  • 输入框:v-model="value"绑定到响应式数据
  • 复选框:v-model="item.isCompleted"绑定到对象的完成状态
  • 数据变化 → 视图更新,用户输入 → 数据更新

4.4 事件处理 (@click)

1
2
<div @click="add" class="todo-button">Add Todo</div>
<div @click="del(index)" class="del">del</div>

事件传递:

  • 点击”Add Todo”时调用 add函数
  • 点击”del”时调用 del(index)并传入当前项的索引

5. 样式处理技巧

5.1 scoped样式作用域

1
2
3
<style scoped>
/* 这里的样式只作用于当前组件 */
</style>

作用:

  • 防止样式污染全局
  • 自动为选择器添加唯一属性标识

5.2 条件样式类

1
2
3
4
5
6
7
.completed {
text-decoration: line-through;
opacity: 0.4;
}
.item {
/* 正常状态的样式 */
}

视觉效果:

  • 已完成事项有删除线且半透明
  • 通过动态类名绑定实现状态切换

6. 响应式系统工作原理

6.1 数据变化检测

  • Vue使用Proxy代理监听数据变化
  • list.value或其中对象属性变化时,触发重新渲染

6.2 虚拟DOM更新

  1. 数据变化时,Vue生成新的虚拟DOM
  2. 与旧虚拟DOM对比差异(diff算法)
  3. 只更新实际变化的DOM元素,提高性能

7. 核心概念总结

概念 作用 示例
ref() 创建响应式数据 const value = ref('')
v-model 双向数据绑定 <input v-model="value">
v-for 列表渲染 <div v-for="item in list">
:class 动态类名 :class="{completed: item.isCompleted}"
@click 事件绑定 @click="add"
methods 定义方法 function add() { ... }

这份笔记应该能帮助你理解Vue的核心概念。Vue的设计理念就是”数据驱动视图”,你只需要关注数据的变化,Vue会自动处理视图的更新。

功能需求分解

1. 显示待办列表功能

数据结构设计

1
2
3
4
5
const list = ref([
{ value: '吃饭', isCompleted: true },
{ value: '睡觉', isCompleted: false },
{ value: '打豆豆', isCompleted: false },
])

实现方式

1
2
3
<div v-for="(item, index) in list" :key="index">
<span>{{ item.value }}</span>
</div>

原理v-for循环遍历数组,为每个事项创建对应的DOM元素


2. 添加新事项功能

实现代码

1
2
3
4
5
6
7
8
9
10
11
const value = ref('') // 输入框绑定值

function add() {
list.value.push({
value: value.value, // 获取输入框内容
isCompleted: false, // 新事项默认未完成
})
value.value = '' // 清空输入框
}
<input v-model="value" placeholder="Add a todo">
<div @click="add" class="todo-button">Add Todo</div>

执行流程

  1. 用户在输入框打字 → v-model同步到value变量
  2. 点击按钮 → 触发add函数
  3. list数组添加新对象
  4. 清空输入框,准备下一次输入

3. 标记完成状态功能

样式定义

1
2
3
4
5
6
7
.completed {
text-decoration: line-through; /* 删除线 */
opacity: 0.4; /* 半透明 */
}
.item {
/* 正常状态样式 */
}

实现方式

1
2
3
4
<div :class="[item.isCompleted ? 'completed' : 'item']">
<input v-model="item.isCompleted" type="checkbox">
<span class="name">{{ item.value }}</span>
</div>

工作原理

  • v-model="item.isCompleted":复选框与完成状态双向绑定
  • :class动态类名:根据isCompleted值切换样式类
  • 用户点击复选框 → isCompleted值变化 → 类名自动更新 → 样式生效

4. 删除事项功能

实现代码

1
2
3
4
function del(index) {
list.value.splice(index, 1) // 从指定位置删除1个元素
}
<div @click="del(index)" class="del">del</div>

删除逻辑

  1. v-for循环时获取每个事项的index(位置索引)
  2. 点击del按钮 → 传入当前项的index
  3. splice(index, 1)从数组中删除该位置元素
  4. Vue自动重新渲染列表

完整代码

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
<script setup>
// 导入Vue的ref函数,用于创建响应式数据
import { ref } from 'vue'

// 定义响应式数据
const value = ref('') // 绑定输入框的值
const list = ref([
{ value: '吃饭', isCompleted: true }, // 待办事项对象:value-内容,isCompleted-完成状态
{ value: '睡觉', isCompleted: false },
{ value: '打豆豆', isCompleted: false },
])

// 添加待办事项的函数
function add() {
// 向列表中添加新事项
list.value.push({
value: value.value, // 使用输入框的当前值
isCompleted: false, // 新事项默认未完成
})

value.value = '' // 添加后清空输入框
}

// 删除待办事项的函数
function del(index) {
// 根据索引从列表中删除对应事项
list.value.splice(index, 1) // splice(位置, 删除数量)
}
</script>

<template>
<!-- 主容器 -->
<div class="todo-app">
<!-- 标题 -->
<div class="title">Todo App</div>

<!-- 输入区域 -->
<div class="todo-form">
<!-- 输入框:v-model实现双向数据绑定 -->
<input
v-model="value"
type="text"
class="todo-input"
placeholder="Add a todo"
/>
<!-- 添加按钮:点击触发add函数 -->
<div @click="add" class="todo-button">Add Todo</div>
</div>

<!-- 待办事项列表 -->
<!-- v-for循环渲染列表,:key提供唯一标识 -->
<div
v-for="(item, index) in list"
:key="index"
<!-- 动态类名:根据完成状态切换样式 -->
:class="[item.isCompleted ? 'completed' : 'item']"
>
<div>
<!-- 复选框:绑定完成状态,点击切换isCompleted -->
<input v-model="item.isCompleted" type="checkbox" />
<!-- 显示待办内容 -->
<span class="name">{{ item.value }}</span>
</div>

<!-- 删除按钮:点击时传入当前索引,触发del函数 -->
<div @click="del(index)" class="del">del</div>
</div>
</div>
</template>

<style scoped>
/* scoped:样式只作用于当前组件,避免全局污染 */

/* 主容器样式 */
.todo-app {
box-sizing: border-box; /* 盒模型:宽度包含padding和border */
margin-top: 40px;
margin-left: 1%;
padding-top: 30px;
width: 98%;
height: 500px;
background: #ffffff;
border-radius: 5px; /* 圆角边框 */
}

/* 标题样式 */
.title {
text-align: center;
font-size: 30px;
font-weight: 700; /* 字体粗细 */
}

/* 输入表单布局 */
.todo-form {
display: flex; /* 弹性布局,子元素横向排列 */
margin: 20px 0 30px 20px;
}

/* 添加按钮样式 */
.todo-button {
width: 100px;
height: 52px;
border-radius: 0 20px 20px 0; /* 右上和右下圆角 */
text-align: center;
/* 渐变背景色 */
background: linear-gradient(
to right,
rgb(61, 227, 141),
rgb(100, 180, 233)
);
color: #fff;
line-height: 52px; /* 行高实现垂直居中 */
cursor: pointer; /* 鼠标悬停时显示手型 */
font-size: 14px;
user-select: none; /* 禁止文字选中 */
}

/* 输入框样式 */
.todo-input {
padding: 0px 15px 0px 15px;
border-radius: 20px 0 0 20px; /* 左上和左下圆角 */
border: 1px solid #40d17d;
outline: none; /* 移除焦点轮廓 */
width: 60%;
height: 50px;
}

/* 未完成事项的样式 */
.item {
box-sizing: border-box;
display: flex;
align-items: center; /* 垂直居中 */
justify-content: space-between; /* 两端对齐 */
width: 80%;
height: 50px;
margin: 8px auto; /* 上下边距8px,左右自动居中 */
padding: 16px;
border-radius: 20px;
/* 阴影效果 */
box-shadow: rgba(35, 234, 227, 0.2) 0px 8px 20px;
}

/* 删除按钮文字颜色 */
.del {
color: rgb(224, 136, 154);
}

/* 已完成事项的特殊样式 */
.completed {
/* 复用item的基本布局样式 */
box-sizing: border-box;
display: flex;
align-items: center;
justify-content: space-between;
width: 80%;
height: 50px;
margin: 8px auto;
padding: 16px;
border-radius: 20px;
box-shadow: rgba(35, 234, 227, 0.2) 0px 8px 20px;

/* 完成状态特有样式 */
text-decoration: line-through; /* 删除线效果 */
opacity: 0.4; /* 半透明 */
}
</style>