vite + vue3
npm create vue@latest
两个插件 vscode
typescript vue plugin
vue language features
options Api 选项式API vue2
composition Api 组合式API vue3
一、第一课 setup 语法糖
组件名字 需要插件的支撑 vite-plugin-vue-setup-extend
<script setup name="Person123" lang="ts"></script>
const app = createApp(App)
app.use(router)
app.mount('#app')
二、第二课 响应式
ref 基本类型和对象类型 哪个数据是响应式的需要用ref包一下
ref用到对象类型的话底层还是用的reactive
let name = ref('38')
reactive 对象类型
let car = reactive({brand:'ss',price:113})
let games = reactive([{name:'222',id:'222'}])
ref 对比 reactive
1、ref创建的对象使用.value (可以使用volar插件自动添加.value)
2、reactive重新分配对象时,会失去响应式 使用Object.assign
解构出来的变量不具备响应式,如果想具备响应式,需要
toRefs:整个json let nl = toRefs(Person)
toRef: let nl = toRef(Person,'age')
三、第三课 计算属性是有缓存的,方法是没有缓存的
ref 定义的一个计算属性
计算属性是一个计算属性,且是只读的
let fullName = computed(()=>{
return
})
计算属性是一个计算属性,可读可写
let fullName = computed(()=>{
get(){
return
},
set(){
}
})
四、第四课 watch监控
只能监控四种数据 监视的是对象的地址值,若想监视对象内部属性的变化,需要配置第三个参数,deep:true
1、ref定义的数据
2、reactive定义的数据,默认开启深度监视
3、ref 或 reactive定义的对象类型数据中的某个属性,属性是基本类型的要写成函数式
watch(()=>Person.name,(n,o)=>{})
监视的如果是对象里面的属性,最好写函数式,注意点:若是对象监视的是地址值,需要关注对象内部,需要手动开启深度监视
watch(谁?,(n,o)=>{
console.log()
},{deep:true})
4、监视多个数据
watch([()=>person.name,person.car],{deep:true})
五、第五课 watchEffect 逻辑里有谁就监听谁
watchEffect(()=>{})
六、第六课 用于存储ref标记的内容
<h2 ref="title2">
let title = ref()
在子组件中用defineExpose将组件中的数据交给外部
import {type PersonInter} from '@/types'
let personList:Array<PersonInter> = []
let personList = reactive<Persons>([])
七、第七课 props
接收list
defineProps(['a'])
接收list + 限制类型
defineProps<{list:Persons}>()
接收list + 限制类型 + 限制必要性 + 指定默认值(withDefault)
defineProps<{list?:Persons}>()
指定默认值(withDefault)
withDefault(defineProps<{list?:Persons}>(),{
list:()=>[]
})
八、第八课 组件的生命周期
创建(created) -> 挂载 -> 更新 -> 销毁
创建 -》 setup
onBeforeMount(()=>{
console.log('挂载前')
})
onMounted(()=>{
console.log(‘挂载完毕)
})
onBeforeUpdate(()=>{
console.log('更新前')
})
onUpdated(()=>{
console.log(’更新完毕)
})
onBeforeUnmount(()=>{
console.log('卸载前')
})
onUnmounted(()=>{
console.log('卸载完毕')
})
九、第九课 自定义hooks
命名规范:useOrder.ts / useOrder.js
可在自定义hooks里面用生命周期函数
十、第十课 路由器
const router = createRouter({
history:createWebHistory(),
routes:[{
path:'路径',
component:A
}],
})
<RouterLink to="" active-class=""></RouterLink>
<RouterView></RouterView>
路由组件一般放在 views 或者 pages 一般组件放在components
通过点击导航,视觉效果上消失了的,默认是被卸载的
工作模式:history模式,hash模式
history:createWebHistory() history模式
history.createWebHashHistory() hash模式
let route = useRoute()
<RouterLink :to="{name:'',params:{}}"></RouterLink>
备注1:传递`params`参数时,若使用`to`的对象写法,必须使用`name`配置项,不能用`path`。
备注2:传递`params`参数时,需要提前在规则中占位。
路由规则的props
第一种写法:
{name:'',path:'',component:'',props:true}
第二种写法:
{name:'',path:'',component:'',props(route){return route.query}}
第三种写法:
{name:'',path:'',component:'',props:{a:1,b:1,c:2}}
编程式导航:
const router = useRouter()
router.push()
十一、第十一课 pinia
集中式状态(数据)管理
npm i pinia
import {createPinia} from 'pinia'
const pinia = createPinia()
app.use(pinia)
注意点:reactive里面的ref不用通过.value就可获得。可自动拆包
export const useCountStore = defineStore('count',{
//真正存储数据的地方
state(){
return {
sum:6
}
},
//actions 放置的是一个一个的方法,用于响应组件中的动作
actions:{
increment(value){
//this是当前的store
this.sum += value
}
},
//对数据的加工
getters:{
bigSum(state){
return state.sum * 10
}
}
})
修改数据
const countStore = useCountStore()
//第一种:
countStore.sum += 1
//第二种:批量修改
countStore.$patch({
sum:8
})
//第三种:调用actions
countStore.increment(3)
const {sum,school,address} = storeToRefs(countStore)
//监听数据的变化
countStore.$subscribe(()=>{
console.log()
})
//store的组合式写法
export const useCountStore = defineStore('count',()=>{
const count = ref(0)
function getATalk(){
}
return {count,getATalk}
})
十二、第十二课 组件通信
1、props: 既能父 -> 子 也能 子 -> 父
父传子:
子传父:子组件调用父组件的方法并传值
2、自定义事件 子传父
子组件声明defineEmits(['aaa']),@接收aaa
const emit = defineEmits(['aaa'])
emit('aaa')
3、任意组件通信 mitt 接收数据:提前绑好事件 提供数据:在合适的时间触发
npm i mitt
utils 文件夹 emitter.ts
import mitt from 'mitt'
//绑定事件,触发事件
const emitter = mitt()
//接收事件
emitter.on('')
//触发事件
emitter.emit('')
//解绑事件
emitter.off('')
export default emitter
在组件卸载时解绑
4、v-model 既能父 -> 子 也能 子 -> 父
v-model 用在html的标签上 <HTMLInputElement>$event.target
对于原生事件$event就是事件对象,对于自定义事件,$event就是触发时间时,所传递的数据不能.target
修改modelValue
v-model:aaa
5、$attrs 祖 -> 孙 孙 -> 祖
<Child v-bind="{a,b,c,d}" />
6、$refs 父 -> 子 defineExpose({}) 将数据抛到外部
$parent 子 -> 父
function getAllChild(refs{[key:string]:any})
7、provide inject 祖 -> 子孙
//向后代传递数据,父组件
provide('money',money)
//子组件
let x = inject('money','我是默认值')
8、pinia
9、插槽:
默认插槽 <slot></slot>
具名插槽 <slot name="s2"></slot>
作用域插槽 子 -> 父 <slot name="s2" :games="games"></slot>
<template v-slot:s2="params"></template>
数据在子那边,但根据数据生成的结构却是父亲决定
十三、第十三课 其它Api
shallowRef 浅层次的ref,只能处理第一层的,只能到.value,对于大的json对象有用
shallowReactive 浅层次的reactive
readonly 深只读,参数需是object,保护数据
shallowReadonly 浅层次的只读,只作用于对象的第一层,保护数据
toRaw 获取响应对象的原始对象,返回的对象不再是响应式的
markRaw 标记对象,使其永远不会变成响应式的
customRef 自定义ref let initValue = '你好' const msg = customRef((track,trigger)=>{
return {
//msg 被读取时调用
get(){
track() //告诉Vue要对msg进行持续关注,一旦msg变化就去更新
return initValue
},
//msg 被修改时调用
set(value){
initValue = value
trigger() //通知vue数据变化了
}
}
})
Teleport 传送 <teleport to="id/css/html"></teleport>
Suspense 异步 <Suspense>
<template v-slot:default> //异步任务完成之后出来
<Child />
</template>
<template v-slot:fallback> //异步任务没回来前
<Child />
</template>
</Suspense
十四、第十四课 全局API转移到应用对象
1、app.component main.ts
2、app.config app.config.globalProperties.x = 99
3、app.directive
4、app.mount
5、app.unmount
6、app.use 安装插件