学习vue3过程中的一些笔记,记录自己对知识点的理解
创建Vue3.0工程
使用 vue-cli 创建:
## 查看@vue/cli版本,确保版本在4.5.0以上
##vue --version
## 安装或者升级你的@vue/cli
npm install -g @vue/cli
## 创建
vue create vue_test
## 启动
cd vue_test
npm run serve
vite —— 新一代前端构建工具。按需编译。开发环境中不用打包,快速冷启动。轻量快速的热重载。
使用 vite 创建:
## 创建工程
/npm init vite-app <project-name>
npm init vue@latest//会安装并执行create-vue(底层切换到了vite)
## 进入工程目录
cd <project-name>
## 安装依赖
npm install
## 运行
npm run dev
Vue3的main.js
//引入的不再是Vue构造函数,而是createApp工厂函数,接受一个根组件作为参数,并返回一个应用实例。
import { createApp } from 'vue'
import App from './App.vue'
//创建应用实例对象——app(类似于Vue2的vm,但app更“轻”)
const app = createApp(App)
//将Vue应用程序渲染到指定id的HTML元素中。
app.mount('#app')
setup–一个函数,是vue3新的配置项
组件中所用到的:数据、方法等等,均要配置在setup中。
返回对象中的属性、方法, 在模板中可直接使用。
注意:不要再混用Vue2配置(data、methos、computed...)。
setup(){
...
return {}
}
ref函数–定义响应式的数据
把数据加工为引用对象,实现响应式。
接收的数据:
- 基本类型:响应式靠Object.defineProperty()的get与set完成。
- 对象类型:内部求助Vue3.0中的新函数—— reactive函数。
const xxx = ref(initValue)
- JS中操作数据: xxx.value
- 模板中读取数据: <div>{{xxx}}</div>
import {ref} from 'vue'
setup(){
let name = ref('张三')
let age = ref(18)
let job = ref({
type:'hello',
name:'98K'
})
function changeInfo(){
name.value = '李四'
job.value.salary = '60K'
}
return {
name,
age,
job,
changeInfo
}
}
reactive函数–定义一个对象类型的响应式数据
const 代理对象= reactive(源对象)接收一个对象(或数组),返回一个代理对象(Proxy的实例对象,简称proxy对象)
import {reactive} from 'vue'
setup(){
let job = reactive({
type:'hello',
name:'98K'
})
function A(){
job.salary = '60K'//不用.value,可直接引用
}
return {
job,
A
}
}
computed函数
import {computed} from 'vue'
setup(){
//简写
let fullName = computed(()=>{
return person.firstName + '-' + person.lastName
})
}
watch函数–
ref定义的响应式数据:
//一个
watch(sum,(newValue,oldValue)=>{
console.log('sum变化了',newValue,oldValue)
},{immediate:true})
//多个
watch([sum,msg],(newValue,oldValue)=>{
...
})
reactive定义的响应式数据:
/* 监视对象,无法获得oldValue!且强制开启了深度监视,deep配置不再奏效*/
watch(person,(newValue,oldValue)=>{
...
},{immediate:true,deep:false})
//监视 对象的某个属性,deep配置有效
watch(()=>person.job,(newValue,oldValue)=>{
...
},{immediate:true,deep:true})
//监视 多个属性
watch([()=>person.job,()=>person.name],(newValue,oldValue)=>{
...
},{immediate:true,deep:true})
watchEffect–不指明监视哪个属性。监视的回调中用到哪个属性就监视哪个属性
import {watchEffect} from 'vue'
watchEffect(()=>{
const x1 = sum.value
const x2 = person.age
console.log('watchEffect配置的回调执行了')
})
生命周期
命名变化:
beforeDestroy ==>BeforeUnmount
Destroyed ======>Unmounted
Vue3 API形式的生命周期钩子,对应关系如下:
beforeCreate===>setup()
created=======>setup()
beforeMount ===>onBeforeMount
mounted=======>onMounted
beforeUpdate===>onBeforeUpdate
updated =======>onUpdated
beforeUnmount ==>onBeforeUnmount
unmounted =====>onUnmounted
toRef–将对象中的属性单独提供给外部使用
<h2>姓名:{{name}}</h2>
<h2>薪资:{{job.salary}}</h2>
setup(){
let person = reactive({
name:'张三',
job:{
salary:20
}
})
// const name2 = toRef(person,'name')
return {
// name:toRef(person,'name'),
// salary:toRef(person.job,'salary'),
...toRefs(person)//批量创建多个ref对象
}
}
自定义hook函数–把setup的组合式API进行封装,实现代码复用。跟Vue2的mixin相似。
hooks->xx文件中定义:
export default function (){
let point = reactive({
x:0,
y:0
})
onMounted(()=>{
...
})
return point
}
使用:
<h2>{{point.x}},{{point.y}}</h2>
import xx from '../hooks/xx'
export default {
name:'Test',
setup(){
const point = xx()
return {point}
}
}
shallowReactive 与 shallowRef–浅响应式,针对对象。
shallowReactive:只处理对象最外层属性的响应式。
let person = shallowReactive({
name:'张三',
age:18,
job:{
salary:20
}
})
shallowRef:只处理基本数据类型的响应式, 不处理对象的响应式。
readonly 与 shallowReadonly–不希望数据被修改时使用
readonly: 让一个响应式数据变为只读的(深层对象也只读)。
person = readonly(person)
shallowReadonly:让一个响应式数据变为只读的(仅是外层对象只读)。
toRaw 与 markRaw–
toRaw:将一个由reactive生成的响应式对象转为普通对象。
markRaw:标记一个对象,使其永远不会再成为响应式对象。
customRef–创建一个自定义的 ref,并对其依赖项跟踪和更新触发进行显式控制。
<template>
<input type="text" v-model="keyword">
<h3>{{keyword}}</h3>
</template>
<script>
import {ref,customRef} from 'vue'
export default {
name:'Demo',
setup(){
function myRef(value,delay){
let timer
//通过customRef去实现自定义
return customRef((track,trigger)=>{
return{
get(){
track() //告诉Vue这个value值是需要被“追踪”的
return value
},
set(newValue){
clearTimeout(timer)
timer = setTimeout(()=>{
value = newValue
trigger() //让Vue去更新界面
},delay)
}
}
})
}
let keyword = myRef('hello',500) //使用程序员自定义的ref
return {
keyword
}
}
}
</script>
provide 与 inject–实现祖与后代组件间(跨级)通信
provide定义数据,自动向下传递给所有子组件,子组件使用inject注入数据。
祖组件定义:
setup(){
let car = reactive({name:'奔驰',price:'40万'})
provide('car',car)
}
后代组件使用:
setup(){
const car = inject('car')
return {car}
}
响应式数据的判断–
isRef: 检查一个值是否为一个ref对象,是则返回true
isReactive: 检查一个对象是否是由 reactive 创建的响应式代理
isReadonly: 检查一个对象是否是由 readonly 创建的只读代理
isProxy: 检查一个对象是否是由 reactive 或者 readonly 方法创建的代理
Composition API 的优势–
传统API,新增一个需求,就要分别在data,methods,computed里添加,代码分散。
组合式API可以将数据和方法放在同一块区域,代码更加有序。为了更好发挥这个优势,可使用hook函数,对组合式API进行封装。
teleport–将组件html结构移动到指定位置。
比如展示一个弹窗:、
<teleport to="移动位置">
<div v-if="isShow" class="mask">
<div class="dialog">
<h3>弹窗</h3>
<button @click="isShow = false">关闭弹窗</button>
</div>
</div>
</teleport>
Suspense–在异步组件加载完成之前,展示一些占位符内容,避免页面空白。
异步引入组件:
import {defineAsyncComponent} from 'vue'
const Child = defineAsyncComponent(()=>import('./components/Child.vue'))
使用Suspense包裹组件,并配置好default 与 fallback
<template>
<div class="app">
<h3>我是App组件</h3>
<Suspense>
<template v-slot:default>
<Child/>
</template>
//加载完成后,fallback节点会被替换成异步组件
<template v-slot:fallback>
<h3>加载中.....</h3>
</template>
</Suspense>
</div>
</template>
Pinia–是vuex的替代品
提供更加简单的API (去掉了mutation )
去掉了 modules 的概念,每一个store都是一个独立的模块
提供符合组合式风格的API (和 Vue3 新语法统一)
定义
import{defineStore}from'pinia'
import{ref}from'vue'
export const useCounterStore = defineStore('counter',()=>{
const count = ref(0) //state
const increment =()=>{ //action,与vuex不同,可同步可异步。
count.value++
}
//getter
const doubleCount = computed(()=>count.value*2)
}
return{count,increment}
})
使用:
<script>
import {useCounterStore} from '@/stores/counter'
const counterStore = useCounterStore()
//保持数据响应式
//const { count, doubleCount } = storeToRefs(counterStore)
</script>
<template>
<button @click="counterStore.increment">
{{counterStore.count}}
</button>
</template>
语法糖–能让代码易读和易写。比如箭头函数、
<script>
export default{
setup (){
const message ='this is message'
const AA = ()=>{}
return {message,AA}
}
}
</script>
变成:
<script setup>
const message ='this is message'
const AA = ()=>{}
</script>
export default 和 export 区别–都是ES6语法
export 可以导出多个,导入的时候要加花括号{}
导出:
export let i = “hello”;
export function get(){ };
或者:
let i = “hello";
function get(){ };
export { i,get }
导入:import { i,get } from '...';
export default 只能导出一个,导入不用加花括号。先定义后导出
function get(){ };
export default get
import get from '...';