Vue3学习笔记
Vue3
官方文档:https://cn.vuejs.org/guide/introduction.html
Vue (发音为 /vjuː/,类似 view) 是一款用于构建用户界面的 JavaScript 框架。它基于标准 HTML、CSS 和 JavaScript 构建,并提供了一套声明式的、组件化的编程模型,帮助你高效地开发用户界面。无论是简单还是复杂的界面,Vue 都可以胜任。
好处:
- 性能优化:Vue 3引入了一系列性能优化,包括更快的渲染和更新机制,以及更小的包大小,提高了整体性能。
- 更好的 TypeScript 支持:Vue 3对 TypeScript 的支持更加友好,使开发过程更加可靠和高效。
- Composition API:引入了Composition API,让代码更加灵活和可维护,能更好地组织组件逻辑。
- 更好的响应式系统:Vue 3中的响应式系统进行了重写,使其更加高效和可靠。
- 更好的服务器端渲染支持:Vue 3对服务器端渲染的支持更加完善,能够更好地应用于复杂的应用场景。
坏处:
- 学习曲线:对于之前使用过Vue2的开发者来说,需要花一些时间来适应Vue 3的新特性和变化。
- 生态系统的不稳定性:由于Vue 3相对较新,一些与Vue 3兼容的第三方库和插件可能不够完善或不稳定。
总体来说,Vue 3带来了许多优点,但也需要开发者在使用时留意一些潜在的问题。
在我看来此次更新最重要的点就在于它的组合式API编程,让代码逻辑更清晰和好维护,创建和使用过程也更加快速,响应也很快

创建Vue3脚手架
输入项目名称并且配置你需要的模块
一般默认都选否 End to End测试工具则选不需要
然后按照教程进入项目 下载依赖
运行vue3
遇到卡住不动的情况
当创建脚手架和下载依赖的时候如果遇到卡住不同的情况,多半是网络问题或者镜像问题,更换镜像或者降低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 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({
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
| 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接收
provide
和 inject
是 Vue 中用于在父组件和子组件之间跨层级传递数据的一种方式。provide
在父组件中创建数据,而 inject
则在子组件中接收这些数据。
在父组件中,通过 provide
来提供数据,子组件通过 inject
来注入这些数据。这种方式可以跨越多个嵌套层级,让数据在组件之间更方便地流动。
下面是一个简单的示例:
1 2 3 4 5 6
| export default { provide: { message: '这是来自父组件的消息' } }
|
1 2 3 4 5 6 7
| 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>
<link rel="stylesheet" href="//unpkg.com/element-plus/dist/index.css" />
<script src="//unpkg.com/vue@3"></script>
<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 yarn add pinia
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');
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
全局安装
使用pnpm创建Vue