使用vite创建vue3
npm create vite
或者 yarn create vite
composition API
- ref
 - reactive
 - torefs
 - watch
 - watch Effact
 - computed
 
setup
它是组件内使用composition API的入口,执行时机是在beforecreate之前执行的
- 
setup的参数
- props:值为对象,包含:组件外部传递过来,且组件内部声明接受了的属性
 - 
context:上下文对象
- attrs:值为对象,包含:组件外部传递过来,但没有在props声明接收了的函数
 - slots:收到的插槽内容,相当于this.$slots
 - emit:分发自定义事件的函数,相当于this.$emit
 
 
 
ref函数:定义普通类型数据
vue3中定义响应式数据:const name : ref(‘小明’);在js中操作:name.value=‘张三’
reactive函数:定义对象类型响应式数据
let obj = reactive({
   type:'前端工程师',
   salary:'30k'
)
function change(){
    obj.type='后端工程师' //vue3可以直接增删改查数据
    this.$set(obj,'type','后端工程师')//vue2中想要修改数据并渲染必须要用$set,而vue3中可以直接改
}
reactive对比ref
- 
从定义数据角度对比
1).ref用来定义:基本类型数据
2).reactive用来定义:对象(或数组)类型数据
3).ref也可以用来定义对象(或数组)类型数据,它内壁会自动通过reactive转为代理对象
 - 
从原理角度对比
1).ref通过object.defineProperty()的get与set来实现响应式(数据劫持)
2)reactive通过使用proxy来实现数据劫持,并通过Reflect操作源对象内部的数据
 - 
从使用角度对比
- ref定义数据:操作数据需要.value, 读取数据时模板中直接读取不需要.value
 - reactive定义数据:操作数据与读取数据都不需要.value
 
 
computed计算属性
setup(){
    let person = reactive({
        firstName:'张',
        lastName:'三',
    })
    //计算属性简写形式(没有考虑计算属性被修改的情况)
    person.name = computed(()=>{
        return person.firstName+'-'+'person.lastName'
    })
    //计算属性完整写法(考虑读和写)
    person.name = computed(()=>{
        get(){
            return person.firstName+'-'+'person.lastName'
        },
        set(value){  //value是新的值
            const nameArr = value.split('-')
            person.firstName = name[0]
            person.lastName = name[1]
        }
    })
    return{
        firstName,
        lastName,
        name
    }
}
父子传参
父传子:
 在父组件中 
 子组件中用 defineProps({data:string})接受
 子传父:
//在子组件中通过defineEmits派发一个事件
const emit = defineEmits(['test']) 
const clickTap = ()=>{
    emit('test',数据) //派发名为test
}
//在父组件中
<Son @test="回调函数"></Son>
在回调函数中第一个参数就是传过来的数据
兄弟间传值
//1. 安装mitt npm install mitt
//2.在main.js中注册挂载到全局
import mitt from 'mitt'
app.config.globalProperties.$mitt = new mitt()
// 发送数据组件
<button @click="sendMitt">$mitt发送数据</button>
function sendMitt() {
				proxy.$mitt.emit('mittFn', 数据)
			}
//接受数据
proxy.$mitt.on('mittFn', (res) => {
				console.log(res) //res就是传过来的数据
			})
配置全局组件
//在main.ts中配置
import Card from './components/Card/index.vue'
createApp(App).component('Card',Card).mount('#app')
//component中第一参数是组件名称,第二个参数是组件实例
动态组件
//让多个组件使用同一个挂载点,并动态切换,这就是动态组件
import A from './A.vue'
import B from './B.vue'
 <component :is="A"></component> // 通过js切换组件
 //如果你把组件实例放到Reactive Vue会给你一个警告runtime-core.esm-bundler.js
 //修改如下:
const tab = reactive<Com[]>([{
    name: "A组件",
    comName: markRaw(A)
}, {
    name: "B组件",
    comName: markRaw(B)
}])
异步组件 Suspense
// 在父组件中引入异步组件
import {  defineAsyncComponent } from 'vue'
const Dialog = defineAsyncComponent(() => import('../../components/Dialog/index.vue'))
// <suspense> 组件有两个插槽。它们都只接收一个直接子节点。default 插槽里的节点会尽可能展示出来。如果不能,则展示 fallback 插槽里的节点。
     <Suspense>
            <template #default>
                <Dialog></Dialog>
            </template>
            <template #fallback>
                <div>loading...</div>
            </template>
</Suspense>
Teleport传送组件
Teleport 是一种能够将我们的模板渲染至指定DOM节点,不受父级style、v-show等属性影响,但data、prop数据依旧能够共用的技术;例如
<teleport to="body">
      <div class="teleport">我是teleport</div>
    </teleport>
    //可以通过to将div放到body里面,也可以使用class或者id放到指定的dom节点里面
keep-alive缓存组件
有时候我们不希望组件被重新渲染影响使用体验;或者处于性能考虑,避免多次重复渲染降低性能。而是希望组件可以缓存下来,维持当前的状态。这时候就需要用到keep-alive组件。
 keep-alive对应两个独有的生命周期 onActivated 和 deactivated
<!-- 基本 -->
<keep-alive>
  <component :is="view"></component>
</keep-alive>
<!-- 多个条件判断的子组件 -->
<keep-alive>
  <comp-a v-if="a > 1"></comp-a>
  <comp-b v-else></comp-b>
</keep-alive>
<!-- 和 `<transition>` 一起使用 -->
<transition>
  <keep-alive>
    <component :is="view"></component>
  </keep-alive>
</transition>
keep-alive生命周期的变化:
 初次进入时:OnMounted 和 onActivated
 退出时:deactivated
 再次进入时只会触发:onActivated
 只执行一次的放在 onMounted中;组件每次进去执行的方法放在 onActivated中
<keep-alive :include="[]" :exclude="" :max=""></keep-alive>
// include数组中可以填入组件名称name,:include里面包含的组件才会被缓存,没有包含的不会被缓存
:exclude则相反; :max 则最大缓存的组件个数
transition 动画组件
自定义 transition 过度效果,你需要对transition组件的name属性自定义。并在css中写入对应的样式
 transition标签中n的ame对应的css标签的设置
 name-enter-from:定义进入过渡的开始状态。
 name-enter-active:定义进入过渡生效时的状态
 name-enter-to:定义进入过渡的结束状态
 name-leave-from:定义离开过渡的开始状态。
 name-leave-active:定义离开过渡生效时的状态
 name-leave-to:离开过渡的结束状态。
 <transition name='fade'>
         <div v-if='flag' class="box"></div>
       </transition>
    //对应css   
.fade-enter-from{
   background:red;
   width:0px;
   height:0px;
   transform:rotate(360deg)
}
//开始过度了
.fade-enter-active{
  transition: all 2.5s linear;
}
//过度完成
.fade-enter-to{
   background:yellow;
   width:200px;
   height:200px;
}
//离开的过度
.fade-leave-from{
  width:200px;
  height:200px;
  transform:rotate(360deg)
}
//离开中过度
.fade-leave-active{
  transition: all 1s linear;
}
//离开完成
.fade-leave-to{
  width:0px;
   height:0px;
}
也可以通过自定义过渡class类名;通过自定义class结合animate css动画库
 <transition
            leave-active-class="animate__animated animate__bounceInLeft"
            enter-active-class="animate__animated animate__bounceInRight"
        >
            <div v-if="flag" class="box"></div>
        </transition>
结合gsap动画库使用GreenSock
vue3全局定义函数和变量
由于Vue3没有prototype属性,是使用app.config.globalProperties代替,然后去定义变量和函数
 vue2中: vue.prototype.$http = ()=>{}
vue3中: const app = createApp(APP)
 app.config.globalProperties.$http = () => {}
CSS样式穿透
vue中使用了scoped后,会在dom结构上会以date-v-hash的方式加在标签上,以保证唯一,不会样式冲突,从而达到样式私有模块化。
 在使用UI组件库的时候,很多时候需要改它默认的样式,就需要用到样式穿透:
 在样式中使用 :deep(input) 这样就可以了
Pinia 全局状态管理工具 代替Vuex
Pinia.js 有如下特点:
完整的 ts 的支持;
 足够轻量,压缩后的体积只有1kb左右;
 去除 mutations,只有 state,getters,actions;
 actions 支持同步和异步;
 代码扁平化没有模块嵌套,只有 store 的概念,store 之间可以自由使用,每一个store都是独立的
 无需手动添加 store,store 一旦创建便会自动添加;
 支持Vue3 和 Vue2
使用:
 1.安装 npm install pinia
 2.main.js 引入注册
 import {createPinia} from ‘pinia’
 const store = createPinia()
 app.use(store)
 3.初始化仓库
import { defineStore } from 'pinia'
export const useTestStore = defineStore(Names, {
     state:()=>{
         return {
             current:1
         }
     },
     //类似于computed 可以帮我们去修饰我们的值
     getters:{
     },
     //可以操作异步 和 同步提交state
     actions:{
     }
})
4.组件中使用 State是允许直接修改值的
<template>
     <div>
         <button @click="Add">+</button>
          <div>
             {{Test.current}}
          </div>
     </div>
</template>
<script setup lang='ts'>
import {useTestStore} from './store'
const Test = useTestStore()
const Add = () => {
    Test.current++
}
</script>
//批量修改
const Add = () => {
    Test.$patch({
       current:200,
       age:300
    })
//批量修改函数形式
const Add = () => {
    Test.$patch((state)=>{
       state.current++;
       state.age = 40
    })
}
//通过原始对象修改整个实例:$state您可以通过将store的属性设置为新对象来替换store的整个状态,缺点就是必须修改整个对象的所有属性
const Add = () => {
    Test.$state = {
       current:10,
       age:30
    }    
}
// 通过actions修改,在cations中定义方法,然后直接调用actions中的方法
const Add = () => {
     Test.setCurrent()
}
依赖注入(provide/inject)
在父组件中provide注入数据,在所有子孙组件中都能接收到
// 例如在APP.vue组件中
import {provide} from 'vue'
provide('flag',shuju)   // 这样数据就注入完成了,在所有子孙组件中都能接受到
//在子组件中接受数据
import {inject} from 'vue'
let data = inject('flag')  // 这样就拿到了父组件的数据
//当在子组件中修改数据的话,会影响所有子组件中的这个数据
TSX 类似于react写法
1.安装 npm install @vitejs/plugin-vue-jsx -D
 2。配置vite.config.ts 、 tsconfig.json
自定义Hooks
优秀的开源库:hooks开源库