Vue_study
Bamboo Lv3

学习网站链接:https://www.dengruicode.com/study?uuid=58893cef7e824a02b16039129d59713c

学习视频链接: https://www.bilibili.com/video/BV1nV411Q7RX/?p=17&share_source=copy_web&vd_source=44c05cee32b4f493b7fbef94d2c257f7

Vue入门

以下代码涉及(可以搜索查询):

自动侦听器 watchEffect

侦听器watch

计算属性 computed

渲染数据v-text和v-html

v_model修饰符

双向数据绑定v-model(v-model等于v-on+v-bind)

遍历数组或对象v-for

动态属性绑定v-bind

显示与隐藏v-show

条件渲染v-if

绑定事件v-on和按键修饰符

ref和reactive的区别

相关代码:

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
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<!-- <script src="vue.global.js"></script> 传统开发模式-->
<style>
.textColor{
color: rgb(234, 134, 202);
}
</style>
</head>

<body>
<div id="app">

<!-- 自动侦听器 watchEffect -->
<!-- 使用时要先在库导入watchEffect方法 -->
<!-- 侦听器watch,手动监听 -->
<!-- 使用时要先在库导入watch方法,需要更加精细的值时可使用 -->
<!-- 侦听需要在网页按F12查看终端输出 -->
爱好
<select v-model="hobby">
<option value="">请选择</option>
<option value="A">写作</option>
<option value="B">画画</option>
<option value="C">运动</option>
</select>
<hr>

<select v-model="date.year">
<option value="">请选择</option>
<option value="2023">2023</option>
<option value="2024">2024</option>
<option value="2025">2025</option>
</select>
<hr>

<select v-model="date.month">
<option value="">请选择</option>
<option value="10">10</option>
<option value="11">11</option>
<option value="12">12</option>
</select>

<!-- 计算属性 computed -->
<!-- 使用时要先在库导入computed方法,在js部分创建好addnumber和subnumber -->
<h3>add :{{addnumber()}}</h3>
<h3>add :{{addnumber()}}</h3>

<h3>sub :{{subnumber}}</h3>
<h3>sub :{{subnumber}}</h3>

<!-- 使用v-model.number确保输入的为数字 -->
x <input type="text" v-model.number="data.x"><br>
y <input type="text" v-model.number="data.y"><br>

<!-- 渲染数据v-text和v-html -->
<h3>{{web.title}}</h3>
<!-- 将数据解析为纯文本格式 -->
<h3 v-text="web.title"></h3>
<!-- 将数据解析为html格式,可以显示出颜色 -->
<h3 v-html="web.url"></h3>

<!-- v_model修饰符 -->
<h3>url: {{ web.url }}</h3>
<h3>user: {{ web.user }}</h3>

v-model实时渲染 <input type="text" v-model="web.url"><br>
v-model.lazy失去焦点或按下回车才渲染 <input type="text" v-model.lazy="web.url"><br>
<!-- 输入100人,web.user的值仍为100;但是输入人数100会变成人数100,此时解析成字符串,所以v-model.number不会去解析 -->
输入框的值转换成数字类型 <input type="text" v-model.number="web.user"><br>
<!-- 首尾的空格都可以去除,中间的不行 -->
v-model.trim去除首尾空格 <input type="text" v-model.trim="web.url">

<!-- 双向数据绑定v-model -->
<h3>文本框 {{ data.text }}</h3>
<h3>单选框 {{ data.radio }}</h3>
<h3>复选框 {{ data.checkbox }}</h3>
<h3>记住密码 {{ data.remember }}</h3>
<h3>下拉框 {{ data.select }}</h3>

<!-- 文本框 -->
<!-- 单向数据绑定 当数据发生变化时,视图会自动更新,但如果用户手动更改input的值,数据不会更新 -->
单向数据绑定 <input type="text" :value="data.text"><br>
<!-- 双向数据绑定 当数据发生变化时,视图会自动更新,用户手动更改input的值,数据也会更新
对于<input type:"text">,v-model 绑定的时input元素的value属性 -->
双向数据绑定 <input type="text" v-model="data.text"><br>

<!-- 单选框 对于<input type="radio">,v-model绑定的是input元素的选中状态-->
单选框 <input type="radio" value="男" v-model="data.radio">男
<input type="radio" value="女" v-model="data.radio">女<br>

<hr>
<!--
复选框
对于 <input type="checkbox">, v-model 绑定的是 input 元素的选中状态
-->
<input type="checkbox" v-model="data.checkbox" value="a">写作
<input type="checkbox" v-model="data.checkbox" value="b">画画
<input type="checkbox" v-model="data.checkbox" value="c">运动

<hr>
<!-- 记住密码 -->
<input type="checkbox" v-model="data.remember">记住密码

<hr>
<!--
下拉框
对于 <select>, v-model 绑定的是 select 元素的选中状态
-->
<select v-model="data.select">
<option value="">请选择</option>
<option value="A">写作</option>
<option value="B">画画</option>
<option value="C">运动</option>
</select>


<!-- 遍历数组或对象v-for -->
<ul>
<!-- 遍历data.number数组 -->
<li v-for="value in data.number">
{{value}}
</li>
</ul>
<ul>
<!-- 多个遍历data.number数组 -->
<li v-for="(value,index) in data.number">
value => {{value}} : index => {{index}}
</li>
</ul>
<ul>
<!-- 多个遍历data.user数组 -->
<li v-for="(value,key,index) in data.user">
value => {{value}} : key => {{key}}: index => {{index}}
</li>
</ul>
<ul>
<!-- 多个遍历data.user数组 -->
<template v-for="(value,key,index) in data.user">
<li v-if="index == 1">
value => {{value}} : key => {{key}}: index => {{index}}
</li>
</template>
</ul>
<!-- Vue会编译<template>的内容,但是不会将其作为DOM元素渲染到页面上 -->
<ul>
<!-- 多个遍历data.teacher数组,两个对象的数组 :key作用 :无论列表如何变化,输入框的状态都会与对应数据项正确绑定。-->
<li v-for="(value,index) in data.teacher" :title="value.name" :key="value.id">
index => {{index}}:value.id => {{value.id}} :value.name => {{value.name}}
</li>
</ul>

<!-- 动态属性绑定v-bind -->
<!-- :value -->
<h3>value="哈哈哈"</h3>
<input type="text" value="哈哈">
<!-- 将value改成动态属性 -->
<h3>v-bind:value="web.URL"</h3>
<input type="text" v-bind:value="web.URL">
<!-- 简写 -->
<h3>:value="web.URL"</h3>
<input type="text" :value="web.URL">

<!-- :src -->
<h3>src="zwz_image.jpg"</h3>
<img src="zwz_image.jpg" >
<!-- src的动态属性绑定 -->
<h3>:src="web.img"</h3>
<img : src="web.img" >

<!-- :class -->
<h3>class="textColor"</h3>
<b class="textColor">你好,我是曾丸子</b>
<!-- class的动态属性绑定 -->
<h3>:class="{textColor:web.fontStatus}"</h3>
<b :class="{textColor:web.fontStatus}">你好,我是曾丸子</b>
<h3>:class="web.fontStatus ? 'textColor' : ''"</h3>

{{ message }}
{{web.show}}<hr>

<!-- 显示与隐藏v-show -->
<p v-show="web.show">你好,我是曾丸子</p>
<!-- 可以使用web.show控制显示与隐藏 -->
<p v-if="web.show">你好,我不是曾丸子</p>
<!-- v-if:当条件为true就渲染,条件为false时就不渲染,不适合频繁点击,性能会下降 -->

<!-- 条件渲染v-if,if-else的应用 -->
<p v-if="web.user <1000">新一年</p>
<p v-else-if="web.user >=1000 && web.user <10000">优秀的一年</p>
<p v-else>牛逼的一年</p>

<h2>{{web.title}}</h2>
<h2>{{web.URL}}</h2>
<h2>{{number}}</h2>

<button @click="toggle">切换显示状态</button>

<!-- 绑定事件v-on和按键修饰符 -->
<!-- 设置一个按钮,为事件绑定edit(v:on和@作用是一样的) -->
<button v-on:click="edit">修改</button><br>
<button @click="edit">修改@</button><hr>

<!-- 改变状态的按键和框 -->
回车 <input type="text" @keyup.enter="add(40,60)"><br>
空格 <input type="text" @keyup.space="add(20,30)"><br>
Tab <input type="text" @keydown.tab="add(10,20)"><br>
w <input type="text" @keyup.w="add(5,10)"><br>
Ctrl+Enter <input type="text" @keyup.ctrl.enter="add(1,2)"><br>
<!-- 组合按键 -->

<!-- 设置一个按钮,为事件绑定add(keyup是松开按键,enter是回车) -->
</div>

<script type="module">
import { createApp,reactive,ref,computed,watch,watchEffect } from './vue.esm-browser.js' //模块化开发模式
//解构赋值,将Vue属性赋值给变量
// Vue是一个对象,包含了Vue的所有属性和方法
// const{createApp, reactive} = Vue

// ref和reactive的区别
const number =ref(10) //ref()用于存储简单数据类型,如:数字、字符串、布尔值、数组等。使用ref创建的变量需要通过.value来访问和修改值
number.value = 20 //修改值

// Vue.createApp() 创建一个Vue应用
// mount() 挂载到页面上
createApp({
// setup选项 用于设置响应式数据和方法等
setup() {
const hobby = ref("") //爱好
const date = reactive({ //reactive()用于存储复杂数据类型,如:对象或数组等。使用reactive创建可以直接通过属性名来访问和修改值
year: 2023,
month: 10
})
//自动侦听器 watchEffect
watchEffect(() => { //自动侦听器watchEffect
console.log("------监听开始");
console.log("hobby", hobby.value) //打印
console.log("date", date.year, date.month) //打印
console.log("------监听结束")
/*
watchEffect() 是 Vue 3 中的一个 API,用于创建一个响应式的副作用函数。
它会自动追踪函数中使用的响应式数据,并在这些数据发生变化时重新执行函数。
watchEffect() 不需要手动指定要侦听的数据,它会自动侦听函数中使用的所有响应式数据。
*/
})
//侦听器watch
watch(hobby, (newValue, oldValue) => {
console.log("hobby","newValue", newValue,"oldValue", oldValue) //打印
// 侦听器watch 侦听hobby的值变化
// newValue:新值 oldValue:旧值
if (newValue === "A") {
console.log("写作")
} else if (newValue === "B") {
console.log("画画")
} else if (newValue === "C") {
console.log("运动")
}

//侦听 date
watch(date, (newValue, oldValue) => { //侦听器watch
console.log("date","newValue", newValue,"oldValue", oldValue) //打印
/*
JS中对象和数组是通过引用传递的,而不是通过值传递
当修改对象或数值时,实际上是修改了对象和数组的引用,而不是创建一个新的对象或数组
所以,如果修改了对象或数组的值,那么打印出来的结果是修改后的结果
*/
if (newValue.year === "2023") {
console.log("2023")
} else if (newValue.year === "2024") {
console.log("2024")
} else if (newValue.year === "2025") {
console.log("2025")
}
if (newValue.month === "10") {
console.log("10")
} else if (newValue.month === "11") {
console.log("11")
} else if (newValue.month === "12") {
console.log("12")
}
})

//监听 date 中的某个属性 year
watch(() => date.year, (newValue, oldValue) => {
console.log("oldValue", oldValue, "newValue", newValue)

if (date.year == "2024") {
console.log("2024")
}
})
})


const data =reactive({
number:["1", "2", "3", "4", "5"], //数组
user:{ //对象
name:"zwz",
gender: "女"
},
teacher:[ //包含两个对象的数组
{id:100,name:"bcy",web:"bcy.com"},
{id:101,name:"bamboo",web:"bamboo.com"}
],
text: "hello world", //文本框
radio: "",//单选框
checkbox: [],//复选框
remember: false,//单个复选框-记住密码
select: "",//下拉框

x :10,
y: 20
})

//方法 -无缓存 只要调用就会执行 调用时为addnumber()
let addnumber = () => {
console.log("addnumber") //打印
return data.x + data.y
}
//属性 -有缓存 可以提高性能,不需要重复计算,当数据发生变化时才需要重新计算 调用时为subnumber 不需要加括号,因为是属性
const subnumber = computed(() => {
console.log("subnumber") //打印
return data.x - data.y
})

//定义一个网站
const web = reactive({ //reactive()用于存储复杂数据类型,如:对象或数组等。使用reactive创建可以直接通过属性名来访问和修改值
title: "hello world",
url: "<i style='color:rgb(234, 134, 202)'>bcy.com</i>",
show: true,
user: 10,
img: "zwz_image.jpg",
fontStatus: true
})
web.URL = "bamboo.com" //修改值

//获取网站新增用户数
const add = (a,b) => {
web.URL += a + b //修改值
}

//修改网站的网址
const edit = () => { //定义一个方法
web.URL = 20 //修改值
}

//定义可以切换show状态的函数
const toggle = () => {
web.show = !web.show //修改值
}

return { //实现页面的返回
message: 'success',
number, //number是一个ref对象,直接返回即可
web,
edit,
add,
toggle,
data,
addnumber,
subnumber,
hobby,
date
}
}
}).mount('#app')
</script>
</body>
</html>

Vue项目实战

图片轮播功能(4张图片,命名为n.jpg,实现了图片的任意切换)

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

<head>
<meta charset="UTF-8">
<title>Title</title>
</head>

<body>
<div id="app">
<h3>{{ number }}</h3>
<!-- 显示一张图片时可以直接导入 -->
<!-- <img src="/images/1.jpg" style="width: 300px;"> -->
<!-- 多张照片可以使用:src动态属性绑定,然后改成字符串 -->
<img :src=`/images/${number}.jpg` style="width: 300px;"> <hr>

<button @click="prev">上一张</button>
<button @click="next">下一张</button>

<!-- 遍历并使用jump函数实现图片的跳转 -->
<ul>
<li v-for="(value, index) in 4">
<a href="#" @click="jump(value)">{{ value }}</a>
</li>
</ul>
</div>

<script type="module">
import { createApp, ref } from './vue.esm-browser.js'

createApp({
setup() {
const number = ref(1)

//上一张
const prev = () => {
number.value--

if (number.value == 0) {
number.value = 4
}
}

//下一张
const next = () => {
number.value++

if (number.value == 5) {
number.value = 1
}
}

//跳转
const jump = (value) => {
number.value = value
}

return {
number,
prev,
next,
jump
}
}
}).mount("#app")
</script>
</body>

</html>

记事本功能(使用list当作记事本,实现增加、删除、清空功能)

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
<!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 id="app">
<input type="text" v-model = "data.content">

<button @click="add">添加</button>

<ul>
<li v-for="(value,index) in data.list">
{{value}}
<button @click="del(index)">删除</button>
</li>
</ul>

<!-- 获取list中的数量 -->
{{data.list.length}}<button @click="clear">清空</button>
</div>

<script type="module">
import { createApp,reactive } from './vue.esm-browser.js'

createApp({
setup(){
const data = reactive({
content:"hello world",
list: ["1","2"]
})
//增加记录到list中
const add = () => {
data.list.push(data.content)
console.log(data.list)
}
//从list删除记录
const del = (index) => {
data.list.splice(index,1)
console.log(data.list)
}
//清空list
const clear = () => {
data.list = []
console.log(data.list)
}

return {
data,
add,
del,
clear
}
}
}).mount('#app')

</script>
</body>
</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
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
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
table {
width: 600px;
color: #8f8e8e;
text-align: center;
border-collapse: collapse;
}

table thead {
background: #F5F5F5;
}

table tr {
height: 30px;
line-height: 30px;
border: 1px solid #ececec;
}
</style>
</head>

<body>
<div id="app">
<table>
<thead>
<tr>
<!-- <td><input type="checkbox" v-model="data.selected" @change="selectAll" /></td> -->
<td><input type="checkbox" v-model="data.selected" /></td>
<td>商品</td>
<td>单价</td>
<td>库存</td>
<td colspan="2">操作</td>
</tr>
</thead>
<tbody>
<tr v-for="(value, index) in data.list">
<!--
<td><input type="checkbox" v-model="data.checkboxList" :value="value" @change="checkSelect" /></td>
-->
<td><input type="checkbox" v-model="data.checkboxList" :value="value" /></td>
<td>{{ value.name }}</td>
<td>{{ value.price }}</td>
<td>{{ value.stock }}</td>
<td>
<button @click="sub(value)">-</button>
{{ value.number }}
<button @click="add(value)">+</button>
</td>
<td><button @click="del(index,value.id)">删除</button></td>
</tr>
</tbody>
<tfoot>
<tr>
<!-- <td>总价 {{ totalPrice() }}</td> -->
<td>总价 {{ totalPrice }}</td>
</tr>
</tfoot>
</table>
</div>

<script type="module">
import { createApp, reactive, watch, computed } from './vue.esm-browser.js'

createApp({
setup() {
const data = reactive({
selected: false,
checkboxList: [],
list: [{
id: 1,
name: "铅笔",
price: 10,
number: 1,
stock: 3
},
{
id: 2,
name: "鼠标",
price: 20,
number: 2,
stock: 5
},
{
id: 3,
name: "键盘",
price: 30,
number: 1,
stock: 6
}],
})

//减
const sub = (value) => {
value.number--

if (value.number <= 1) {
value.number = 1
}
}

//加
const add = (value) => {
value.number++

if (value.number >= value.stock) {
value.number = value.stock
}
}

//删除
//先将list中的删除,list中直接按照索引位置删,再将表示选中的数组按照id将要删除的移除数组
const del = (index, id) => {
data.list.splice(index, 1) //splice(要删除元素的索引位置, 要删除的元素数量)

//filter 筛选符合条件的元素, 返回一个新的数组
let newArr = data.checkboxList.filter((value, index) => {
return value.id != id
})
data.checkboxList = newArr

//checkSelect() //检查勾选状态
}

/*
//总价
const totalPrice = () => {
let total = 0
for (let i = 0; i < data.checkboxList.length; i++) {
total += data.checkboxList[i].price * data.checkboxList[i].number
}

return total
}
*/
//计算属性-有缓存 [计算属性根据其依赖的响应式数据变化而重新计算]
const totalPrice = computed(() => {
/*
reduce定义: 用于对数组中的所有元素进行迭代操作, 并将每次操作的结果累加到一个初始值上
reduce接收两个参数: 一个是累加器函数, 另一个是初始值
reduce: 将 data.checkboxList 数组中的每个 checkbox 对象的 price 和 number 属性进行相乘,
并将结果累加到初始值 0 上, 最后返回累加的结果

total(累加器) 用于存储每次计算的结果, 初始值为 0
item(当前元素) 在每次迭代过程中, 当前元素的值会被传递给回调函数
*/

return data.checkboxList.reduce((total, item) => total + item.price * item.number, 0)
})

/*
//全选/反选
const selectAll = () => {
if (data.selected) { //true
data.checkboxList = data.list
} else { //false
data.checkboxList = []
}
}
*/
//监听 data.selected
let flag = true
//上面监听为false,所以要另设一个标记位
//缺少不全选的判断,通过标记位将不全选状态传递给第一个watch作判断
watch(() => data.selected, (newValue, oldValue) => {
//console.log("newValue:",newValue,"oldValue:",oldValue)

if (newValue) {
data.checkboxList = data.list
} else {
if (flag) {
data.checkboxList = []
}
}
//console.log(data.checkboxList)
})

/*
//检查勾选状态
const checkSelect = () => {
if (data.checkboxList.length == data.list.length && data.list.length != 0) {
data.selected = true
} else {
data.selected = false
}
}
*/
//监听 data.checkboxList
watch(() => data.checkboxList, (newValue, oldValue) => {
console.log("newValue:", newValue, "oldValue:", oldValue)
console.log(newValue.length)

if (newValue.length == data.list.length && data.list.length != 0) {
data.selected = true
flag = true
} else {
data.selected = false
flag = false
}
})

return {
data,
sub,
add,
del,
totalPrice
//selectAll,
//checkSelect
}
}
}).mount("#app")
</script>
</body>

</html>
Powered by Hexo & Theme Keep
Total words 28.5k Unique Visitor Page View