Vue3学习

一、认识VUE3

VUE2写法
<script>
export default{
  data(){
    return{
      count:0
    }
  },
  methods:{
    addCount(){
      this.count++
    }
  }
}
</script>

VUE3写法
<script setup>
import {ref} from 'vue'
const count = ref(0)
const addCount = ()=>count.value++
</script>

以上VUE2和VUE3的区别

  1. 代码量变少了
  2. 分散式维护转为集中式维护

VUE3更多的优势

  1. 更容易维护:
    1.组合式API
    2.更好的TypeScript支持
  2. 更快的速度:
    1.重写diff算法
    2.模板编译优化
    3.更高效的组件初始化
  3. 更小的体积
    1.良好的TreeShaking
    2.按需引入
  4. 更优的数据响应式
    1.Proxy

二、使用create-vue搭建Vue3项目

认识create-vue

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

使用create-vue创建项目

1.前提环境条件
   已安装16.0node或更高的版本的Node.js
   (node官网:https://nodejs.cn/download/,使用快捷键 win + R 打开运行 输入cmd打开终端。在终端里面输入node -v和npm -v查看是否都可用,如果显示版本号则证明安装成功。)
2.创建一个Vue应用
   npm init vue@latest
   这一指令将会安装并执行create-vue

三、熟悉项目目录和关键文件

项目目录

在这里插入图片描述

关键文件

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的挂载点

四、组合式API - setup选项

setup

原始复杂写法
<script>
export default{
  setup(){
    // 数据
    const message = 'this is message'
    // 函数
    const logMessage=()=>{
      console.log(message);
    }
    return{
      message,
      logMessage
    }
  }
}
</script>

语法糖写法
<script setup>
    // 数据
    const message = 'this is message'
    // 函数
    const logMessage=()=>{
      console.log(message);
    }
</script>

总结

1.setup选项的执行实机是在beforeCreate钩子之前 自动执行
2.setup写代码的特点是 定义数据+函数,然后以对象方式return
3.(script setup)经过语法糖的封装更简单的使用组合式API
4.setup中的this指向undefined

五、组合式API - reactive和ref函数

reactive()

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

<script setup>
// 导入
import { reactive } from 'vue'

// 执行函数 传入参数 变量接收
const state = reactive(对象类型的数据)

</script>

例子
<script setup>
// 导入
import { reactive } from 'vue'

// 执行函数 传入参数 变量接收
const state = reactive({
  count:0
})

const setCount=()=>{
  state.count++
}
</script>

<template>
  <div>
     <button @click="setCount">{{state.count}}</button>  
  </div>
</template>

在这里插入图片描述

1.从vue包中导入reactive函数
2.在(script setup)中执行reactive函数并传入类型对象的初始值,并使用变量接收返回值

ref()

<script setup>
// 导入
import { ref } from 'vue'
// 执行函数 传入参数 变量接收
const state = ref(简单类型或者复杂类型数据)
</script>

例子
<script setup>
// 导入
import { ref } from 'vue'
// 执行函数 传入参数 变量接收
const count = ref(0)
const setCount=()=>{
  // 脚本区域修改ref产生的响应式对象数据 必须通过.value属性
  count.value++
}
</script>

<template>
  <div>
     <button @click="setCount">{{count}}</button>  
  </div>
</template>

1.从vue包中导入ref函数
2.在(script setup)中执行ref函数并传入初始值,并使用变量接收ref函数的返回值

总结

1.reactive和ref函数的共同作用是什么?
用函数调用的方式生成响应式数据
2.reactive vs ref 的区别?
(1)reactive不能处理简单类型的数据
(2) ref参数类型支持更好但是必须通过.value访问修改
(3) ref函数的内部实现依赖于reactive函数
3.在实际工作中推荐使用哪个
推荐使用ref函数,更加灵活。

六、组合式API - computed

computed

计算属性基本思想和Vue2完全一致,组合式API下的计算属性只是修改了写法。

<script setup>
// 导入
import {computed} from 'vue'
// 执行函数 变量接收 在回调函数中return计算值
const computedState=computed(()=>{
  return 基于响应式数据做计算的值
})
</script>

1.导入computed函数
2.执行函数在回调参数中return基于响应式数据做计算的值,用变量接收

demo例子


<script setup>
// 导入
import {ref,computed} from 'vue'

const list = ref([1,2,3,4,5,6,7,8])
// 执行函数 变量接收 在回调函数中return计算值
const computedList=computed(()=>{
  //返回大于2的元素的数组
  return list.value.filter(item=>item>2)
})
</script>
<template>
  <div>
     原始响应式数组 - {{ list }}
  </div>
  <div>
     计算属性数组 - {{ computedList }}
  </div>
</template>

在这里插入图片描述

总结

1.计算属性中不应该有“副作用”
比如异步请求/修改dom(应该交给watch来做)
computed只能应该根据一个数据计算得到一个新数据
2.避免直接修改计算属性的值
计算属性应该是只读

七、组合式API - watch

作用:侦听一个或者多个数据的变化,数据变化时执行回调函数
两个额外参数:1.immediate(立即执行) 2.deep(深度侦听)

基础使用-侦听单个数据

<script setup>
// 导入watch
import {ref,watch} from 'vue'
const count = ref(0)

// 2.调用watch 侦听变化
watch(count,(newValue,oldValue)=>{
  console.log(`count发生了变化,老值为${oldValue},新值为${newValue}`);
})
</script>

demo例子

<script setup>
// 导入watch
import {ref,watch} from 'vue'
const count = ref(0)

const setCount=()=>{
  count.value++
}
// 2.调用watch 侦听变化
// TODO watch侦听单个数据源
// ref对象不需要加.value
watch(count,(oldValue,newValue)=>{
  console.log(`count发生了变化,老值为${oldValue},新值为${newValue}`);
}) 
 </script>
<template>
    <div>
      <button @click="setCount">+{{ count }}</button>
    </div>
</template>

在里插入图片描述

基础使用-侦听多个数据

说明:同时侦听多个响应式数据的变化,不管哪个数据变化都需要执行回调。

<script setup>
  import {ref,watch} from 'vue'
  const count = ref(0)
  const name =  ref('cp')

  // 侦听多个数据源
  watch(
    [count,name],
    ([newCount,newName],[oldCount,oldName])=>{
      console.log(`count或者name发生了变化,`[newCount,newName],[oldCount,oldName]);
    }
  )
</script>

例子demo

<script setup>
  import {ref,watch} from 'vue'
  const count = ref(0)
   const changeCount = ()=>{
    count.value++
   }


  const name =  ref('cp')
  const changeName = ()=>{
    name.value='pc'
   }

  // 侦听多个数据源
  watch(
    [count,name],
    ([newCount,newName],[oldCount,oldName])=>{
      console.log(`count或者name发生了变化,`,[newCount,newName],[oldCount,oldName]);
    }
  )
</script>

<template>
    <div>
      <button @click="changeCount">修改count--{{ count }}</button>
    </div>
    <div>
      <button @click="changeName">修改name--{{ name }}</button>
    </div>
</template>

在这里插入图片描述

immediate

说明:在侦听器创建时立即触发回调,响应式数据变化之后继续执行回调

<script setup>
  import {ref,watch} from 'vue'

  const count = ref(0)
  watch(count,()=>{
    console.log('立即监听count');
  },{
    immediate:true
  })
</script>

<template>
    <div>
      <button>修改count--{{ count }}</button>
    </div>
</template>

在这里插入图片描述

deep

默认机制:通过watch监听的ref对象默认是浅层侦听的,直接修改嵌套的对象属性不会触发回调执行,需要开启deep选项。

<script setup>
  import {ref,watch} from 'vue'

  const state = ref({count:0})
  watch(state,()=>{
    console.log('数据变化了');
  },{
    deep:true
  })

  const changeState=()=>{
    // 直接修改属性 -> 不会触发回调
    state.value.count++
  }
</script>

<template>
    <div>
      <button @click="changeState">修改count--{{ state.count }}</button>
    </div>
</template>

在这里插入图片描述

精确侦听对象的某个属性

需求:在不开启deep的前提下,侦听age的变化,只有age变化时才执行回调

<script setup>
  import {ref,watch} from 'vue'

  const state = ref({count1:0,age:18})
  watch(
    // 精确侦听某个具体属性
    ()=>state.value.count1,
    ()=>console.log('count1发生变化了')
    )

  const changeState=()=>{
    state.value.count1++
  }
</script>

<template>
    <div>
      <button @click="changeState">修改count--{{ state.count1 }}</button>
    </div>
</template>

在这里插入图片描述

总结

1.作为watch函数的第一个函数,ref对象需要添加.value吗?
不需要,watch会自动读取
2.watch只能侦听单个数据吗?
不对,能监听单个或多个
3.不开启deep,直接修改嵌套属性能触发回调吗?
不能,默认是浅层侦听
4.不开启deep,想在某个层次比较深度属性变化时执行回调怎么做?
可以把第一个参数写成函数的写法,返回要监听的具体属性

八、组合式API - 生命周期函数

Vue3的生命周期API(选项式VS组合式)

在这里插入图片描述

生命周期函数的基本使用

1.导入生命周期函数
2.执行生命周期函数 传入回调

<script setup>
// 声明周期函数的使用
// 1.引入函数
  import {onMounted} from 'vue'
// 2.执行函数 传入回调
onMounted(()=>{
  console.log('组件挂载完毕mounted执行了');
})
</script>
<template>
    <div>
    </div>
</template>

在这里插入图片描述

执行多次

生命周期函数是可以执行多次的,多次执行时传入的回调会在时机成熟时依次执行

<script setup>
// 声明周期函数的使用
// 1.引入函数
  import {onMounted} from 'vue'
// 2.执行函数 传入回调
onMounted(()=>{
  console.log('组件挂载完毕mounted执行了');
  console.log('组件挂载完毕mounted执行了2')
})

onMounted(()=>{
  console.log('组件挂载完毕mounted执行了3');
})
</script>

在这里插入图片描述

总结

1.组合式API中生命周期函数的格式是什么?
on+生命周期名字
2.组合API中可以使用onCreated吗?
没有这个钩子函数,直接写到setUp中
3.组合式API中组件卸载完毕时执行哪个生命周期函数
onUnmounted

九、组合式API - 父子通信 - 父传子

基本思想

1.父组件中给子组件绑定属性
2.子组件内部通过props选项接收

父组件
<script setup>
// 引入子组件
import { ref } from 'vue';
import sonComVue from './son-com.vue'
const count = ref(100)
setTimeout(()=>{
  count.value=200
},3000)
</script>

<template>
  <!-- 绑定属性 -->
  <h1>我是父组件</h1>
  <!-- :动态绑定数据 可监听到数据变化 -->
  <sonComVue :count="count" message="this is sonComVue"></sonComVue>
</template>
子组件
<script setup>
// 2.通过defineProps“编译器宏”接收子组件传递的数据
const props = defineProps({
  message:String,
  count:Number
})
</script>
<template>
  <h2>我是子组件</h2>
   父组件传入的数据----{{ message }} -- {{ count }}
</template>

总结

1.父传子的过程中通过什么方式接收props?
defineProps({属性名:类型})
2.setup语法糖中如何使用父组件传过来的数据?
const props = defineProps({属性名:类型})

十、组合式API - 父子通信 - 子传父

基本思想

1.父组件中给子组件标签通过@绑定事件
2.子组件内部通过$emit方法触发事件

父组件
<script setup>
// 引入子组件
import sonComVue from './son-com.vue'
const getMessage = (msg)=>{
  console.log(msg);
}
</script>

<template>
  <h1>我是父组件</h1>
  <!-- 绑定自定义事件 -->
  <sonComVue @get-message="getMessage"></sonComVue>
</template>
子组件
<script setup>
// 2.通过defineProps“编译器宏”接收子组件传递的数据
const emit = defineEmits(['get-message'])

const sendMSg = ()=>{
  // 3.触发自定义事件 并传递参数
  emit('get-message','this is son msg')
}
</script>
<template>
  <h2>我是子组件</h2>
   <button @click="sendMSg">子传父</button>
</template>

在这里插入图片描述

总结

1.子传父的过程中通过什么方式得到emit方法?
defineEmits([‘事件名称’])

十一、组合式API - 模板引用

概念

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

如何使用(以获取dom为例 组件同理)

<script setup>
import {ref} from 'vue'
// 1.调用ref函数得到ref对象
const h1Ref=ref(null)

// 组件挂载完毕之后才能获取
onMounted(()=>{
  console.log(h1Ref.value);
})
</script>
<template>
  <!-- 2.通过ref标识绑定ref对象 -->
   <h1 ref="h1Ref">
    我是dom标签h1
   </h1>
</template>

在这里插入图片描述
1.通过ref函数生成一个ref对象
2.通过ref标识绑定ref对象到标签

defineExpose()

默认情况下在

<script setup>
// 引入子组件
import { onMounted, ref } from 'vue';
import testMessage from './testMessage.vue'
// 1.调用ref函数 -> ref对象
const comRef = ref(null)

onMounted(()=>{
  comRef.value.setName()
  console.log(comRef.value.name);
})
</script>

<template>
  <!-- 2.通过ref标识绑定ref对象 -->
  <h1>我是父组件</h1>
  <testMessage ref="comRef"></testMessage>
</template>
<script setup>
import {ref} from 'vue'
const name = ref('test name')
const setName = ()=>{
  name.value = 'test new name'
}
defineExpose({
  name,
  setName
})
</script> 
<template>
<div>我是test组件</div>
</template>

在这里插入图片描述

总结

1.获取模板引用的时机是什么?
组件挂载完毕
2.defineExpose编译宏的作用是什么?
显示暴露组件内部的属性和方法

十二、组合式API - provide和inject

作用和场景

顶层组件向任意的底层组件传递数据和方法,实现跨层组件通信

跨层传递普通数据

1.顶层组件通过provide函数提供数据
2.底层组件通过inject函数获取数据

顶层组件
provide('key',顶层组件中的数据)
底层组件
const message = inject('key')

例子

顶层组件RoomPage.vue
<script setup>
import RoomMsgItem from './RoomMsgItem.vue'
import {provide} from 'vue'
// 组件嵌套关系:
// RoomPage -> RoomMsgItem -> RoomMsgComment

// 1.顶层组件提供数据
provide('data-key','this is room data')
</script>
<template>
<div>
  顶层组件
  <RoomMsgItem />
</div>
</template>
中间组件RoomMsgItem,vue
<script setup>
import RoomMsgComment from './RoomMsgComment.vue'
</script>
<template>
   <div>
    中间组件
    <RoomMsgComment />
   </div>

</template>
底层组件RoomMsgComment.vue
<script setup>
import {inject} from 'vue'
// 2.接收数据
const roomData = inject('data-key')
</script>

<template>
   <div>
    底层组件
    <div>
      来自顶层组件中的数据为:{{ roomData }}
    </div>
    <div>
      来自顶层组件的响应式数据:
    </div>
   </div>
</template>

在这里插入图片描述

跨层传递响应式数据

顶层组件
provide('app-key',ref对象)
底层组件
const message = inject('app-key')

例子

顶层组件RoomPage.vue
<script setup>
import RoomMsgItem from './RoomMsgItem.vue'
import {provide,ref} from 'vue'
// 组件嵌套关系:
// RoomPage -> RoomMsgItem -> RoomMsgComment

// 1.顶层组件提供数据(传递普通数据)
provide('data-key','this is room data')

// 传递响应式数据
const count = ref(0)
provide('count-key',count)

setTimeout(()=>{
  count.value=100
},3000)
</script>
<template>
<div>
  顶层组件
  <RoomMsgItem />
</div>
</template>
中间组件RoomMsgItem,vue
<script setup>
import RoomMsgComment from './RoomMsgComment.vue'
</script>
<template>
   <div>
    中间组件
    <RoomMsgComment />
   </div>

</template>
底层组件RoomMsgComment.vue
<script setup>
import {inject} from 'vue'

// 2.接收数据(普通数据)
const roomData = inject('data-key')

// 接收响应式数据
const countData = inject('count-key')
</script>

<template>
   <div>
    底层组件
    <div>
      来自顶层组件中的数据为:{{ roomData }}
    </div>
    <div>
      来自顶层组件的响应式数据:{{countData}}
    </div>
   </div>

</template>

在这里插入图片描述

跨层传递方法

顶层组件可以向底层组件传递方法,底层组件调用方法修改顶层组件中的数据

顶层组件
const setCount = ()=>{
count.value++
}
provide('setCount-key',setCount)
底层组件
const setCount = inject('setCount-key')

例子`

顶层组件RoomPage.vue
<script setup>
import RoomMsgItem from './RoomMsgItem.vue'
import {provide,ref} from 'vue'
// 组件嵌套关系:
// RoomPage -> RoomMsgItem -> RoomMsgComment

// 1.顶层组件提供数据(传递普通数据)
provide('data-key','this is room data')

// 传递响应式数据
const count = ref(0)
provide('count-key',count)

setTimeout(()=>{
  count.value=100
},3000)


// 传递方法(谁的数据谁负责修改)
const setCount = ()=>{
count.value++
}
provide('setCount-key',setCount)
</script>
<template>
<div>
  顶层组件
  <RoomMsgItem />
</div>
</template>

中间组件RoomMsgItem,vue
<script setup>
import RoomMsgComment from './RoomMsgComment.vue'
</script>
<template>
   <div>
    中间组件
    <RoomMsgComment />
   </div>

</template>
底层组件RoomMsgComment.vue
<script setup>
import {inject} from 'vue'

// 2.接收数据(普通数据)
const roomData = inject('data-key')

// 接收响应式数据
const countData = inject('count-key')

// 接收方法
const setCount = inject('setCount-key')
</script>

<template>
   <div>
    底层组件
    <div>
      来自顶层组件中的数据为:{{ roomData }}
    </div>
    <div>
      来自顶层组件的响应式数据:{{countData}}
    </div>
    <div>
      <button @click="setCount">修改顶层组件的数据count</button>
    </div>
   </div>

</template>

在这里插入图片描述

总结

1.provide和inject的作用是什么?
跨层组件通信
2.如何在传递的过程中保持数据响应式?
第二个参数传递ref对象
3.底层组件想要通知顶层组件做修改,如何做?
传递方法,底层组件调用方法
4.一颗组件树中只有一个顶层或底层组件吗?
相对概念,存在多个顶层和底层的关系

十三、Pinia

什么是Pinia

Pina是Vue的专属的最新状态管理库,是Vuex状态管理工具的替代品。

1.提供更加简单的API(去掉了mutation)
2.提供符合组合式风格的API(和Vue3新语法统一)
3.去掉了modules的概念,每一个store都是一个独立的模块
4.搭配TypeScript一起使用提供可靠的类型推断

添加Pinia到Vue项目

1.使用create-vue创建空的新项目
npm init vue@latest
2.按照官方文档安装pinia到项目
npm install pinia
3.在main.js文件配置pinia

//1.导入createPinia
import { createPinia } from 'pinia'
//2.执行方法得到实例
const pinia = createPinia()
//3.把pinia实例加入到app应用中
createApp(App).use(pinia).mount('#app')

实现Pinia实现计数器案例(Pinia-counter的基础使用)

1.在stores/counter定义Store(state+action 同步+异步)
在这里插入图片描述
2.在vue组件使用Store
在这里插入图片描述
3.结果
在这里插入图片描述

Pinia-getters和异步action

getters的实现:Pinia中的getters直接使用computed函数进行模拟
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
action如何实现异步:action中实现异步和组件中定义数据和方法的风格完全一致
在这里插入图片描述
![在这里插入图片描述](https://img-blog.csdnimg.cn/9ee8aef5517f49fe8aa360205399f2f6.png在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

Pinia-storeToRefs和调试

storeToRefs:使用storeToRefs函数可以辅助保持数据(state+getter)的响应式解构
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
用与不用storeToRefs的区别:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
注意方法直接从原来的counterStore中解构赋值
在这里插入图片描述

总结

1.Pinia是用来做什么的?
集中状态管理工具,新一代的vuex
2.Pinia中还需要mutation吗?
不需要,action既支持同步也支持异步
3.Pinia如何实现getter?
computed计算属性函数
4.Pinia产生的Store如何解构赋值数据保持响应式?
storeToRefs

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值