Vue3学习笔记

owofile Lv5

Vue3学习笔记

Vue3

官方文档:https://cn.vuejs.org/guide/introduction.html

Vue (发音为 /vjuː/,类似 view) 是一款用于构建用户界面的 JavaScript 框架。它基于标准 HTML、CSS 和 JavaScript 构建,并提供了一套声明式的、组件化的编程模型,帮助你高效地开发用户界面。无论是简单还是复杂的界面,Vue 都可以胜任。

好处:

  1. 性能优化:Vue 3引入了一系列性能优化,包括更快的渲染和更新机制,以及更小的包大小,提高了整体性能。
  2. 更好的 TypeScript 支持:Vue 3对 TypeScript 的支持更加友好,使开发过程更加可靠和高效。
  3. Composition API:引入了Composition API,让代码更加灵活和可维护,能更好地组织组件逻辑。
  4. 更好的响应式系统:Vue 3中的响应式系统进行了重写,使其更加高效和可靠。
  5. 更好的服务器端渲染支持:Vue 3对服务器端渲染的支持更加完善,能够更好地应用于复杂的应用场景。

坏处:

  1. 学习曲线:对于之前使用过Vue2的开发者来说,需要花一些时间来适应Vue 3的新特性和变化。
  2. 生态系统的不稳定性:由于Vue 3相对较新,一些与Vue 3兼容的第三方库和插件可能不够完善或不稳定。

总体来说,Vue 3带来了许多优点,但也需要开发者在使用时留意一些潜在的问题。

在我看来此次更新最重要的点就在于它的组合式API编程,让代码逻辑更清晰和好维护,创建和使用过程也更加快速,响应也很快

创建Vue3脚手架

1
npm init vue@latest

输入项目名称并且配置你需要的模块

一般默认都选否 End to End测试工具则选不需要

然后按照教程进入项目 下载依赖

1
npm install

运行vue3

1
npm run dev

遇到卡住不动的情况

当创建脚手架和下载依赖的时候如果遇到卡住不同的情况,多半是网络问题或者镜像问题,更换镜像或者降低npm版本即可。

参考教程:

https://blog.csdn.net/m0_46695182/article/details/127846670

Vue3相比Vue2的变化

关键文件

1.vite.config.js - 项目的配置文件 基于vite的配置
2.package.json - 项目包文件 核心依赖项变成了 Vue3.x 和 vite
3.main.js - 入口文件 createApp函数创建应用实例
4.app.vue - 根组件 SFC单文件组件 script - template - style

变化

变化一: 脚本script和模板template顺序调整
变化二: 模板template不再要求唯一根元素
变化三:脚本script添加setup标识支持组合式API
5.index.html- 单页入口 提供id为app的挂载点

Vue3页面结构

1
2
3
4
5
6
<script setup>
</script>
<template>
</template>
<style scoped>
</style>

相比于Vue2,结构发生了一些变换,script 放在了最上方 中间的template不在需要div包裹直接写也可以显示

setup是最早的生命周期,创建的生命周期代码直接写在setup里就好

创建变量,创建方法,使用变量和方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<script setup>
// 变量
const count = 999
// 方法
const logCount = ()=>{
console.log(count);
}
</script>
<template>
<!-- 页面渲染 -->
<h1>{{ count }}</h1>
<button @click="logCount">打印</button>
</template>
<style scoped>
</style>

组件API

reative()

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>
// 这里的数据是死的
const count = 999;
// 这里是响应式数据,可以++
import { reactive } from 'vue';
const msg = reactive({
// 只能接收对象
count:123,
name:'小明'
})
const logmsg = ()=>{
// console.log(msg.count);
msg.count++
}
</script>
<template>
<!-- 页面渲染 -->
<h1>{{ msg.count }}</h1>
<h1>{{ msg.name }}</h1>
<button @click="logmsg">点击</button>
</template>
<style scoped>
</style>

使用reative()里的对象数据是响应式的,可以被加一

ref

直接定义创建数据

由于ref定义后直接msg++会出问题,需要使用它的value值

ref返回永远是一个响应式对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<script setup>
import { ref } from 'vue';
//创建变量 值为1
const msg = ref(0)
//创建方法改变变量msg值
const logmsg = ()=>{
msg.value++
}
</script>
<template>
<!-- 页面渲染 -->
<h1>{{ msg }}</h1>
<button @click="logmsg">点击</button>
</template>
<style scoped>
</style>

使用对象创建数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<script setup>
import { ref } from 'vue';
const msg = ref({
const:0
})
const logmsg = ()=>{
msg.value.const++
}
</script>
<template>
<!-- 页面渲染 -->
<h1>{{ msg.const }}</h1>
<button @click="logmsg">点击</button>
</template>
<style scoped>
</style>

computed

计算属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<script setup>
import { computed, ref } from 'vue';
const list = ref([1,2,3,4,5,6,7,8]);
// 调用函数
const logList = computed(() => {
// return list.value.filter(item => item > 3);
return list.value.filter((item) => {return item > 3});
});
</script>
<template>
<!--接收变量 -->
<p>{{ list }}</p>
<p>{{ logList }}</p>
</template>
<style scoped>
</style>

watch

监听器

基础监听器

检测到count值发生变化后控制台打印信息

1
2
3
4
5
6
7
8
9
10
11
12
<script setup>
import { ref,watch} from 'vue';''
const count = ref(0)
watch(count,(newValue,oldValue)=>{
console.log(newValue,oldValue);
})
</script>
<template>
<button @click="count++" >{{ count }}</button>
</template>
<style scoped>
</style>
侦听对象开启深度监听
1
deep:true
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<script setup>
import { ref,watch} from 'vue';''
const msg = ref({
const:0
})
watch(msg,(newValue,oldValue)=>{
console.log(newValue,oldValue);
},{
deep:true
})
</script>
<template>
<button @click="msg.const++" >{{ msg.const }}</button>
</template>
<style scoped>
</style>
精确监听
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<script setup>
import { ref,watch} from 'vue';''
const msg = ref({
// 只监听const
const:0,
age:'cp'
})
watch(
// 精确监听某个属性
()=>msg.value.const,
(newValue,oldValue)=>{
console.log(newValue,oldValue);
}
)
</script>
<template>
<button @click="msg.const++" >{{ msg.const }}</button>
</template>
<style scoped>
</style>
生命周期onMounted
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<script setup>
import { onMounted } from 'vue';
onMounted(() => {
console.log('mounted1');
});
onMounted(() => {
console.log('mounted2');
});
</script>
<template>
<h1>你好</h1>
</template>
<style scoped>
</style>

父传子

父组件

1
2
3
4
5
6
7
8
9
10
<script setup>
//导入子组件
import Soncon from './components/son-con.vue'
</script>
<template>
<h1>这是父组件</h1>
<Soncon message="这是传给子组件的数据"></Soncon>
</template>
<style scoped>
</style>

子组件

1
2
3
4
5
6
7
8
9
10
11
12
<script setup>
// 编译器宏函数
const props = defineProps({
// 因为setup生命周期太早所以需要使用defineProps编译器宏
message:String
})
</script>
<template>
<h1>这是子组件=={{ message }}</h1>
</template>
<style scoped>
</style>
使用props接收参数
1
2
3
4
const props = defineProps({
// 因为setup生命周期太早所以需要使用defineProps编译器宏
message:String
})

子传父

父组件

1
2
3
4
5
6
7
8
9
10
11
12
<script setup>
import Soncon from './components/son-con.vue'
const getMessage = (mes)=>{
console.log(mes);
}
</script>
<template>
<h1>这是父组件</h1>
<Soncon message="这是传给子组件的数据" @get-message="getMessage"></Soncon>
</template>
<style scoped>
</style>

子组件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<script setup>
// 编译器宏函数
const props = defineProps({
// 因为setup生命周期太早所以需要使用defineProps编译器宏
message:String
})
const emit = defineEmits(['get-message'])
const show = ()=>{
emit('get-message','子组件数据')
}
</script>
<template>
<h1>这是子组件=={{ message }}</h1>
<button @click="show">按钮</button>
</template>
<style scoped>
</style>

获取Dom元素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<script setup>
import { ref,onMounted } from 'vue';
const h1Ref = ref(null)
// setup生命周期在早,页面未渲染直接输出不会显示
// 所以换一个生命周期
onMounted(()=>{
console.log(h1Ref.value);
})
</script>
<template>
<h1 ref="h1Ref">这是根组件</h1>
</template>
<style scoped>
</style>
defineExpose
1
2
3
4
const msg = ref('hello world');
defineExpose({
msg
})

使用defineExpose再去获取Dom元素才能在跨层获取才能获取到数据

defineExpose 是 Vue 3 中的一个特性,用于向父组件公开子组件的内部状态或方法。通过 defineExpose,子组件可以显式地公开需要暴露给父组件的属性或方法。

在上述代码中,我们使用 defineExpose 来向父组件暴露了一个名为 msg 的响应式数据。

下面是一个简单的示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
// ChildComponent.vue
import { defineComponent, ref, defineExpose } from 'vue';
export default defineComponent({
setup() {
const msg = ref('hello world');
defineExpose({
msg
});
return {
msg
};
}
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// ParentComponent.vue
<template>
<div>
<ChildComponent ref="childComponent" />
</div>
</template>
<script>
import ChildComponent from './ChildComponent.vue';
export default {
mounted() {
console.log(this.$refs.childComponent.msg); // 输出: "hello world"
}
}
</script>

在这个示例中,子组件通过 defineExpose 公开了 msg 这个数据,然后在父组件中通过 $refs 访问子组件并获取到了 msg 数据。

这种方式适用于需要在子组件中定义一些内部状态或方法,并且需要在父组件中进行访问或操作时。

provide和inject

除了使用上述的方式来跨层传递数据还有一种更便捷的方法那就是provide创建数据和inject接收

provideinject 是 Vue 中用于在父组件和子组件之间跨层级传递数据的一种方式。provide 在父组件中创建数据,而 inject 则在子组件中接收这些数据。

在父组件中,通过 provide 来提供数据,子组件通过 inject 来注入这些数据。这种方式可以跨越多个嵌套层级,让数据在组件之间更方便地流动。

下面是一个简单的示例:

1
2
3
4
5
6
// ParentComponent.vue
export default {
provide: {
message: '这是来自父组件的消息'
}
}
1
2
3
4
5
6
7
// ChildComponent.vue
export default {
inject: ['message'],
mounted() {
console.log(this.message); // 输出: "这是来自父组件的消息"
}
}

在这个例子中,父组件通过 provide 提供了一个名为 message 的数据,而子组件则通过 inject 注入了这个数据,并在 mounted 钩子中访问了这个数据。

这种方式比较方便,但需要注意的是,使用 inject 时要确保你知道提供数据的来源,以避免意外的耦合。

Element

在Vue3中使用ElementUI需要使用Element-plus

官网链接:https://element-plus.org/zh-CN/component/button.html

在对应路径按照依赖

1
npm install element-plus --save

也可以选择线上引入

1
2
3
4
5
6
7
8
<head>
<!-- Import style -->
<link rel="stylesheet" href="//unpkg.com/element-plus/dist/index.css" />
<!-- Import Vue 3 -->
<script src="//unpkg.com/vue@3"></script>
<!-- Import component library -->
<script src="//unpkg.com/element-plus"></script>
</head>

详细参考官方文档

Pinia

官方文档:https://pinia.vuejs.org/zh/getting-started.html

安装

1
2
3
4
npm cteate vue@latest #安装最新vue3脚手架
yarn add pinia
# 或者使用 npm
npm install pinia

使用get接口获取数据

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
import { defineStore } from "pinia";
import { ref } from "vue";
import { computed} from 'vue';
import axios from 'axios';
export const useCounterStore= defineStore('counter',()=>{
//创建变量
const count=ref(0)
// 创建响应式数组
const arrayr = ref([]);
//创建计算属性
const logList = computed(() => {
return count.value \* 2;
});
//创建方法
const increment=()=>{-+
count.value++
}
// 获取数据
const fetchData = async () => {
const res = await axios.get('http://geek.itheima.net/v1\_0/channels');
// console.log(res.data.data.channels);
arrayr.value = res.data.data.channels
console.log('res' + arrayr.value);
};
//用对象的形式返回
//所有方法和变量都需要返回,否则报错和接收不到
return {
count,
logList,
increment,
// 返回结果
fetchData,
arrayr,
}
})

组件展示数据

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>
import sPage from './components/store-page.vue'
import sMsg from './components/store-msg.vue'
//1、导入
import { useCounterStore }from './stores/Counter'
//2、执行方法
const counterStore = useCounterStore()
counterStore.fetchData()
console.log('hello:' + counterStore.arrayr);
</script>
<template>
<div>
<ul>
<li v-for="item in counterStore.arrayr" :key="item.id">{{ item.name }}</li>
</ul>
</div>
<button @click="counterStore.increment">这是按钮</button>
<h1>这是父组件=={{ counterStore.count }}=={{ counterStore.logList}}</h1>
<sPage></sPage>
<sMsg></sMsg>
</template>
<style scoped>
</style>

pnpm

全局安装

1
npm install -g pnpm

使用pnpm创建Vue

1
pnpm create vue
  • Title: Vue3学习笔记
  • Author: owofile
  • Created at : 2023-12-13 00:29:19
  • Updated at : 2025-04-11 21:18:26
  • Link: https://owofile.github.io/blog/2023/12/13/Vue3学习笔记/
  • License: This work is licensed under CC BY-NC-SA 4.0.
Comments