对比Vue2

Vue3使用与Vue2选项式api不同的组合式api
javascript
// Vue2
<script>
export default {
data(){
return {
count:0
}
},
methods:{
addCount(){
this.count++
}
}
}
</script>
javascript
// Vue3
<script setup>
import { ref } from 'vue'
const count = ref(0)
const addCount = ()=> count.value++
</script>
create-vue
create-vue是Vue官方新的脚手架工具,底层切换到了 vite,为开发提供极速响应

安装命令
npm init vue@latest
组合式API - setup选项
在beforeCreate钩子之前执行

不在script加时需要像Vue2中的data一样
javascript
<script>
export default {
setup(){
const message = 'this is message'
const logMessage = ()=>{
console.log(message)
}
// 必须return才可以
return {
message,
logMessage
}
}
}
</script>
在script中加入后的语法糖写法
javascript
<script setup>
const message = 'this is a message'
const logMessage = () => {
console.log(message)
}
</script>
<template>
<div>{{ message }}</div>
<button @click="logMessage">按钮</button>
</template>
注意不用this:setup中的this指向undefined
reactive()
作用:接受对象类型数据的参数传入并返回一个响应式的对象
- 从 vue 包中导入 reactive 函数
2.在<script setup>中执行 reactive 函数并传入类型为对象的初始值,并使用变量接收函数返回值
只能传类型为对象的初始值
javascript
import { reactive } from 'vue'
const state = reactive({
count: 100
})
const setCount = () => {
state.count++
}
ref()
作用:接收简单类型或者对象类型的数据传入并返回一个响应式的对象
-
从 vue 包中导入 ref 函数
-
在<script setup>中执行 ref 函数并传入初始值,并使用变量接收函数返回值
javascript
// 2. ref: 接收简单类型 或 复杂类型,返回一个响应式的对象
// 本质:是在原有传入数据的基础上,外层包了一层对象,包成了复杂类型
// 底层,包成复杂类型之后,再借助 reactive 实现的响应式
// 注意点:
// 1. 脚本中访问数据,需要通过 .value
// 2. 在template中,.value不需要加 (帮我们扒了一层)
import { ref } from 'vue'
const count = ref(0)
const setCount = () => {
count.value++
}
computed计算属性函数
计算属性基本思想和Vue2的完全一致,组合式API下的计算属性只是修改了写法
-
导入computed函数
-
执行函数在回调参数中return基于响应式数据做计算的值,用变量接收
javascript
<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)
})
// 定义一个修改数组的方法
const addFn = () => {
list.value.push(666)
}
</script>
<template>
<div>
<div>原始数据: {{ list }}</div>
<div>计算后的数据: {{ computedList }}</div>
<button @click="addFn" type="button">修改</button>
</div>
</template>
注意:计算属性应该是只读的,特殊情况可以配置 get set(看官网)
watch函数
-
导入watch函数
-
执行watch函数传入要侦听的响应式数据(ref对象)和回调函数
javascript
<script setup>
import { ref, watch } from 'vue'
const count = ref(0)
const nickname = ref('张三')
const changeCount = () => {
count.value++
}
const changeNickname = () => {
nickname.value = '李四'
}
// 1. 监视单个数据的变化
// watch(ref对象, (newValue, oldValue) => { ... })
watch(count, (newValue, oldValue) => {
console.log(newValue, oldValue)
})
// 2. 监视多个数据的变化
// watch([ref对象1, ref对象2], (newArr, oldArr) => { ... })
watch([count, nickname], (newArr, oldArr) => {
console.log(newArr, oldArr)
})
// 3. immediate 立刻执行
watch(count, (newValue, oldValue) => {
console.log(newValue, oldValue)
}, {
immediate: true
})
// --------------------------------------------
// 4. deep 深度监视, 默认 watch 进行的是 浅层监视
// const ref1 = ref(简单类型) 可以直接监视
// const ref2 = ref(复杂类型) 监视不到复杂类型内部数据的变化
const userInfo = ref({
name: 'zs',
age: 18
})
const setUserInfo = () => {
// 修改了 userInfo.value 修改了对象的地址,才能监视到
// userInfo.value = { name: 'ls', age: 50 }
userInfo.value.age++
}
// deep 深度监视
// watch(userInfo, (newValue) => {
// console.log(newValue)
// }, {
// deep: true
// })
// 5. 对于对象中的单个属性,进行监视
watch(() => userInfo.value.age, (newValue, oldValue) => {
console.log(newValue, oldValue)
})
</script>
Vue3的生命周期API

生命周期函数基本使用
-
导入生命周期函数
-
执行生命周期函数 传入回调
javascript
<script setup>
import { onMounted } from 'vue';
// beforeCreate 和 created 的相关代码
// 一律放在 setup 中执行
const getList = () => {
setTimeout(() => {
console.log('发送请求,获取数据')
}, 2000)
}
// 一进入页面的请求
getList()
// 如果有些代码需要在mounted生命周期中执行
onMounted(() => {
console.log('mounted生命周期函数 - 逻辑1')
})
// 写成函数的调用方式,可以调用多次,并不会冲突,而是按照顺序依次执行
onMounted(() => {
console.log('mounted生命周期函数 - 逻辑2')
})
</script>
组合式API - 父子通信
父传子
基本思想:
-
父组件中给子组件以绑定属性的方式传值
-
子组件内部通过props选项接收
注意:由于写了 setup,所以无法直接配置 props 选项,所以此处需要借助于 "编译器宏" 函数接收子组件传递的数据
对于props传递过来的数据,模板中可以直接使用
在js里需要props.调用

子传父
基本思想:
-
父组件中给子组件标签通过@绑定事件
-
子组件内部通过 emit 方法触发事件

通过模板引用
模板引用的时机是什么在组件挂载完毕时
javascript
// 模板引用(可以获取dom,也可以获取组件)
// 1. 调用ref函数,生成一个ref对象
// 2. 通过ref标识,进行绑定
// 3. 通过ref对象.value即可访问到绑定的元素(必须渲染完成后,才能拿到)
const inp = ref(null)
javascript
<div>
<input ref="inp" type="text">
<button @click="clickFn">点击让输入框聚焦</button>
</div>
defineExpose()
默认情况下在<script setup>语法糖下组件内部的属性和方法是不开放给父组件访问的,可以通过defineExpose 编译宏指定哪些属性和方法允许访问**(显式暴露组件内部的属性和方法)**
javascript
<script setup>
const count = 999
const sayHi = () => {
console.log('打招呼')
}
defineExpose({
count,
sayHi
})
</script>
javascript
<script setup>
const testRef = ref(null)
const getCom = () => {
console.log(testRef.value.count)
testRef.value.sayHi()
}
</script>
javascript
<TestCom ref="testRef"></TestCom>
<button @click="getCom">获取组件</button>
组合式API - provide和inject
顶层组件向任意的底层组件传递数据和方法,实现跨层组件通信
- 导入povide,顶层组件通过provide函数提供数据
javascript
import { provide, ref } from 'vue'
// 1. 跨层传递普通数据
provide('theme-color', 'pink')
// 2. 跨层传递响应式数据
const count = ref(100)
provide('count', count)
setTimeout(() => {
count.value = 500
}, 2000)
// 3. 跨层传递函数 => 给子孙后代传递可以修改数据的方法
provide('changeCount', (newCount) => {
count.value = newCount
})
- 导入inject,底层组件通过inject函数获取数据
javascript
<script setup>
import { inject } from 'vue'
const themeColor = inject('theme-color')
const count = inject('count')
const changeCount = inject('changeCount')
const clickFn = () => {
changeCount(1000)
}
</script>
<template>
<div>
<h3>我是底层组件-{{ themeColor }} - {{ count }}</h3>
<button @click="clickFn">更新count</button>
</div>
</template>
defineOptions
如果我们要定义组件的 name 或其他自定义的属性,得再添加一个<script></script>在其中export
所以我们可以用 defineOptions 定义任意的定义 Options API 的选项, props, emits, expose, slots 除外(因为这些可以使用 defineXXX 来做到)

defineModel()
自定义组件上使用v-model, 相当于传递一个modelValue属性,同时触发 update:modelValue 事件

javascript
<script setup>
import MyInput from '@/components/my-input.vue'
import { ref } from 'vue'
const txt = ref('123456')
</script>
<template>
<div>
<MyInput v-model="txt"></MyInput>
{{ txt }}
</div>
</template>
javascript
<script setup>
const modelValue = defineModel()
</script>
<template>
<div>
<input
type="text"
:value="modelValue"
@input="e => modelValue = e.target.value"
>
</div>
</template>
defineModel()
返回的值是一个 ref。它可以像其他 ref 一样被访问以及修改,不过它能起到在父组件和当前变量之间的双向绑定的作用:
- 它的
.value
和父组件的v-model
的值同步; - 当它被子组件变更了,会触发父组件绑定的值一起更新
可以在子组件中更改父组件传过来的值并同步到父组件