认识Ref全家桶:
ref:接受一个内部值并返回一个响应式且可变的 ref 对象。ref 对象仅有一个 .value property,指向该内部值。
isRef:判断是不是一个ref对象
shallowRef:创建一个跟踪自身 .value 变化的 ref,但不会使其值也变成响应式的。虽然打印的数据变了,但不是响应式,视图未更新
triggerRef :强制更新页面DOM。可以配合shallowRef更新视图
customRef:自定义ref(了解)customRef 是个工厂函数要求我们返回一个对象 并且实现 get 和 set 适合去做防抖之类的
bug:ref和shallowRef同时存在时,ref的更新会导致shallowRef的更新
认识Reactive全家桶:
reactive:不可以绑定普通的数据类型,会给我们报错
不推荐直接赋值,会改变引用类型数据的地址,破坏了数据的响应式。可以push、包裹一层对象来解决该问题
readonly:拷贝一份proxy对象将其设置为只读,修改会报错
shallowReactive:只能对浅层的数据 如果是深层的数据只会改变值,不会改变视图。如果和浅层数据一起改变则都会更新视图
认识to系列全家桶:
toRef:如果原始对象是非响应式的就不会更新视图,数据是会变的
toRefs:可以帮我们批量创建ref对象主要是方便我们解构使用
toRaw:将响应式对象转化为普通对象
Computed计算属性:
写法:
// const name = computed(()=>{//第一种
// return firstName.value + '————————————————' + lastName.value
// })
const name = computed({//第二种
get() {
return firstName.value + lastName.value
},
set() {
firstName.value + lastName.value
}
})
Watch监听器:使用ref时:deep可以开启深度监听 immediate第一次立即执行。 reactive不写也可以监听
watch([message,message2],(newval,oldval)=>{
console.log("new:",newval,"old:",oldval);
},{
deep:true
immediate:true
})
可以监听对象内单一属性 ()=>对象.属性
WatchEffect高级监听器:每次更新都会先执行一次oninvalidate
watchEffect((oninvalidate)=>{
console.log('message===>',message.value);
console.log('message2===>',message2.value);
oninvalidate(()=>{
console.log("before先执行");
})
})
组件的生命周期:
onBeforeMounted、onMounted、onBeforeUpdate、onUpdated、onBeforeUnmount、onUnmounted
组件通讯:
<Menu ref="menus" :data="list" @on-click="getList" @on-click2="getList" title="我是静态标题"></Menu>
const getList = (list:number[],flag:boolean) => {
console.log(list,'子组件',flag);
console.log(menus.value,"aaaaaaaa");
}
type Props = {
title:string
data:number[]
}
defineProps<Props>()//子组件defineProps接收父组件传递的数据
const emit = defineEmits(['on-click','on-click2'])
const clickTap = () => {
emit('on-click',list,false)//defineEmits定义,emit发送数据。父组件@on-click="getList"调用
}
defineExpose({})//可以暴露子组件的属性方法到父组件,使用ref.value访问
type Props = {
title?:string
data?:number[]
}
withDefaults(defineProps<Props>(),{
title:"默认值",
data:() => [1,2,3]
})//设置默认值,如果没传递值则采用默认值
组件:
全局组件:mian.ts中注册:createApp(App).component('Card',Card).mount('#app')
局部组件:import直接导入实例化,不需要component注册
递归组件:1.在组件内部重新import导入实例化,并调用。2.再定义一个script标签,export default导出name。
派发内容要在TreeItem和父组件都派发
<template>
<div v-for="(item,index) in data" :key="index" style="margin-left:10px;">
{{item.name}}
<TreeItem v-if="item?.children?.length" :data="item.children"></TreeItem>
</div>
</template>
<script setup lang="ts">
// import TreeItem from './index.vue'//第一种
import { type } from 'os';
import { reactive } from 'vue';
type TreeList = {
name:string,
icon?:string,
children?:TreeList[] | []
}
type Props = {
data?:TreeList[]
}
defineProps<Props>()
</script>
<script lang="ts">
export default {
name:"TreeItem"//第二种
}
</script>
动态组件:
<component :is="A"></component>//A组件实例的方式来使用
补充:markRow(A)可以跳过Proxy代理,组件不需要是Proxy对象。在vue2中可以绑定字符串,vue3不行,要export default注册
插槽:slot
匿名插槽:<slot></slot>
<template v-slot>
<div>
默认插槽的内容
</div>
</template>
具名插槽:<slot name="header></slot>
<template v-slot:header>
<div>
具名插槽的内容
</div>
</template>
<template #footer>//简写。默认插槽#default
<div>
具名插槽的内容
</div>
</template>
作用域插槽:父组件可以拿到子组件的值
<template #default="{data}">
<div>
{data}//data未<slot :data="item"></slot>传递的值
</div>
</template>
动态插槽:
<template #[name]>
<div>
动态插槽的内容
</div>
</template>
let name = ref('default')
let name = ref('footer')
异步组件:
打包:npm run build =>生成dist文件
Teleport传送组件:将我们的模板渲染到指定DOM结点。不受父级的v-show、style影响,但受v-if影响
<teleport to='body'>
<div>loading.....</div>
</teleport>
keep-alive缓存组件:(内置组件)
属性:include(需要缓存的组件)、exclude(不需要缓存的组件)、max(缓存的数量)
增加的生命周期:onActivated、onDeactivated
transition动画组件:
<transition name="fade">
<div v-if="flag" class="box"></div>
</transition>
//定义name="fade",在style里定义,fade-enter-from、fade-enter-active、fade-enter-to、fade-leave-from.....
//也可以在transition内自定义对应类名:enter-from-class="e-from"
也可以使用第三方类库:animate.css
安装:npm install animate.css 引入: import 'animate.css'
<transition
:duration="500"
leave-active-class="animate__animated animate__fadeOut"
enter-active-class="animate__animated animate__fadeIn"
>
<div v-if="flag" class="box"></div>
</transition>
生命周期(8个): @before-enter="beforeEnter" //对应enter-from
@enter="enter"//对应enter-active
@after-enter="afterEnter"//对应enter-to
@enter-cancelled="enterCancelled"//显示过度打断
@before-leave="beforeLeave"//对应leave-from
@leave="leave"//对应enter-active
@after-leave="afterLeave"//对应leave-to
@leave-cancelled="leaveCancelled"//离开过度打断
//当只用 JavaScript 过渡的时候,在 enter 和 leave 钩子中必须使用 done 进行回调
结合gsap 动画库使用 GreenSock
<transition
@before-enter="EnterFrom"
@enter="EnterActive"
@leave="Leave"
>
<div v-if="flag" class="box"></div>
</transition>
const EnterActive = (el:Element,done:gsap.Callback) => {
gsap.to(el,{
width:200,
height:200,
onComplete:done
})
}
appear:设置初始节点过度 就是页面加载完成就开始动画
transition-group过度列表:
<transition-group tag="section">//tag给内部元素套一层标签
<div class="items" v-for="item in list" :key="item">{{item}}</div>
</transition-group>
<transition-group
enter-active-class="animate__animated animate__hinge"
leave-active-class="animate__animated animate__hinge">
<div class="items" v-for="item in list" :key="item">{{item}}</div>
</transition-group>
new Array(81)//
Array.apply(null,{length:81} as number[])//会初始化每一条数据为undefined
//案例,随机排列81个1-9的数字,并使用动画(补充:lodash的shuffle()可以创建一个被打乱的集合)
<div>
<button @click="random">Shuffle</button>
<transition-group
move-class="mmm"
tag="div" class="wraps">
<div class="items" v-for="item in list" :key="item.id">{{item.number}}</div>
</transition-group>
</div>
import { shuffle } from 'lodash';
import { ref } from 'vue'
let list = ref(Array.apply(null,{length:81} as number[]).map((_,index)=>{
return {
id:index,
number:(index % 9) + 1
}
}))
const random = () => {
list.value = shuffle(list.value)
}
.mmm {
transition: all 2s;
}
状态过度
Provide / Inject:
父、祖组件使用provide提供数据或方法,子孙使用inject接收provide提供的数据或方法
import { provide,ref } from 'vue';
provide('flag',ref(false))
import { inject,Ref,ref } from 'vue';
let data = inject<Ref<boolean>>('flag',ref(false))
//Ref解决类型推断的报错,第二个参数“ref(false)”设置默认值,避免接收到undefined的情况,使用?.语法会导致无法赋值
兄弟组件传参Event Bus:
定义一个bus.ts公共方法(发布订阅模式)可以使用Mitt代替
TSX:
定义".tsx"类型的文件,定义并导出。使用小括号调用变量如(v-if={falg})。不能使用v-for,可以使用map代替
Vue3自动引入插件:unplugin-auto-import
链接:https://blog.csdn.net/qq_42611074/article/details/123036047
npm i -D unplugin-auto-import =>vite.config.ts中注册=>重新运行项目,自动生成声明文件=>
样式穿透:scoped(给dom结点添加一个不重复的data属性,如data-v-123)Vue2:/deep/ .类名{} Vue3::deep(.类名){}
CSS新特性:
插槽选择器::slotted(.a) {}//选择插槽内容的class类名。:deep好像也行
全局选择器::global(div) {}//设置全局div的属性
动态 CSS:color: v-bind(style);//动态绑定script内定义的"style"变量
color: v-bind('style.color');//动态绑定script内定义的"style"对象的color属性。可以动态修改对应的属性值
css module:
Vue3集成Tailwind CSS
Event Loop时间循环机制:
所有的同步任务都是在主进程执行的形成一个执行栈,主线程之外,还存在一个"任务队列",异步任务执行队列中先执行宏任务,然后清空当次宏任务中的所有微任务,然后进行下一个tick如此形成循环。
nextTick:nextTick 就是创建一个异步任务,那么它自然要等到同步任务执行完成后才执行。
Vue如何开发移动端:
vw 视口的最大宽度,1vw等于视口宽度的百分之一
vh 视口的最大高度,1vh等于视口高度的百分之一
unocss原子化:tips:最好用于vite webpack属于阉割版功能很少。使用一些class类名实现样式布局
函数式编程,h函数:h 接收三个参数
1.type 元素的类型
2.propsOrChildren 数据对象, 这里主要表示(props, attrs, dom props, class 和 style)
3.children 子节点