Vue3入门
使用create-vue创建项目
create-vue 是Vue官方新的脚手架工具,底层切换到了vitr(下一代构建工具),为开发提供极速响应
-
前提环境:
- 已安装16.0或更高版本的Node.js
- node -v
-
创建一个Vue应用
- npm init vue@latest
- 这一指令将会安装并执行create-vue
成功——————————————\^o^/
项目目录和关键文件
1. 插件更换
将原来的Vetur禁用,并安装Volar
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的入口)
- 比beforeCreate执行还早
- 也就是说它在创建实例之前就执行了,所以setup函数中是获取不到this的,也就是undefined
- setup需要写成一个函数,直接往配置项里面去写
- 将来里面可以编写组合式的API,可以往里面调各种函数
setup选项中写代码的特点:
原来:
setup提供的任何数据或者函数,如果想要在模板中使用,就必须return
举例:
<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>
-
- 从vue包中导入ref函数
-
- 在
<script setup>
中执行 ref 函数并传入初始值,使用变量接收 ref 函数的返回值
- 在
- ! 需要简单类型的写它
总结/区别
组合式API—computed
核心步骤:
- 导入computed函数
- 执行函数 在回调参数中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>
组合式API——watch
作用:侦听一个或多个数据的变化,数据变化时执行回调函数
基础使用 - 侦听单个数据
- 导入watch函数
- 执行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>
两个额外参数:
- immediate (立刻执行)
- deep (深度侦听),
- 默认watch进行的是 浅层监视
- (也就是可以直接监测到简单类型数据变化;但是监测不到复杂类型内部数据的变化)
<script>
const count = ref(0)
watch(count, () => {
console.log('count发生了变化变化')
}, {
immediate: true // 一进页面立刻执行一次
deep:true
})
</script>
想要精确侦听 对象的某个属性
刚刚那样直接deep:true,监听到的是整个对象,并且里面包含各个详细的内部数据变化
指定监听对象里的某个具体的数据
这样当对象里别的数据变化时,就不会触发这个监听了
组合式API——生命周期函数
组合式API——父子通信
父传子
- 父组件中给子组件绑定属性(以添加属性的方式传值)
- 子组件内部通过props选项接收
- 由于写了setup,所以无法直接配置props选项
- 所以需要借助“编译器宏”函数,来接收子组件传递的数据
传死数据
传动态数据(父组件这里改变子组件也会响应改变)
到时候直接对你用ref声明的变量money在父组件里绑定事件,就可以动态修改并响应了
所以这里父传子传的数据是动态数据
子传父
- 父组件中给子组件标签通过@绑定事件
- 子组件内部通过emit方法触发事件
- 所以就需要编译器宏生成emit方法
- 编译器宏里面需要传数组
- 然后父组件就可以@监听了
组合式API——模板引用
通过ref ——表示获取真实的dom对象 或者 组件实例对象
获取模板引用的时机是什么?
组件挂载完毕
如何使用( 以获取do为例 组件同理 )
- 首先调用ref函数生成一个ref对象
- 在页面中通过ref标识绑定ref对象到标签
- 通过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>
但是
这里有个小问题:我明明声明了,为什么打印不出来
defineExpose()
- 在默认情况下
<script setup>
语法糖下组件内部的属性和方法是不开放给父组件访问的 - 可以通过
defineExpose
编译宏 指定哪些属性和方法允许访问
组合式API——provide和inject
作用和场景
顶层组件向任意的底层组件传递数据和方法,实现跨层组件通信
跨层传递数据
实现步骤
- 顶层组件通过 provide 函数提供 数据
- 底层组件通过 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)
}