Vue2 快速入门
渐进式 JavaScript 框架
# 指令(Directives)
# 1. 插值表达式:{{}}
<template>
<div id="app">
<!-- 插值表达式:向元素中插入数据,不会覆盖标签中原有的内容 -->
<span>姓名: {{ username }}</span>
</div>
</template>
2
3
4
5
6
# 2. v-text
<template>
<div id="app">
<!-- v-text:会覆盖标签中原有的内容,不识别标签样式及属性 -->
<span v-text="username">原有内容</span>
</div>
</template>
2
3
4
5
6
# 3. v-html
<template>
<div id="app">
<!-- v-html:会覆盖标签中原有的内容,且识别标签及样式属性 -->
<span v-html="username">原有内容</span>
</div>
</template>
2
3
4
5
6
# 4. v-bind(简写 : )
<template>
<div id="app">
<!-- v-bind:给元素的属性 动态的绑定 属性值(单项数据绑定) -->
<input type="text" v-bind:value="msg">
<!-- 简写 -->
<input type="text" :value="msg">
<!-- 可以为表达式 -->
<input type="text" :value="10 + num">
<!-- 通过 v-bind 绑定类样式 -->
<div :class="'red'">设置类样式</div>
<div :class="['red', 'color']">设置多个类样式</div>
<div :class="{ active: flag }">当 flag 为真时,则添加 active 类</div>
<!-- 通过 v-bind 绑定内联样式 -->
<div :style="`background: url(${bj})`">设置内联样式</div>
</div>
</template>
<script>
export default {
data() {
return {
flag: true,
bj: "http://localhost:8080/background/bg.jpg"
}
}
};
</script>
<style lang="less" scoped>
.red {background-color: red;}
.font {font-size: 30px;}
.color {color: #fff;}
.active {background-color: purple;color: orange;}
</style>
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
# 5. v-on(简写 @ )
<template>
<div id="app">
<!-- v-on:给元素绑定事件,并执行 add 方法 -->
<button v-on:click="add">+</button>
<!-- 简写 -->
<button @click="add(1)">+</button>
<!-- 事件修饰符 -->
<!-- .stop:阻止冒泡(只想触发本身,不想让父级触发) -->
<input type="button" value="按钮" @click.stop="btn">
<!-- .prevent:阻止默认事件行为(a 链接,只触发事件不想让它跳转) -->
<a href="http://www.baidu.com" @click.prevent="btn">百度一下</a>
<!-- 其它事件修饰符
.capture:事件捕获模式(从外到里的顺序触发事件),先触发父级
.self:只触发本身
.once:事件只触发一次
-->
</div>
</template>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 6. v-model(双向绑定)
<template>
<div id="app">
<!-- v-model:给表单元素双向绑定数据(监听用户输入的内容,并将内容更新到数据源中,从而渲染到页面中) -->
用户名: <input type="text" v-model="username">
<p>您输入的用户名为: {{ username }}</p>
<!-- .trim 自动过滤掉用户输入的空白字符 -->
<input type="text" v-model.trim="username">
<!-- .number 自动将用户输入的内容,转化为 数值型 -->
<input type="text" v-model.number="username">
<!-- .lazy 当用户内容输入完毕,光标离开时,才将用户输入的内容更新到数据源中 -->
<input type="text" v-model.lazy="username">
</div>
</template>
<script>
export default {
data() {
return {
username: "请输入您的姓名",
}
}
}
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
注意:v-model 只能运用在表单元素中,表单中的 value 可以省略不写
v-model 作用:双向数据绑定,用来辅助开发者在不操作DOM的前提下,快速获取表单的数据
# 7. v-if、v-show
<template>
<div id="app">
<button @click="flag = !flag">显示/隐藏</button>
<h2 v-if="flag">这是用 v-if 控制的元素</h2>
<h2 v-show="flag">这是用 v-show 控制的元素</h2>
<!-- v-if 可以搭配 v-else-if 和 v-else 一起使用 -->
<div v-if="type == 'A'">优秀</div>
<div v-else-if="type == 'B'">一般</div>
<div v-else>较差</div>
</div>
</template>
<script>
export default {
data() {
return {
flag: true,
type: "A"
}
}
}
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
v-if 和 v-show 的区别(共同点:根据表达式的真假,来切换元素的显示状态)
v-if 原理:根据表达式的真假,来 创建/删除 元素 (有较高的切换性能消耗,如果元素切换频率较低时,推荐使用)
v-show 原理:根据表达式的真假,来 修改 display 的值(有较高的初始渲染消耗,如果元素切换频率较高时,推荐使用)
# 8. v-for
<template>
<div id="app">
<ul>
<!-- 1. 遍历数组 -->
<li v-for="item in list">{{ item }}</li>
<li v-for="(item,index) in list">索引: {{index}} --- 每一项: {{item}}</li>
<!-- 2. 遍历对象 -->
<li v-for="value in obj">{{ value }}</li>
<li v-for="(value, key) in obj">{{ key }} --- {{ value }}</li>
<!-- 3. 遍历列表中的对象 -->
<li v-for="item in arr" :key="item.id">姓名:{{ item.name }} --- 年龄:{{ item.age }}</li>
<!-- 4. 遍历数字(从 1 开始) -->
<li v-for="count in 10">这是第{{ count }}次循环</li>
</ul>
</div>
</template>
<script>
export default {
data() {
return {
list: ["清华", "北大", "复旦", "浙大"],
obj: { name: "刘德华", sex: "男" },
arr: [
{ id: 1, name: "张三", age: 18 },
{ id: 2, name: "李四", age: 20 }
],
}
}
}
</script>
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
- (1). 组件中使用 v-for 指令的时候,需要绑定一个 :key 属性,并推荐把 id 做为 key 的值
- (2). key 属性的值不能重复(具有唯一身份)且 key 属性的值,类型必须为数字或字符串
- (3). 在 .vue 文件中,如果没有 key 属性,会报错
# 过滤器(Filters)
过滤器是一个函数,常用于文本的格式化(在 Vue3 中不再使用)
过滤器可用在两个地方:插值表达式 和 v-bind 属性绑定。
过滤器应该被添加在 JavaScript 表达式的尾部,由 "|" 管道符,进行调用
# 1. 私有过滤器
<template>
<div class="box">
<!-- 在 插值表达式中 通过 | 调用过滤器函数,对 message 的值进行格式化(首字母大写) -->
<p>插值表达式的值为: {{ message | capi }}</p>
<!-- 在 V-bind中 通过 | 调用过滤器 -->
<input type="text" :value="message | capi">
</div>
</template>
<script>
export default {
data() {
return {
message: "hello vue.js",
};
},
// 私有过滤器
filters: {
// 过滤器函数中的 形参val,永远都是"管道符" 前面的值(message属性的值)
capi(val) {
console.log(val); // hello vue.js
// 使用 charAt() 方法,根据索引号查找字符,将查找到的第一个字符转化为大写
const first = val.charAt(0).toUpperCase();
// 使用 slice() 方法,截取字符串(截取 索引号为1 后面的全部字符)
const other = val.slice(1);
// 过滤器中,一定要有一个返回值(把message格式化后的值,更新到插值表达式中)
return first + other;
},
},
};
</script>
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
# 2. 全局过滤器
(1). 在 utils/filter.js 文件中,定义全局过滤器
import Vue from "vue"
// 第一个参数,是全局过滤器的名字;第二个参数,是全局过滤器的处理函数
Vue.filter("capi", (val) => {
const first = val.charAt(0).toUpperCase()
const other = val.slice(1)
return first + other
})
2
3
4
5
6
7
8
(2). 在 main.js 入口文件中,导入全局过滤器
import "@/utils/filter.js"
(3). 在组件中使用
<template>
<div class="box">
<p>插值表达式的值为: {{ message | capi }}</p>
</div>
</template>
<script>
export default {
data() {
return {
message: "hello vue.js"
}
}
};
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
# 3. 给过滤器传参
<template>
<div class="box">
<!-- 通过 管道符 | 调用过滤器 capi 并传入两个参数 -->
<p>插值表达式的值为: {{ num | capi(20, 30) }}</p>
</div>
</template>
<script>
export default {
data() {
return {
num: 50
}
},
filters: {
capi(val, num1, num2) {
const sum = val + num1 + num2
return sum;
},
},
};
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 侦听器(watch)
本质上是一个函数,用于监视数据的变化(当监听的数据发生变化时,就自动触发一次这个函数)
侦听器有两种写法:(都应该被定义到 watch 节点下)
1. 方法格式的侦听器
缺点1:刚进入界面,无法自动触发
缺点2:无法侦听 对象中属性 的变化
2. 对象格式的侦听器
好处1:可通过 immediate 选项,让侦听器是否进入页面时自动触发一次
好处2:可通过 deep 选项,让侦听器深度监听对象中每个属性的变化
# 1. 侦听器(方法格式)
<template>
<div class="box">
<button @click="count++">值 + 1</button>
</div>
</template>
<script>
export default {
data() {
return {
count: 1
}
},
// 所有的侦听器,都应该被定义到 watch 节点下
watch: {
// 监听 count 数据的变化(侦听谁,就把谁当作方法名)
// 当 count 值发生变化时,就会调用这个函数
count(newVal, oldVal) {
console.log("新值为:", newVal);
console.log("旧值为:", oldVal);
}
}
};
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
注意:方法格式的侦听器,无法侦听 对象中属性 的变化;刚进入页面时不会自动触发
# 2. 侦听器(对象格式)
<template>
<div class="box">
<button @click="obj.count++">值 + 1</button>
</div>
</template>
<script>
export default {
data() {
return {
obj: {
count: 1
}
}
},
watch: {
// 定义 对象格式 的侦听器(监听 obj 对象中 count 属性的变化)
"obj.count": {
// handler 是固定写法,表示当 obj.count 的值发生变化,自动调用 handler 处理函数
handler(newVal, oldVal) {
console.log("新值为:", newVal);
console.log("旧值为:", oldVal);
},
immediate: true // 进入页面时,自动触发一次
}
}
};
</script>
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
注意:对象格式的侦听器可通过 immediate 选项,让侦听器是否进入页面时自动触发一次
# 3. 深度侦听(开启 deep 选项)
<script>
export default {
watch: {
// 定义 对象格式 的侦听器(监听 obj 对象的变化,需要开启深度监听)
obj: {
handler(newVal, oldVal) {
console.log("新对象为:", newVal);
console.log("旧对象为:", oldVal);
},
immediate: true,
deep: true // 开启深度监听,只要对象中任何一个属性发生变化,都会触发这个侦听器
}
}
};
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 计算属性(computed)
计算属性作用:通过一系列运算后,得到一个全新的值
(1). 必须定义成函数的形式,且必须要有返回值(通过一系列计算得到的新值)
(2). 不能写异步操作
(3). 所依赖的属性不变的时候会调用缓存
<template>
<div class="box">
<!-- 2. 模板中直接渲染 -->
<span>{{ num }}</span>
</div>
</template>
<script>
export default {
// 所有的计算属性,都应该被定义到 computed 节点下
computed: {
// 1. 定义计算属性:直接在模板中渲染(渲染出来的值:是通过一系列计算后返回的新值)
num() {
return 100 + 100
}
},
};
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
案例:动态的 RGB 颜色
<template>
<div class="player">
<div>R: <input type="text" v-model="r" /></div>
<div>G: <input type="text" v-model="g" /></div>
<div>B: <input type="text" v-model="b" /></div>
<div>透明度: <input type="text" v-model="a" /></div>
<!-- 模板中直接渲染 -->
<div class="box" :style="{ backgroundColor: rgb }">
<span>{{ rgb }}</span>
</div>
</div>
</template>
<script>
export default {
data() {
return {
r: 0,
g: 0,
b: 0,
a: 0.5
};
},
computed: {
rgb() {
// 返回一个动态的属性值:rgba(x,x,x,x) 格式的字符串
return `rgba(${this.r}, ${this.g}, ${this.b}, ${this.a})`;
},
},
};
</script>
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
# 自定义属性(props)
props 是一个自定义属性,是用来传递数据的(父向子传值)
(1). props 是只读的,不要直接修改它的值,否则终端会报错(如果需要修改,可以转存到 data 中,再修改)
(2). props 的类型,可以为 字符串数组 或 对象
(3). props 中的数据,可以直接渲染到模板结构中
# 1. props(字符串数组格式)
// 父组件:给子组件绑定自定义属性(子组件可以通过 props 来接收自定义属性的值)
<template>
<div id="app">
<!-- 绑定自定义属性:用于给子组件传值 -->
<hello-world uname="张三" :age="18"></hello-world>
</div>
</template>
// 子组件:使用 props 来接收值(字符串数组的格式)
<template>
<div class="hello">
<span>姓名: {{ uname }}</span>
<span>年龄:{{ count }}</span>
<button @click="count++">年龄 + 1</button>
</div>
</template>
<script>
export default {
// 通过 props 来接收自定义属性的值(可以在模板中直接渲染)
props: ["uname", "age"],
// props 中的数据是只读的,如果需要修改 可以转存到 data 中,再修改
data() {
return {
count: this.age
}
}
};
</script>
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
# 2. props(对象格式)
// 父组件:按照子组件的规定,给子组件绑定自定义属性(子组件可以通过 props 来接收自定义属性的值)
<template>
<div id="app">
<!-- 绑定自定义属性:用于给子组件传值 -->
<hello-world uname="张三" :age="18"></hello-world>
</div>
</template>
// 子组件:通过 props 来接收自定义属性的值(对象格式)
<template>
<div class="hello">
<span>姓名: {{ uname }}</span>
<span>年龄:{{ age }}</span>
</div>
</template>
<script>
export default {
// 对象格式:规定父组件 在使用 当前组件时的一些限制,并接收自定义属性的值(可以在模板中直接渲染)
props: {
uname: {
default: "李四", // 自定义属性的默认值(在使用当前组件时,如果没有绑定 uname 属性时,则默认值生效)
type: String, // 规定自定义属性值的类型
},
age: {
default: "",
type: [Number, String],
required: true // required 必填项校验(在使用当前组件时,必须绑定 age 属性)
}
}
};
</script>
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
# 生命周期
生命周期:是指一个组件从 创建 -> 运行 -> 销毁,这整个过程就叫做"生命周期"
生命周期函数:是由 Vue 框架提供的内置函数,会伴随着组件的生命周期,自动按次序执行。
组件的生命周期分为三个阶段:组件创建阶段、组件运行阶段、组件销毁阶段(每个阶段都有对应的生命周期钩子)
1. 创建阶段:生命周期函数只执行1次(按次序依次执行)
| 函数名 | 阶段 | 说明 |
|---|---|---|
| beforeCreate | 创建前 | 组件还未创建,什么事都不能做 |
| created | 创建完成(组件已经创建完成) | props、data、methods,都处于可用状态 |
| beforeMount | 挂载前 | 不能操作 DOM 元素 |
| mounted | 挂载完成(DOM结构渲染完成) | 可以操作 DOM 元素 |
2. 运行阶段:生命周期函数最少执行1次,最多执行N次(数据发生变化时才执行)
| 函数名 | 阶段 | 说明 |
|---|---|---|
| beforeUpdate | 更新之前 | 还未把最新数据,重新渲染到模板结构中 |
| updated | 更新成功(完成了 DOM 结构的重新渲染) | 此时可以操作到最新的 DOM 元素 |
3. 销毁阶段:生命周期函数只执行1次(按次序依次执行)
| 函数名 | 阶段 | 说明 |
|---|---|---|
| beforeDestroy | 销毁前 | 组件还处于正常工作状态 |
| destroyed | 销毁完成(组件已经被销毁) | 浏览器中对应的 DOM 结构已被完全移除 |
重点掌握 created、mounted 和 updated 这3个生命周期钩子函数
# 组件间的数据共享
# 1. 父向子传值(props)
参考:父向子传值
# 2. 子向父传值($emit)
参考:子向父传值
# 3. 兄弟间传值(eventBus)
参考:兄弟间传值
# ref 引用
ref:用来辅助开发者在不依赖于 jQuery 的情况下获取 DOM 元素 或 组件实例的引用
(1). 每个 vue 的组件实例上都包含一个 $refs 对象,里面存储着对应的 DOM 元素或组件的引用
(2). 默认情况下,组件的 $refs 指向一个空对象
(3). ref 引用组件实例:可以获取到该组件中的数据和方法
# 1. ref 引用 DOM 元素
<template>
<div class="box">
<h1 ref="myh1">我是h1</h1>
<button @click="change">h1变红</button>
</div>
</template>
<script>
export default {
methods: {
change() {
// 使用 $refs 来获取元素,并将文本颜色改为红色
this.$refs.myh1.style.color = "red"
}
}
};
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 2. ref 引用组件实例
// 父组件
<template>
<div id="app">
<!-- 1. 使用 ref 属性,为对应的"组件"添加引用名称(要引用哪个组件,就给该组件添加 ref 属性) -->
<hello-world ref="hello"></hello-world>
<button @click="getRef">获取 $refs 引用</button>
</div>
</template>
<script>
import HelloWorld from "@/components/HelloWorld.vue"
export default {
components: {
HelloWorld
},
methods: {
getRef() {
// 2. 通过 this.$refs.引用的名称 可以获取到 HelloWorld 组件中的方法和数据
console.log(this.$refs.hello);
console.log(this.$refs.hello.count); // 获取 HelloWorld 组件中的数据
this.$refs.hello.add() // 调用 HelloWorld 组件中的方法
}
},
};
</script>
// HelloWorld 子组件
<script>
export default {
data() {
return {
count: 1,
}
},
methods: {
add() {
this.count++
}
}
};
</script>
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
# 3. this.$nextTick()
this.$nextTick 作用:等 DOM 结构渲染完成后,再执行回调函数里面的代码
注意:在 created 生命周期函数中,如果需要操作DOM元素,一定要写在 this.$nextTick() 回调函数中
<div class="box3" ref="mydiv">ref引用</div>
<script>
export default {
// 注意:在 created 生命周期函数中,数据已经有了,但是页面结构还未被渲染
created() {
// this.$nextTick 表示:等 DOM 结构渲染完成后,再执行回调函数里面的代码
this.$nextTick(() => {
this.$refs.mydiv.style.color = "blue"
})
},
};
</script>
2
3
4
5
6
7
8
9
10
11
12
13
# 动态组件
# 1. components(动态渲染组件)
components:内置标签,是一个占位符,用于给组件预留位置(is 属性的值:表示要展示哪个组件)
被展示的组件会被创建,而被隐藏的组件会被销毁,因此每一次切换,组件都会被重新渲染/重新创建(数据会被初始化,不会保持状态)
<template>
<div id="app">
<button @click="comName = 'Left'">展示 Left 组件</button>
<button @click="comName = 'Right'">展示 Right 组件</button>
<!-- components:内置标签,是一个占位符,用于给组件预留位置(is 属性的值:表示要展示哪个组件) -->
<components :is="comName"></components>
</div>
</template>
<script>
import Left from "@/components/Left.vue"
import Right from "@/components/Right.vue"
export default {
components: {
Left,
Right
},
data() {
return {
comName: "Left" // 要展示组件的名称(默认展示 Left 组件)
}
}
};
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 2. keep-alive(保持状态)
keep-alive 内置标签:用于给组件保持状态
注意:所有被 keep-alive 包裹的组件都会被缓存,而不是销毁
<keep-alive>
<components :is="comName"></components>
</keep-alive>
2
3
# 3. include 属性(指定缓存)
keep-alive 内置标签的属性:include 属性(指定哪些组件需要被缓存)、exclude 属性(指定哪些组件不需要被缓存)
注意:include 和 exclude 属性不能同时使用,指定多个组件时用逗号分隔
<keep-alive include="Left,Right">
<components :is="comName"></components>
</keep-alive>
2
3
- 如果声明组件的时候,我们指定了组件的 name 名称,include 和 exclude 属性的值则要与指定的组件名称一致
# 4. keep-alive 的生命周期函数
注意:只有被 keep-alive 内置标签所包裹的组件,才可以使用 activated 和 deactivated 这两个生命周期函数
(1). activated 生命周期函数:组件被 激活/展示 时的生命周期函数
(2). deactivated 生命周期函数:组件被 缓存/隐藏 时的生命周期函数
<template>
<div class="left">
<h2>我是 Left 组件</h2>
<h2>当前值为: {{ count }}</h2>
<button @click="count += 1">值 + 1</button>
</div>
</template>
<script>
export default {
data() {
return {
count: 1
}
},
activated() {
console.log("Left 组件被激活了");
},
deactivated() {
console.log("Left 组件被缓存了");
}
}
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 插槽(slot)
参考:插槽
# 自定义指令(directives)
# 1. 私有自定义指令
<template>
<div id="app">
<!-- 2. 绑定自定义指令 -->
<h2 v-color="textColor">我是绑定了自定义指令的元素</h2>
<button @click="textColor = 'green'">变色</button>
</div>
</template>
<script>
export default {
data() {
return {
textColor: "red"
}
},
// 1. 定义自定义指令
directives: {
// 定义一个 v-color 的指令,指向一个配置对象(提供几个函数,可选)
color: {
// (1). bind 函数:只触发一次,当元素第一次绑定该指令的时候触发(数据的更新不会再次渲染)
bind(el, binding) {
// el:绑定该指令的元素(可以用来操作 DOM 元素)、binding:是一个对象
el.style.color = binding.value // bingding.value:指令的绑定值(red)
},
// (2). update 函数:当 DOM 更新的时候触发
update(el, binding) {
el.style.color = binding.value
},
// (3). inserted、componentUpdated、unbind 函数,查阅文档了解
},
// 简写(方法格式):当 bind 和 update 函数执行代码相同时,且并不关心其他函数,可采取方法格式的简写形式
color(el, binding) {
el.style.color = binding.value
}
}
}
</script>
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
# 2. 全局自定义指令
在 main.js 入口文件中,定义全局自定义指令
// 对象格式
Vue.directive("title", { // title 是全局指令的名称
bind(el, binding) {
el.style.color = binding.value
},
update(el, binding) {
el.style.color = binding.value
}
})
// 方法格式
Vue.directive("title", function(el, binding) {
el.style.color = binding.value
})
2
3
4
5
6
7
8
9
10
11
12
13
14
# 路由(router)
参考:路由(vue-router)
参考:路由传参(实现页面跳转)