Vue3基础

本文最后更新于:2023年7月28日 凌晨

快速开始

使用官方工具vite快速初始化一个vue应用

本文使用vite在线工具演示(Vite在线体验)

先清空文件夹,再执行命令初始化一个Vue3项目

1
npm create vite

执行后按提示输入项目文件夹名,包名,之后选择vue,继续选择vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
> npm create vite
> success Install finished in 1.06s
>
> Project name: … learnVue3
> Package name: … learnvue3
> Select a framework: › vue
> Select a variant: › vue
>
> Scaffolding project in /home/projects/vitejs-vite-o33svt/learnVue3...
>
> Done. Now run:
>
> cd learnVue3
> npm install
> npm run dev

再按提示命令执行,即创建并启动了一个vue应用,为了学习vue3,先将src下的所有的文件/文件夹删除

生成vue3

src目录新建一个App.vue单文件组件

src/App.vue

1
2
3
4
<template>
<h1>🎉 Hello Vue3!</h1>
</template>

src目录新建一个main.js文件

src/main.js

1
2
3
4
5
6
7
import { createApp } from 'vue';
import App from './App.vue';

const app = createApp(App); // 生成一个vue根组件

app.mount('#app'); // 将vue挂载至id="app"的DOM元素(在index.html)

vite热更新后即可看到App.vue组件

单文件组件的创建与使用

App.vue中的h1封装为组件来示例

src新建components文件夹,新建Hello.vue单文件组件

src/components/Hello.vue

1
2
3
4
5
6
7
8
9
10
11
12
<!-- <script setup></script> -->
<!-- script标签中写js(可选) -->
<!-- setup: Vue3.2+语法糖 -->

<template>
<h1>🎉 Hello Vue3!</h1>
</template>

<!-- <style scoped></style> -->
<!-- style标签写css(可选) -->
<!-- scoped表示css样式只作用于当前组件 -->

App.vue导入组件

src/App.vue

1
2
3
4
5
6
7
8
9
10
<script setup>
import Hello from './components/Hello.vue';
// 使用了setup语法,引入组件便会在该文件注册组件
</script>

<template>
<!-- 直接像html一样使用 -->
<Hello />
</template>

template模板语法

template可使用{{ data }}来创建动态内容

src目录下新建components文件夹,新建Template.vue,并在App.vue注册使用

src/components/Template.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
<script setup>
const name = 'Jon-a-than';
let birthYear = 2002;

// 在模板中不会更新
setTimeout(() => birthYear = 2000, 1000);
</script>

<template>
<!-- 可直接在模板中使用HTML元素 -->
<h2>template语法</h2>

<!-- 可使用函数 -->
<time>{{ new Date() }}</time>

<!-- 使用变量 -->
<p>
My name is <span>{{ name }}</span>
</p>

<!-- 使用表达式 -->
<p>
I am a <span>{{ new Date().getFullYear() - birthYear }}</span>
-year-old boy
</p>
</template>

<style scoped>
p > span {
color: #00f;
}
</style>

  • {{ }}中只可使用单句Javascript表达式
  • 若变量未使用响应式API,变量不会动态更新
  • 变量会进行转义而不会插入innerHTML

setup函数

1
2
3
4
<script setup>
// ...
</script>

  • setup内导入组件可直接使用
  • setup内没有全局this

Vue指令

动态属性

template中的花括号语法无法作用于元素属性,v-bind指令可以实现动态的元素属性

src/components/Directives/Vbind.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<script setup>
const url = "https://qingshaner.com";

const link = "https://staging-cn.vuejs.org/api/built-in-directives.html#v-bind";
</script>

<template>
<h2>指令</h2>
<p>
<a v-bind:href="url">Blog</a>
<br />
<a :href="link">v-bind语法糖</a>
</p>
</template>

条件展示

使用v-show命令可以让元素只在条件满足时显示元素

src/components/Directives/Vshow.vue

1
2
3
4
5
6
7
8
9
10
11
12
<script setup>
let isShow = false

setTimeout(() => isShow = true, 3000)
</script>

<template>
<!-- -->
<h3 v-show="!isShow">看见了吗</h3>
<!-- 3秒后显示 -->
<h1 v-show="isShow">👋我在这</h1>
</template>

使用v-if,v-else-if,v-else指令也可按条件显示不同的元素

1
<set

生命周期

🍈钩子函数

  • setup创建实例前
  • onBeforeMount挂载DOM前
  • onMounted挂载DOM后
  • onBeforeUpdate更新组件前
  • onUpdated更新组件后
  • onBeforeUnmount卸载销毁前
  • onUmounted卸载销毁后
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
<template>
<div class="container">
</div>
</template>
<script>
import {onBeforeMount, onMounted, onBeforeUpdate, onUpdated, onBeforeUnmount, onUmounted} from 'vue'
// 使用钩子函数需先导入
export default {
name: 'App',
setup () {
// 创建实例前

onBeforeMount(){
// 挂载DOM前
}
onMounted(){
// 挂载DOM后
}
onBeforeUpdate(){
// 更新组件前
}
onUpdated(){
// 更新组件后
}
onBeforeUnmount(){
// 卸载销毁前
}
onUmounted(){
// 卸载销毁后
}
}
}
</script>
  • 钩子函数无需return可直接执行

  • 可注册多个相同钩子(按序执行)

响应式数据

自定义属性

向所用组件传值

1
2
3
4
5
6
7
<script setup>
const props = defineProps({})
</script>

<template>
<p>{{ props.value }}</p>
</template>

自定义事件

1
2
3
<script setup>

</script>

reactive函数

  • 定义复杂数据类型(对象)为响应式数据

🍒写入点击记数功能

此时数据变化,但DOM不渲染

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<template>
<div class="container">
<!-- 展示dom -->
<h1 @click="cnt" >{{ obj.count }}</h1>
</div>
</template>
<script>
export default {
name: 'App',
setup () {
const obj = {
count: 0
}
const cnt = () => obj.count++
return { obj, cnt } // 返回函数为对象
}
}
</script>

🍒使用reactive函数

reactive函数将obj对象构造为响应式数据即可动态响应

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<template>
<div class="container">
<!-- 展示dom -->
<h1 @click="cnt" >{{ obj.count }}</h1>
</div>
</template>
<script>
import { reactive } from 'vue' // 需导入
export default {
name: 'App',
setup () {
const obj = reactive({ // 构造为响应式数据
count: 0
})
const cnt = () => obj.count++
return { obj, cnt } // 返回函数为对象
}
}
</script>

toRef函数

  • 单独返回响应式对象的某一属性
  • 修改attribute.value来响应式变化

🥒写入点击记数功能

使用解构得到的为静态值,无法实时更新

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<template>
<div class="container">
<!-- 展示dom -->
<h1 @click="cnt" >{{ count }}</h1>
</div>
</template>
<script>
import { reactive } from 'vue' // 需导入
export default {
name: 'App',
setup () {
const obj = reactive({ // 构造为响应式数据
count: 0,
time: 2
})
const { count } = obj
const cnt = () => obj.count++
return { count, cnt } // 返回函数为对象
}
}
</script>

🥒使用toRef函数

toRef函数将属性构造为响应式对象即可响应

通过修改其value属性实现响应式数据

该值与原对象关联

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<template>
<div class="container">
<!-- 展示dom -->
<h1 @click="cnt" >{{ count }}</h1>
</div>
</template>
<script>
import { reactive, toRef } from 'vue' // 需导入
export default {
name: 'App',
setup () {
const obj = reactive({ // 构造为响应式数据
count: 0,
time: 2
})
const count = toRef(obj, 'count')
const cnt = () => count.value++
return { count, cnt } // 返回函数为对象
}
}
</script>

toRefs函数

  • 可以批量解构响应式对象为响应式数据

🍓写入点击记数功能

使用解构得到的为静态值,无法实时更新

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<template>
<div class="container">
<!-- 展示dom -->
<h1 @click="cnt" >{{ count }}</h1>
<h2>{{ time }}</h2>
</div>
</template>
<script>
import { reactive } from 'vue' // 需导入
export default {
name: 'App',
setup () {
const obj = reactive({ // 构造为响应式数据
count: 0,
time: 2
})
const cnt = () => obj.count++
return { ...obj } // 返回函数为对象
}
}
</script>

🍓使用toRefs函数

toRefs函数将属性集构造为响应式对象

新对象与原对象关联

通过修改其属性的value属性实现响应式数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<template>
<div class="container">
<!-- 展示dom -->
<h1 @click="cnt" >{{ count }}</h1>
<h2>{{ time }}</h2>
</div>
</template>
<script>
import { reactive, toRefs } from 'vue' // 需导入
export default {
name: 'App',
setup () {
const obj = reactive({ // 构造为响应式数据
count: 0,
time: 2
})
const obj2 = toRefs(obj) // 响应式属性集
const cnt = () => obj.count++
return { ...obj2, cnt } // 返回函数为对象
}
}
</script>

ref函数

  • 将简单数据类型定义为响应式数据

  • 更改数据需更改value属性

🍊定义简单响应式数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<template>
<div class="container">
<h1>{{ msg }}</h1>
</div>
</template>
<script>
export default {
import { ref } from 'vue'
name: 'App',
setup () {
const msg = ref('title') //
return { msg }
}
}
</script>

computed函数

  • 数据 根据响应式数据变化而变化时使用计算函数

  • 计算函数返回值只读

🥦计算函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<template>
<div class="container">

</div>
</template>
<script>
export default {
import { computed, ref } from 'vue'
name: 'App',
setup () {
const oldDate = ref(2020)
const newDate = computed(() => {
return oldDate.value + 1
})
return { oldDate, newDate }
}
}
</script>

get()

set()

watch函数

  • 数据变化后执行

🍎监听一个简单响应式数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<template>
<div class="container"></div>
</template>
<script>
export default {
import { ref, watch }
name: 'App',
setup () {
const foo = ref('bar')
whatch(foo, (oldDate, newDate) => { // 回调函数传递改变前后的数据值
console.log('foo变化了')
})
}
}
</script>

🍎监听一个响应式对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<template>
<div class="container"></div>
</template>
<script>
export default {
import { reactie, watch }
name: 'App',
setup () {
const foo = reactive({
name: 'bar',
age: 19
})
whatch(foo, (oldDate, newDate) => { // 回调函数传递改变前后的数据值
console.log('foo变化了')
})
}
}
</script>

🍎监听多个响应式数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<template>
<div class="container"></div>
</template>
<script>
export default {
import { reactie, ref, watch }
name: 'App',
setup () {
const foo = reactive({
name: 'bar',
age: 19
})
const far = ref(10)
whatch([foo, far], () => {
console.log('foo,far至少一个变化了')
})
}
}
</script>

🍎监听一个响应式对象的某一属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<template>
<div class="container"></div>
</template>
<script>
export default {
import { reactie, watch }
name: 'App',
setup () {
const foo = reactive({
name: 'bar',
age: 19
})
whatch(() => foo.name, () => { // 用函数传递属性值
console.log('foo.name变化了')
})
}
}
</script>

🍎深度监听

  • 监听响应式对象的对象变化
1
2
3
watch(date, callback, {
deep: true
})

🍎默认执行

  • 初始化时执行一次
1
2
3
watch(date, callback, {
immediate: true
})

ref属性

  • 获取DOM或组件实例

🌳获取单个DOM

先定义并返回空的响应式数据

再将ref属性绑定到DOM上

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<template>
<div class="container">
<h1 ref="title">title</h1>
</div>
</template>
<script>
export default {
name: 'app'
setup () {
const title = ref(null)
return { title }
}
}
</script>

🌳获取v-for遍历的DOM

定义并返回一个空数组

定义一个DOM插入函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<template>
<div class="container">
<!-- 展示dom -->
<ul>
<li v-for="i in 4" :key="i" :ref="setDom">第{{ i }}个</li>
</ul>
</div>
</template>
<script>

export default {
name: 'App',
setup () {
const domList = []
const setDom = (el) => {
domList.push(el)
}
return { setDom }
}
}
</script>

父子通讯

🍁父=>子

:key="variable"绑定给子组件

子元素用props接收数据

子元素setup(props)传递数据给组合API

App.vue:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<template>
<div class="container">
<!-- 展示dom -->
<h1>{{ level }}</h1>
<son :relationship="level" /> // 绑定传递
</div>
</template>
<script>
import { ref } from 'vue'
import son from './son.vue' // 需导入
export default {
name: 'App',
components: { // 注册组件
son
},
setup () {
const level = ref('father')
return { level }
}
}
</script>

son.vue:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<template>
<div class="container">
<!-- 展示dom -->
<h1>子组件{{ relationship }}</h1>
</div>
</template>
<script>
export default {
name: 'son',
props: { // 接收数据
relationship: {
type: String,
default: 'null'
}
},
setup (props) { // 传递数据
console.log(props.relationship)
}
}
</script>

🍁父<=子

利用{ emit }(触发自定义事件)向父组件传递数据

父组件函数接收数据

App.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<template>
<div class="container">
<!-- 展示dom -->
<h1>父组件</h1>
<son @msg="receive" /> <!-- 触发接受函数 -->
</div>
</template>
<script>
import son from './son.vue'
export default {
name: 'App',
components: {
son
},
setup () {
const receive = (res) => console.log(res) // 接收数据
return { receive }
}
}
</script>

son.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<template>
<div class="container">
<!-- 展示dom -->
<h1 @click="pass" >子组件</h1> <!-- 触发传递函数 -->
</div>
</template>
<script>
export default {
name: 'son',
setup (props, { emit }) { // 不可省略props
const pass = () => emit('msg', 'sonDom') // 数据传递
return { pass }
}
}
</script>

🍁父<=>子 语法糖

依赖注入

provide函数给后代提供数据与方法

inject函数接受父代数据与方法

🍉向后代传值

1
2
import { provide } from 'vue'
provide('key', value) // 向后代传值

🍉接收值

单向数据流

1
const key = inject('key')                  // 接受父代传递值

🍉数据通信

在父组件定义并传递一个数据修改方法

1
2
const changeValue = () => key()            // 修改value
provide('changeKey', changeValue) // 向后代传递方法

后代接收方法来修改数据

1
const change = inject('changeKey')         // 用此函数修改key的值

setup 语法糖

🍍注册与变量

1
2
3
4
5
6
7
8
9
<template>
<h1>{{ title }}</h1>
<Son />
</template>

<script setup>
import Son from '@...' // 无需再注册
const title = '糖' // 无需return变量
</script>

🍍


Vue3基础
https://qingshaner.com/vue3基础/
作者
清山
发布于
2022年1月17日
许可协议