目录

[TOC]

安装及项目初始化

认识create-vue

create-vue是Vue官方新的脚手架工具,底层切换到了 vite (下一代前端工具链),为开发提供极速响应

image.png

使用create-vue创建项目

1
2
3
4
# 前置条件 - 已安装16.0或更高版本的Node.js

# 执行如下命令,这一指令将会安装并执行 create-vue
npm init vue@latest

image.png

熟悉项目和关键文件

image.png

语法

setup

1
2
3
4
5
6
7
<!-- setup写法 -->
<script setup>
const message = 'this is message'
const logMessage = () => {
console.log(message)
}
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!-- 旧版本写法 -->
<script>
export default {
setup() {
const message = 'this is message'
const logMessage = () => {
console.log(message)
}
// 必须return才可以
return {
message,
logMessage
}
}
}
</script>

reactive和ref函数

reactive

接受对象类型数据的参数传入并返回一个响应式的对象接受对象类型数据的参数传入并返回一个响应式的对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<script setup>
// reactive只能支持对象类型
import {reactive} from "vue";

// reactive里面定义各种属性
const person = reactive({
id: 0,
username: 'XiaoFei',
age: 18
})

// 创建一个函数
const addAge = () => {
person.age++
}
</script>

<template>
<div>person对象信息:{{ person }}</div>
<button @click="addAge">点击添加年龄:{{ person.age }}</button>
</template>

ref

接收简单类型或者对象类型的数据传入并返回一个响应式的对象

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
<script setup>
// ref 函数可以接收普通类型,也可以接收对象,ref定义的,需要在获取的时候 .value
import {ref} from "vue";

// ref接收普通类型值
const count = ref(0)

// ref接收对象类型值
const person = ref({
id: 0,
username: 'XiaoFei',
age: 18
})

// 定义一个函数
const addCount = () => {
count.value++
}

// 定义函数
const addAge = () => {
person.value.age++
}

</script>

<template>
<div>普通类型值</div>
<div>count:{{ count }}</div>
<button @click="addCount">点击添加</button>

<div>传入对象</div>
<div>person:{{ person }}</div>
<button @click="addAge">点击添加</button>
</template>

reactive对比ref

  • 都是用来生成响应式数据
  • 不同点
    • reactive不能处理简单类型的数据
    • ref参数类型支持更好,但是必须通过.value做访问修改
    • ref函数内部的实现依赖于reactive函数
  • 在实际工作中的推荐
    • 推荐使用ref函数,减少记忆负担

computed

  • 计算属性中不应该有“副作用”,比如异步请求 / 修改dom
  • 避免直接修改计算属性中的值,计算属性应该只读的
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<script setup>
// 导入
import {ref, computed} from 'vue'

// 原始数据
const list = ref([1, 2, 3, 4, 5, 6, 7, 8])

// 计算属性后数据
const computedList = computed(() => {
// 返回数组中 > 2的值
return list.value.filter(item => item > 2)
})
</script>

<template>
<div> 原始数据 —— {{ list }} </div>
<div> 计算属性数据 —— {{ computedList }} </div>
</template>

watch

属性监听,当属性的值改变时,触发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
<script setup>
// 导入watch
import {ref, watch} from 'vue'

const count = ref(0)
const age = ref(0)

const addCountAndAge = () => {
count.value++
age.value++
}

// 调用 watch 侦听单个数据变化
watch(count, (newValue, oldValue) => {
console.log("调用 watch 侦听单个数据变化")
console.log('count', count.value, newValue, oldValue)
})

// 调用 watch 侦听多个数据变化【多个值使用[]接收】
watch([count, age], ([countNewValue, ageNewValue], [countOldValue, ageOldCount]) => {
console.log("调用 watch 侦听多个数据变化")
console.log('count', count.value, countNewValue, countOldValue)
console.log('age', age.value, ageNewValue, ageOldCount)
})
</script>

<template>
<div>
<button @click="addCountAndAge">Count:{{ count }}</button>
<br/>
<button @click="addCountAndAge">Age:{{ age }}</button>
</div>
</template>

immediate

immediate:watch的第三个参数,传入对象,immediate设置为true,会先执行一次watch的回调函数,不用等监听的属性值改变

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<script setup>
// 导入watch
import {ref, watch} from 'vue'

const count = ref(0)

const addCountAndAge = () => {
count.value++
}

// 调用 watch 侦听单个数据变化 ,immediate为watch的第三个参数
// immediate设置为true 会先执行一次watch的回调函数,不用等监听的属性值改变
watch(count,() => {
console.log("watch回调函数执行了")
}, {immediate: true})
</script>

<template>
<div>
<button @click="addCountAndAge">Count:{{ count }}</button>
</div>
</template>

deep

通过watch监听的ref对象默认是浅层侦听的,直接修改嵌套的对象属性不会触发回调执行,需要开启deep,deep开启有性能损耗,尽量不使用deep

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
<script setup>
// 导入watch
import {ref, watch} from 'vue'

const person = ref({
age: 18,
count: 1
})

const updateAge = () => {
person.value.age++
}

const updateCount = () => {
person.value.count++
}

// 在watch的第三个参数设置 deep:true ,watch才能监听ref设置的对象属性,此时,对象中无论哪个值改变都会触发watch的回调
watch(
person,
() => {
console.log("person修改了", person.value)
},
{deep: true}
)

// 在watch的第三个参数设置 deep:true ,watch才能监听ref设置的对象属性,此时,指定的对象中的属性的值修改了才能触发watch的回调
watch(
() => {
person.value.age
},
() => {
console.log("person修改了", person.value)
},
{deep: true}
)
</script>

<template>
<div>
<button @click="updateAge">修改age:{{ person.age }}</button>
<br/>
<button @click="updateCount">修改count:{{ person.count }}</button>
</div>
</template>

生命周期函数

选项式:vue2

组合式:vue3

image.png

使用import从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
<script setup>
// 生命周期
import {onBeforeMount, onMounted, onBeforeUpdate, onUpdated, onBeforeUnmount, onUnmounted} from 'vue'

onBeforeMount(() => {
console.log("onBeforeMount1")
})
//同一个生命周期函数可以同时写多个,会按照顺序执行
onBeforeMount(() => {
console.log("onBeforeMount2")
})

onMounted(() => {
console.log("onMounted")
})

onBeforeUpdate(() => {
console.log("onBeforeUpdate")
})

onUpdated(() => {
console.log("onUpdated")
})

onBeforeUnmount(() => {
console.log("onBeforeUnmount")
})

onUnmounted(() => {
console.log("onUnmounted")
})
</script>

组件间通信

父传子

父组件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<script setup>
// 引入子组件
import Son from './Son.vue'
import {ref} from "vue";

const person = ref({
name: "XiaoFei",
age: 18
})
</script>

<template>
<div>
<!-- 可以传入上面定义的参数 -->
<son :person="person"/>
</div>
</template>

子组件

1
2
3
4
5
6
7
8
9
10
11
12
13
<template>
<div>子组件接收的数据:{{ props }}</div>
</template>

<script setup>
// 子组件接收数据
const props = defineProps({
//参数名:参数类型
person: Object
})

console.log(props.person)
</script>

子传父

父组件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<script setup>
// 引入子组件
import Son from './Son.vue'

const getSonData = (sonData) => {
console.log("子组件传递的数据:", sonData)
}
</script>

<template>
<div>
<!-- 可以传入上面定义的参数 -->
<son @get-son-data="getSonData"/>
</div>
</template>

子组件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<script setup>
import {ref} from "vue";

const person = ref({
name: "XiaoFei",
age: 18
})

// 通过 defineEmits 编译器宏生成emit方法
const emit = defineEmits(['get-son-data'])

const sentMsg = () => {
// 触发自定义函数 向父组件传输数据
emit('get-son-data', person)
}
</script>
<template>
<button @click="sentMsg">点击后,向父组件传递数据</button>
</template>

跨组件

provideinject实现跨组件间的任意通讯

如果传递的是方法,方法中有修改传递数据组件中的数据,接收方法的组件拿到该函数也会修改传递数据组件中的数据

  • 传递数据组件

    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
    <script setup>
    import Son from './Son.vue'
    import {provide, ref} from "vue";

    // 需要传递的对象参数
    const user = ref({
    username: "123456",
    password: "223456"
    })

    // 需要传递的方法
    const testMethod = () => {
    console.log("传递测试方法")
    }

    // 跨组件传递数据
    provide('user', user)

    // 跨组件传递方法
    provide('testMethod', testMethod)

    </script>

    <template>
    <son ref="sonRef"/>
    </template>
  • 接收数据组件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    <script setup>
    import {inject} from "vue";

    // 跨组件接收参数
    const user = inject('user')

    // 跨组件接收方法
    const testMethod = inject('testMethod')

    // 在script中使用跨组件接收的方法
    testMethod()
    </script>
    <template>
    <div>
    <!-- 使用跨组件接收的参数 -->
    {{ user }} <br/>
    <!-- 在template中使用跨组件接收方法 -->
    <button @click="testMethod">使用跨组件接收方法</button>
    </div>
    </template>

模版引用

通过 ref 标识 获取真实的 dom 对象或者组件实例对象

获取标签对象dom

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<script setup>
import {onMounted, ref} from "vue";

const h1Ref = ref(null)

// 使用ref获取dom对象,需要在组件挂载完成之后才能获取
onMounted(() => {
console.log(h1Ref.value)
})
</script>

<template>
<h1 ref="h1Ref">dom标签</h1>
</template>

获取vue组件dom及使用testMessage获取组件属性

父组件使用ref获取到的vue组件的dom,默认情况下在 script setup语法糖下组件内部的属性和方法是不开放给父组件访问的,可以通过defineExpose编译宏指定哪些属性和方法容许访问

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<script setup>
import {onMounted, ref} from "vue";
import Son from './Son.vue'

const sonRef = ref(null)

onMounted(() => {
console.log(sonRef.value)
})
</script>

<template>
<son ref="sonRef"/>
</template>
1
2
3
4
5
6
7
8
9
10
11
12
<!--Son组件-->
<script setup>
import {ref} from "vue";

const name = ref("XiaoFei")

<!-- 当使用ref获取该组件的模板引用时,使用defineExpose指定哪些属性和方法容许访问 -->
defineExpose({
name
})
</script>
<template></template>

20231105-Vue3快速上手

项目创建

image-20231105211542773