前言

终于写完了毕业论文,匆忙的一天突然空闲下来,终于有时间将前期学习的东西作为笔记搬上博客了。这个月发生了很多事,下面这些Vue的相关知识也是我在匆忙之中学习的,有错误的请见谅。

Vue是什么

简单来说就是一个JavaScript框架,但是他有个特点叫渐进式,即不需要一次性学会所有的内容,可以根据需要选择学习,是一个易学易用,性能出色,使用场景丰富的Web前端框架。相比于React,它关注于数据的流向,而不是数据的样式。

Vue.js - 渐进式 JavaScript 框架 | Vue.js (vuejs.org)

快速上手

和我们学其他前端一样,可以使用线上的CND链接,也可以下载后使用离线的版本。

1
2
<!--CDN的形式-->
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>

这里是非min的形式,也可以下载min的形式(本质就是将换行去除)

然后就可以开始创建Vue应用,都是固定的写法,最后的mount("#app")别忘写,他确实容易让人忘记。

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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="./js/vue3.global.min.js"></script>
</head>
<body>

<div id="app">
<!-- 插值表达式-->
{{ msg }}

<h1>{{web.title}}</h1>
<h2>{{web.url}}</h2>
</div>

<script>
// import {createApp, reactive, ref} from "vue";

Vue.createApp({
setup() {

const msg = Vue.ref("success")

const web = Vue.reactive({
title: "百度",
url: "baidu.com"
})

return {
web: web,
msg: msg
}
}
}).mount("#app")

</script>
</body>
</html>

如果你熟悉ES6,那么还可以使用解构的写法,将createApp, reactive结构出来,这样就可以不用再写Vue这个前缀。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 解构赋值语法 去除Vue
const {createApp, reactive} = Vue
createApp({
// setup选项 用于设置响应式数据与方法
setup() {
// 返回是一个对象 使用reactive
const web = reactive({
title: "gcnanmu",
url: "gcnanmucode"
})

// 返回数据
return {
msg: "success",
web: web
}
}
}).mount("#app")
// 与id进行绑定

这边出现了模版语法和响应式数据的知识,我们在后面会学习到,对于模版插值语法,使用过后端框架的人应该已经见过了。

模块化开发 import

上述创建vue应用的时候都是使用vue3.global.js全局导入的,但是有时候我们并不需要使用它全部的模块,学过es6之后我们了解到相关模块可以使用import按需导入。如果想要使用按需导入可以使用vue.esm-browser.js这个js文件

1
<script src="js/vue.esm-browser.js"></script>

打开文件划到最下面可以发现export,导出了所有的模块

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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
{ { msg } }
<h2>{{web.title}}</h2>
<h2>{{web.url}}</h2>
</div>

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

createApp({
setup() {

const web = reactive({
title: "百度",
url: "www.baidu.com"
})

return ({
msg: "success",
web
})
}
}).mount("#app")
</script>
</body>
</html>

插值表达式

又称模版语法,是一种用来在html标签中给数据占位的一种语法。在vue中常用的有三种

  1. 文本插值 { { } } 默认是纯文本的形式

    1
    <span>Message: {{ msg }}</span>
  2. 纯文本数据 v-text 和{{}}的用法很像

    1
    <span v-text="xxx"></span>
  3. 原始HTML v-html 会将文本渲染为HTML

    1
    <h3 v-html="web.url"></h3>

下面是一个例子:

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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<!-- 以前都是使用插值表达式来实现数据站位-->
<!-- vue中提供了v-text和v-html来实现数据的渲染-->
<h3>{{web.title}}</h3>

<h3 v-text="web.title"></h3>

<h3 v-html="web.url"></h3>
</div>

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

createApp({
setup() {

const web = reactive({
title: "百度",
url: "<i style='color:red;'>www.baidu.com</i>"
})

return {
web
}
}
}).mount("#app")
</script>
</body>
</html>

响应式数据 ref reactive

基本语法为:

1
2
3
4
5
6
const number = ref(10)

const web = reactive({
title: "百度",
url: "www.baidu.com"
})

响应式数据顾名思义,通俗的理解就是源数据会顺应实时修改而变化,如果学过其他编程语言,我觉得可以理解成js封装好的特殊对象。

有两种形式:

  1. ref 用于存储基本的数据类型 这并不意味着ref只能存储单个数据,如果想要修改响应式数据的值,需要使用value属性。
  2. 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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>

<div id="app">
{{msg}}

<h2>{{web.title}}</h2>
<h2>{{web.url}}</h2>
<h2>{{number}}</h2>
<h2>{{arr}}</h2>
</div>

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

createApp({
setup() {

// ref用于存储基本的数据类型 单个类型的数据
const number = ref(10)
// 修改值
number.value = 20

const arr = ref([1,2,3])
arr.value[1] = 4


// reactive用于存储复杂的数据类型
const web = reactive({
title: "邓睿编程",
url: "dengruicode.com"
})

web.url = "www.baidu.com"

return {
msg: "success",
web,
number,
arr
}
}
}).mount("#app")
</script>

</body>
</html>

动态属性绑定 v-bind

以input标签作为例子,指令书写的格式为:

1
<input type="text" v-bind:value="web.url">

也可以缩写为:

1
<input type="text" :value="web.url">

下面是一个例子:

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">
<title>Title</title>

<style>
img {
height: 100px;
}

.textColor {
color: lightblue;
}
</style>
</head>
<body>
<div id="app">
<h3>dengruicode</h3>
<input type="text" value="dengruicode.com">

<h3>v-bind:value="web.url"</h3>
<input type="text" v-bind:value="web.url">

<h3>src="./img/二专.jpg"</h3>
<img src="./img/二专.jpg" alt="">

<h3>v-bind:src="web.url"</h3>
<img :src="web.img" alt="">


<h3>class="textColor"</h3>
<b class="textColor">邓瑞编程</b>

<h3>:class="{textColor:web.fontStatus}"</h3>
<b :class="{textColor:web.fontStatus}">邓瑞编程</b>


</div>


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

createApp({
setup() {

const web = reactive({
url: "wwww.dengruicode.com",
img: "./img/二专.jpg",
fontStatus: false
})

return {
web
}
}
}).mount("#app")
</script>
</body>
</html>

事件绑定 v-on

以button标签为例子,语法如下:

1
2
3
4
<button v-on:click="edit"></button>
<!-- 可缩写为@-->

<button @click="edit">修改</button>

click来监听DOM的点击事件的,本质就是使用了将js原生的一些方法绑定到Vue函数上,如果你的处理比较简单,还可以直接使用内联式,在html标签处就完成操作。

1
const count = ref(0)
1
<button @click="count++">Add 1</button>

如果还想要同时传入数据和原生DOM事件,可以使用$event变量

1
2
3
4
5
6
7
8
9
<!-- 使用特殊的 $event 变量 -->
<button @click="warn('Form cannot be submitted yet.', $event)">
Submit
</button>

<!-- 使用内联箭头函数 -->
<button @click="(event) => warn('Form cannot be submitted yet.', event)">
Submit
</button>
1
2
3
4
5
6
7
function warn(message, event) {
// 这里可以访问原生事件
if (event) {
event.preventDefault()
}
alert(message)
}

Vue甚至还提供了对键盘的监听,比较常见的有两种:

  1. keydown 按下键盘就触发
  2. keyup 按下后回弹才触发

keydownkeyup后面可以添加键盘字符名,以下是一些常见的字符键盘:

别名 说明
.enter 回车
.tab tab
.delete delete和backspace
.esc esc
.space 空格
.ctrl ctrl
.alt alt
.meta 在 Mac 键盘上,meta 是 Command 键 (⌘)。在 Windows 键盘上,meta 键是 Windows 键 (⊞)

以上的监听是非严格监听,意思是如果你按下其中某一个键,其余的键同时按下也会触发,如果想要严格监听,可以在末尾加上.exact

1
2
3
4
5
6
7
8
<!-- 当按下 Ctrl 时,即使同时按下 Alt 或 Shift 也会触发 -->
<button @click.ctrl="onClick">A</button>

<!-- 仅当按下 Ctrl 且未按任何其他键时才会触发 -->
<button @click.ctrl.exact="onCtrlClick">A</button>

<!-- 仅当没有按下任何系统按键时触发 -->
<button @click.exact="onClick">A</button>

看了上面的例子,你应该明白他也支持组合键监听

1
<input type="text" @keyup.ctrl.enter="add(40, 60)"> <br>

下面是一个例子:

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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
{{msg}}

<h2>{{web.url}}</h2>
<h2>{{web.user}}</h2>

<button v-on:click="edit">修改</button>
<br>
<button @click="edit">@修改</button>
<hr>

<!--keydown是按下就直接触发-->
<input v-on:keyup.enter="add(40,60)" type="text"><br>
回车<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(40, 60)"> <br>
Ctrl + A <input type="text" @keyup.ctrl.a="add(20, 30)">
</div>


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

createApp({
setup() {

const web = reactive({
url: "dengruicode.com",
user: 0
})

const edit = () => {
web.url = "www.baidu.com"
}


const add = (a, b) => {
web.user += a + b
}

return {
msg: "success",
web,
edit,
add
}

}
}).mount("#app")

</script>
</body>
</html>

显示与隐藏 v-show

以input标签作为例子,语法为:

1
<input type="text" v-show="web.show">

本质上是通过操作css属性中的display属性来控制标签的显示与否,需要传入一个布尔值,如果为true就显示,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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>

<div id="app">
{{web.show}}
<!-- v-show本质是生成了css的display属性-->
<p v-show="web.show">gcnanmu学Vue</p>

<hr>

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

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

createApp({
setup() {

const web = reactive({
show: true
})

const toggle = () => {
web.show = !web.show
}

return {
web,
toggle
}
}
}).mount("#app")
</script>
</body>
</html>

条件渲染 v-if

以p标签作为例子,语法如下:

1
2
3
<p v-if="web.user < 1000">新网站</p>
<p v-else-if="web.user >= 1000 && web.user < 10000">优秀网站</p>
<p v-else>资深网站</p>

这个语法和v-show很像,如果不满足判断的条件就会不显示标签,但是这与v-show操作display属性不太一样,他会直接将标签删除,因此会造成很大的性能开销。

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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
{{web.show}}
<hr>
<p v-show="web.show">百度 baidu.com</p>
<!-- 相比v-show v-if直接将元素进行了剔除-->
<!-- 不适合频繁切换元素的显示状态-->
<p v-if="web.show">github github.com</p>

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

<p v-if="web.user < 1000">新网站</p>
<p v-else-if="web.user >= 1000 && web.user < 10000">优秀网站</p>
<p v-else>资深网站</p>
</div>


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

createApp({
setup() {

const web = reactive({
show: true,
user: 20000
})

const toggle = () => {
web.show = !web.show
}

return {
web,
toggle
}
}
}).mount("#app")
</script>
</body>
</html>

遍历 v-for

以li标签作为例子,语法如下:

对于数组对象,可以拿到index和value两个值

1
2
3
4
5
<ul>
<li v-for="(value,index) in data.number">
index:{{index}} value:{{value}}
</li>
</ul>

对于自定义对象,可以拿到index,key,index三个值

1
2
3
4
5
<ul>
<li v-for="(value,key,index) in data.user">
index:{{index}} key:{{key}} value:{{value}}
</li>
</ul>

下面是一个例子:

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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>

<div id="app">
<ul>
<li v-for="value in data.number">
{{value}}
</li>
</ul>

<ul>
<li v-for="(value,index) in data.number">
index:{{index}} value:{{value}}
</li>
</ul>

<ul>
<li v-for="(value,key) in data.user">
key:{{key}} value:{{value}}
</li>
</ul>


<ul>
<li v-for="(value,key,index) in data.user">
index:{{index}} key:{{key}} value:{{value}}
</li>
</ul>


<ul>
<template v-for="(value,key,index) in data.user">
<li v-if="index == 1">
index:{{index}} key:{{key}} value:{{value}}
</li>
</template>
</ul>

<ul>
<template v-for="(value,index) in data.teacher">
<!-- 使用动态属性来设定标签属性 -->
<li :title="value.name" :key="value.id">
index:{{index}} id:{{value.id}} name:{{value.name}} web:{{value.web}}
</li>
</template>
</ul>
</div>


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

createApp({
setup() {

const data = reactive({
number: ["十", "十一", "十二"],
user: {
name: "gcnanmu",
gender: "man"
},
teacher: [
{id: 100, name: "百度", web: "baidu.com"},
{id: 101, name: "码云", web: "gitee.com"},
]

})

return {
data
}
}
}).mount("#app")
</script>
</body>
</html>

双向数据绑定 v-model

虽然refreactive确保了数据的响应式,但是它们本身并不实现自动收集用户输入并更新状态的逻辑。v-model正是为了简化这个过程:它自动更新绑定的响应式变量,无需手动编写事件监听器和数据更新逻辑。这对于表单数据的绑定尤其有用,可以极大简化代码。

区别在于

  • 单向数据绑定 当数据发生改变时, 视图会自动更新. 但用户手动更改 input 的值, 数据不会自动更新
  • 双向数据绑定 当数据发生改变时, 视图会自动更新. 当用户手动更改 input 的值, 数据也会自动更新

以input标签作为例子,语法如下:

1
<input type="text" v-model="data.radio">

下面是一个例子:

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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>

<div id="app">
<h3>文本框:{{data.text}}</h3>
<h3>单选框:{{data.radio}}</h3>
<h3>多选框:{{data.checkbox}}</h3>
<h3>记住密码:{{data.remember}}</h3>
<h3>下拉框:{{data.select}}</h3>

单项数据绑定:<input type="text" :value="data.text">
<hr>
双向数据绑定:<input type="text" v-model="data.text">
<hr>
<input type="radio" v-model="data.radio" id="one" value="1"><label for="one">写作</label>
<input type="radio" v-model="data.radio" id="two" value="2"><label for="two">画画</label>

<hr>

<input type="checkbox" value="1" v-model="data.checkbox">写作
<input type="checkbox" value="2" v-model="data.checkbox">画画
<input type="checkbox" value="3" v-model="data.checkbox">编程

<hr>

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

<select v-model="data.select">
<option value=""></option>
<option value="A">写作</option>
<option value="B">画画</option>
<option value="C">运动</option>
</select>

</div>

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

createApp({
setup() {

const data = reactive({
text: "dengruicode.com",
radio: "",
checkbox: [],
remember: false,
select: ""
})

return {
data
}
}
}).mount("#app")
</script>
</body>
</html>

计算属性 computed

computed是Vue中一个新的数据类型,语法为:

1
2
3
const sub = computed(() => {
return data.x - data.y
})

他作用是为计算添加本地缓存,相比无缓存的计算,如果出现相同的计算表达式,就不需要重复计算。

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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<h3>add:{{add()}}</h3>
<h3>add:{{add()}}</h3>
<h3>add:{{sub}}</h3>
<h3>add:{{sub}}</h3>

<!-- 如果不使用v-model.number返回的值是str类型-->
x <input type="text" v-model.number="data.x"> <br>
y <input type="text" v-model.number="data.y">
</div>


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

createApp({
setup() {

const data = reactive({
x: 10,
y: 20
})

// 无缓存
let add = () => {
console.log("add") // 打印两次
return data.x + data.y
}

// 有缓存 计算属性根据其依赖的响应式数据发生变化而重新计算
// 有缓存不需要重复计算
const sub = computed(() => {
console.log("sub") //打印一次
return data.x - data.y
})

return {
data,
add,
sub
}
}
}).mount("#app")
</script>
</body>
</html>

监听器 watch

watch是Vue中一个特殊的函数,语法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 通过监听hobby变量可以知道是否选择发生了改变
watch(hobby, (newValue, oldValue) => {
console.log("newValue", newValue, "oldValue", oldValue)
})

// 监听date的year变化
watch(() => date.year, (newValue, oldValue) => {
console.log("oldValue", oldValue, "newValue", newValue)

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

if (newValue === "2024") {
console.log("2024")
}
})

它可以监听绑定变量的数据变化情况,需要自己手动安装指定要监听的变量或者数据,可以实时查看值是否发生变化。

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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<select v-model="hobby">
<option value="">请选择</option>
<option value="1">写作</option>
<option value="2">画画</option>
<option value="3">运动</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>


<select v-model="date.month">
<option value="">请选择</option>
<option value="10">10</option>
<option value="11">11</option>
<option value="12">12</option>
</select>
</div>
<script type="module">
import {createApp, reactive, ref} from "./js/vue.esm-browser.js"
import {watch} from "./js/vue.esm-browser.js";

createApp({
setup() {

const hobby = ref("") // 爱好
const date = reactive({ // 日期
year: "2023",
month: "10"
})


// 通过监听可以知道是否选择发生了改变
watch(hobby, (newValue, oldValue) => {
console.log("newValue", newValue, "oldValue", oldValue)

if (newValue === "2") {
console.log("画画")
}
})


// JS中对象和数组是通过引用传递的,而不是通过值传递
// 当修改对象或数组的值时,实际上修改的是对象或数组的引用,而不是创建一个新的对象或数组
// 所以,如果修改了对象或数组的值,那么打印出来的结果则是修改后的值

watch(date, (newValue, oldValue) => {
console.log("newValue", newValue, "oldValue", oldValue)

if (newValue.year === "2025") {
console.log(2025)
}

if (newValue.month === "11") {
console.log("11")
}
})


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

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

if (newValue === "2024") {
console.log("2024")
}
})

return {
hobby,
date
}
}
}).mount("#app")
</script>
</body>
</html>

自动监听器 watchEffect

它是相对于watch模块需要手动监听的特点反过来提供一种自动监听的Vue函数,语法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
watchEffect(() => {
console.log("------ 监听开始")

if (hobby.value == "2") {
console.log("画画")
}

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

if (date.month == "11") {
console.log("11")
}

console.log("------ 监听结束")
})

他会监听网站上的所有数据变化。

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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<select v-model="hobby">
<option value="">请选择</option>
<option value="1">写作</option>
<option value="2">画画</option>
<option value="3">运动</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>


<select v-model="date.month">
<option value="">请选择</option>
<option value="10">10</option>
<option value="11">11</option>
<option value="12">12</option>
</select>
</div>
<script type="module">
import {createApp, reactive, ref, watchEffect} from "./js/vue.esm-browser.js"


createApp({
setup() {

const hobby = ref("") // 爱好
const date = reactive({ // 日期
year: "2023",
month: "10"
})


//自动监听
// 网页已加载就会自动执行
watchEffect(() => {
console.log("------ 监听开始")

if (hobby.value == "2") {
console.log("画画")
}

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

if (date.month == "11") {
console.log("11")
}

console.log("------ 监听结束")
})


return {
hobby,
date
}
}
}).mount("#app")
</script>
</body>
</html>

Vue案例

学了很多知识后,为了方便融汇贯通最好还是要做点综合案例来检测自己的学习的知识是否牢固。

图片轮播图

在没有使用前端框架的时候,我们需要大段的js代码去修改图片的链接,但是有了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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<h3 v-text="当前为num"></h3>
<img :src=`./img/${num}.png` :alt="num" style="height: 200px;">
<hr>

<button @click="sub">上一张</button>
<button @click="add">下一张</button>

<!-- $event.target是得到触发事件后的元素本身即input标签-->
<input type="text" @change="jump($event.target.value)" v-model.lazy="num">

<hr>
<ul>
<template v-for="(value,index) in 4">
<li>
<a href="#" @click="jump(value)">{{value}}</a>
</li>
</template>
</ul>
</div>


<script type="module">

import {createApp, ref} from "./js/vue.esm-browser.js"

createApp({
setup() {

const num = ref(3)

const add = () => {
if (num.value < 4) {
num.value++
} else {
num.value = 1
}
}

const sub = () => {
if (num.value >= 2) {
num.value--
} else {
num.value = 4
}
}

const jump = (value) => {
const numValue = parseInt(value); // 将输入的字符串转换为数字
if (isNaN(numValue)) {
return; // 如果转换结果是 NaN,则不做任何操作
}
if (numValue > 4) {
num.value = 4;
} else if (numValue < 1) {
num.value = 1;
} else {
num.value = numValue; // 确保 num.value 被更新为数字类型的值
}
}


return {
num,
add,
sub,
jump
}
}
}).mount("#app")

</script>
</body>
</html>

记事本

如果是在使用vue框架之前,如果想要完成一个todolist的效果,需要使用大量的js操作dom的函数,但是有了vue之后,我们只需要通过双向数据绑定操作原本的数据,再将数据通过v-for来展示在界面上即可。

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">
<title>Title</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>

<span>{{data.list.length}} </span>
<button @click="clear">清空</button>
</div>

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

createApp({
setup() {

const data = reactive({
content: "邓瑞编程",
list: ["baidu.net", "www.github.com"]
})


// 将文本输入框的值绑定为一个数据双向绑定的值
const add = () => {
data.list.push(data.content)

}

const del = (index) => {
data.list.splice(index, 1)
console.log(data.list)
}


const clear = () => {
data.list = []
}

return {
data,
add,
del,
clear
}
}
}).mount("#app")
</script>
</body>
</html>

购物车

这个案例就稍微复杂很多,加入了多选框之后要判断的情况会较多,但是依然能体会到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
167
168
169
<!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>商品</td>
<td>单价</td>
<td>库存</td>
<!-- 相邻边框合并为单一边框-->
<td colspan="2">操作</td>
</tr>
</thead>

<tbody>
<!-- 从 data.list 中删除一个项目时,Vue.js 的响应式系统会自动更新 DOM,以反映数据的变化。-->
<tr v-for="(value,index) in data.list">
<!-- 需要特定的value作为唯一的标识 -->
<!-- Vue.js 内部会根据 v-model 绑定的数组和当前复选框的值来决定复选框是否应该被勾选 -->
<td><input type="checkbox" :value="value" v-model="data.checkboxList" @change="checkSelect"></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>
</tr>
</tfoot>
</table>
</div>


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

createApp({

setup() {

const selectAll = () => {
console.log(data.selected)
if (data.selected) {
data.checkboxList = data.list
} else {
data.checkboxList = []
}
// 如果商品被删完了就取消全选状态
checkSelect()
}

const checkSelect = () => {
console.log(data.checkboxList)
// 这里要注意购物车为空的情况
if (data.checkboxList.length === data.list.length && data.list.length !== 0) {
data.selected = true
} else {
data.selected = false
}
}

const del = (index, id) => {
data.list.splice(index, 1)
// 其实是不用自己去删除checklist中的数据的
// 由于 data.checkboxList 是通过 v-model 与复选框绑定的,
// Vue.js 会自动处理 data.checkboxList 与复选框的同步。
// 当 data.list 更新时,
// Vue.js 会检查 data.checkboxList 中的每一项是否仍然存在于 data.list 中,
// 如果不存在,相应的复选框将不再被勾选。
}


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 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 sub = (value) => {
if (value.number > 1) {
value.number--
}
}

const add = (value) => {
if (value.number < value.stock) {
value.number++
}
}

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

购物车(优化)

我们不再单独写函数来处理数据的变化,使用watch函数来监听数据的变化并做出反应:

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
<!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>
<!-- 从 data.list 中删除一个项目时,Vue.js 的响应式系统会自动更新 DOM,以反映数据的变化。-->
<tr v-for="(value,index) in data.list">
<!-- 需要特定的value作为唯一的标识 -->
<!-- Vue.js 内部会根据 v-model 绑定的数组和当前复选框的值来决定复选框是否应该被勾选 -->
<td><input type="checkbox" :value="value" v-model="data.checkboxList" @change="checkSelect"></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>

</tr>
</tfoot>
</table>
</div>


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

createApp({

setup() {

const del = (index, id) => {
data.list.splice(index, 1)
// 其实是不用自己去删除checklist中的数据的
// 由于 data.checkboxList 是通过 v-model 与复选框绑定的,
// Vue.js 会自动处理 data.checkboxList 与复选框的同步。
// 当 data.list 更新时,
// Vue.js 会检查 data.checkboxList 中的每一项是否仍然存在于 data.list 中,
// 如果不存在,相应的复选框将不再被勾选。
}


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 totalPrice = computed(() => {

/*
* reduce:用于对数组元素中的所有元素进行迭代操作,并将每次操作累加到一个初始值上
* 接受两个参数:一个是累加函数、另一个是初值
* reduce将data.checkboxList数组中的每个checkbox对象的price和number属性进行相乘
* 并将结果累加到初始值0上,最后返回相加的结果
* */

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

const sub = (value) => {
if (value.number > 1) {
value.number--
}
}

const add = (value) => {
if (value.number < value.stock) {
value.number++
}
}

watch(() => data.selected, (newValue, oldValue) => {
// console.log("newValue", newValue, "oldValue", oldValue)

if (newValue) {
data.checkboxList = data.list
} else {
data.checkboxList = []
}
})

watch(() => data.checkboxList, (newValue, oldValue) => {
console.log("newValue", newValue, "oldValue", oldValue)
// 这句不用写,实际已经变为了新值
// data.checkboxList = newValue
})

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

文章搜索

一般来说网页的数据都是通过API文档发送的,API中的格式一般为json格式,下面是一个通过API来实现文章搜索的案例。

请求的方式也分为get和post请求两种。

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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="js/axios.js"></script>
</head>
<body>
<div id="app">
<select v-model="data.type">
<option value="0">请选择</option>
<option value="1">ID</option>
<option value="2">标题</option>
</select>

<input type="text" v-model="data.content">
<button @click="search()">搜索</button>
<br>

<ul>
<li v-for="(value,index) in data.list">
{{value}}
</li>
</ul>
</div>

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


createApp({
setup() {

const data = reactive({
type: "0", // 搜索类型
content: "", // 搜索内容
list: []
})

const search = () => {
console.log("搜索类型", data.type, "搜索内容", data.content)

data.list = []

if (data.type === "1") {
let id = data.content

axios.get(`http://localhost/article/get/id/${id}`).then(
response => {
console.log("get,data", response.data)

if (response.data.status === "success") {
data.list.push(response.data.data)
}
}
).catch(error => {
console.log("get.error", error)
})
} else if (data.type === "2") {
let param = {
title: data.content
}

axios.post('http://127.0.0.1/article/postJson/search', param).then(
response => {
console.log("post.data", response.data)

if (response.data.status === "success") {

for (let i = 0; i < response.data.data.length; i++) {
data.list.push(response.data.data[i])
}

}
}
).catch(error => {
console.log("post.error", error)
})
}
}

return {
data,
search
}
}
}).mount("#app")
</script>
</body>
</html>