Vue3学习

146 阅读5分钟

Vue3入门

image.png

使用create-vue创建项目

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

  1. 前提环境:

    • 已安装16.0或更高版本的Node.js
    • node -v
  2. 创建一个Vue应用

    • npm init vue@latest
    • 这一指令将会安装并执行create-vue
image.png

成功——————————————\^o^/

image.png

项目目录和关键文件

联想截图_20240204140812.png

1. 插件更换

将原来的Vetur禁用,并安装Volar

image.png

2. setup

//app.vue中
<!-- 加上setup允许在script中直接编写组合式api -->
<script setup>
</script>

3. 在vue3中组件导入后无需注册直接使用

4. template不再要求只能有一个根元素了

5. main.js

import './assets/main.css'

// new Vue() 创建一个实例 => createApp()
// createRouter() createStore()
// 将创建实例进行了封装,保证每个实例的独立封闭性
import { createApp } from 'vue'
import App from './App.vue'

// 前半段是创建实例,后半段mount是将app往实例上挂载
// mount是设置挂载点#app的意思(挂载到index.html)
createApp(App).mount('#app')

6. 有index.html,提供挂载点

组合式API—setup选项(组合式api的入口)

image.png
  • 比beforeCreate执行还早
  • 也就是说它在创建实例之前就执行了,所以setup函数中是获取不到this的,也就是undefined
  • setup需要写成一个函数,直接往配置项里面去写
  • 将来里面可以编写组合式的API,可以往里面调各种函数

setup选项中写代码的特点:

原来:

setup提供的任何数据或者函数,如果想要在模板中使用,就必须return

举例:

image.png

<script>
export default {
  setup () {
    // 数据
    const message = 'hello vue3'
    // 函数
    const logMessage = () => {
      console.log(message)
    }
    
    return {
      message,
      logMessage
    }
  }
}
</script>

<template>
  <div>{{ message }}</div>
  <button @click="logMessage">按钮</button>
</template>

setup语法糖

问题:每个都要写return太麻烦了

解决:写成<script setup>

<script setup> 
const message = 'this is a message' 
const logMessage = () => { console.log(message) }
</script>

组合式API—reactive和ref函数(声明数据)

1. reactive()

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

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

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

  • 1.从vue包中 导入reactive函数
  • 2.在<script setup>执行reactive函数 并传入 类型为对象 的初始值,并使用变量接收返回值
  • 必须是函数()包对象的{}的写法,不包起来就是普通对象了

比如:

<script setup>
// reactive:接收一个对象类型的数据,返回一个响应式的对象
import { reactive } from 'vue'
const state = reactive({
	count: 100
})
const setCount = () => {
	state.count++
}
</script>

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

2. ref()

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

<script setup>
// ref:接收简单类型 或 复杂类型, 返回一个响应式的队形 
// 本质:是在原有传入数据的基础上,外层包了一层对象,包成了复杂类型 
// 底层,包成复杂类型之后,再借助 reactive 实现的响应式
// 注意点: 
// 1. 访问数据,需要通过 .value(不点的话,返回的是对象)
// 2. 在template中, .value 不需要加(帮我们扒了一层) 

// 推荐: 以后声明数据,统一用 ref => 统一了编码规范


// 导入
import { ref } from 'vue'

// 执行函数 传入参数 变量接收
const count = ref(简单类型或者复杂类型数据)

</script>

    1. 从vue包中导入ref函数
    1. <script setup>中执行 ref 函数并传入初始值,使用变量接收 ref 函数的返回值
  • 需要简单类型的写它

总结/区别

image.png

组合式API—computed

核心步骤:

  1. 导入computed函数
  2. 执行函数 在回调参数中return基于响应式数据做计算的值(计算逻辑),用变量接收
<script setup>
// 导入
import { computed } from 'vue'

// 执行函数 变量接受 在回调参数中return计算值
const computedState = computed(() => {
	return 基于响应式数据做计算之后的值
})
</script>

也就是:

const 计算属性 = computed(()=>{

return 计算返回的结果

})

<script setup>
// const 计算属性 = computed(()=>{
// return 计算返回的结果
// })

import { computed, ref } from 'vue'

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

// 基于list派生一个计算属性,从list中过滤出 >2
const computedList = computed(() => {
	return list.value.filter(item => item > 2) // 但凡是在script脚本中访问数据,都要通过 .value
})

// 定义一个修改数组的方法
const addFn = () => {
	list.value.push(666)
}
</script>

<template>
	<div>
		<div>原始数据: {{ list }}</div>
		<div>计算后的数据: {{ computedList }}</div>
		<button @click="addFn" type="button">修改</button>
	</div>
</template>

image.png

组合式API——watch

作用:侦听一个或多个数据的变化,数据变化时执行回调函数

基础使用 - 侦听单个数据

  1. 导入watch函数
  2. 执行watch函数传入要侦听的响应式数据 (ref对象) 和回调函数
<script setup>

//1. 导入watch
import { ref, watch } from 'vue'
const count = ref(0)

// 2. 调用watch 侦听变化
	// watch后面跟上一个ref对象(count),后面再去写一个回调
// 这里面写count而不是count.value(写.value相当于监视了0,0有什么好监视的)
watch(count, (newValue, oldValue) => {
	console.log(`count发生了变化,老值为${oldValue},新值为${newValue}`)
})
// 上面代码的意思是:一旦当前这个这个count变化了,就会执行后面的回调,后面的回调当中可以拿到新值和老值(即变化前和变化后的)
</script>

基础使用 - 侦听多个数据

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

<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>

两个额外参数:

  1. immediate (立刻执行)
  2. deep (深度侦听),
    • 默认watch进行的是 浅层监视
    • (也就是可以直接监测到简单类型数据变化;但是监测不到复杂类型内部数据的变化)
<script>
const count = ref(0)
watch(count, () => {
	console.log('count发生了变化变化')
}, {
	immediate: true // 一进页面立刻执行一次
        deep:true
})
</script>

想要精确侦听 对象的某个属性

刚刚那样直接deep:true,监听到的是整个对象,并且里面包含各个详细的内部数据变化

指定监听对象里的某个具体的数据

这样当对象里别的数据变化时,就不会触发这个监听了 image.png

组合式API——生命周期函数

image.png

组合式API——父子通信

父传子

  1. 父组件中给子组件绑定属性(以添加属性的方式传值)
  2. 子组件内部通过props选项接收
    • 由于写了setup,所以无法直接配置props选项
    • 所以需要借助“编译器宏”函数,来接收子组件传递的数据

传死数据

image.png

传动态数据(父组件这里改变子组件也会响应改变)

到时候直接对你用ref声明的变量money在父组件里绑定事件,就可以动态修改并响应了

所以这里父传子传的数据是动态数据 image.png

子传父

  1. 父组件中给子组件标签通过@绑定事件
  2. 子组件内部通过emit方法触发事件
    • 所以就需要编译器宏生成emit方法
    • 编译器宏里面需要传数组
  3. 然后父组件就可以@监听了

image.png

组合式API——模板引用

通过ref ——表示获取真实的dom对象 或者 组件实例对象

获取模板引用的时机是什么?

组件挂载完毕

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

  1. 首先调用ref函数生成一个ref对象
  2. 在页面中通过ref标识绑定ref对象到标签
  3. 通过ref对象.value即可访问到绑定的元素(必须渲染完成后,才能拿到)
<script setup>
import {ref} from 'vue'

// 1. 调用ref函数得到ref对象
const h1Ref =ref(null)
</script>

<template>
  <!-- 2. 通过ref标识绑定ref对象 -->
  <h1 ref="h1Ref">我是dom标签h1</h1>
</template>

但是

这里有个小问题:我明明声明了,为什么打印不出来 image.png

defineExpose()

  • 在默认情况下<script setup>语法糖下组件内部的属性和方法是不开放给父组件访问
  • 可以通过defineExpose编译宏 指定哪些属性和方法允许访问

image.png

组合式API——provide和inject

作用和场景

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

image.png

跨层传递数据

实现步骤

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

两处的键名要统一

顶层组件

provide('key',顶层组件中的数据 / ref对象,也就是响应式数据 / 方法)

底层组件

const message = inject('key')

谁的数据谁来维护

  • 意思是当你想在一个组件里修改从别的组件拿过来的数据是不行的,都不是你自己的数据,你改什么^^
  • 这就涉及到 跨层级传递函数
// 在你想要改的数据的vue(也就是你最开始provide这个数据的地方)中提供provide修改的函数,共享方法

//跨层级传递函数=>给孙后代传递可以改数据的方法
provide('changeCount',(newCount) =>{
  count.value = newCount
})


//在子孙后代中去接收这个函数
const changeCount = inject('changeCount')
const clickFn = () => {
// 调用
  changeCount(1000)
}