vue3笔记


1.vue3
    1)vue2与vue3的区别
        1. 性能提升
            1)打包大小减少41%
            2)初次渲染快55%, 更新渲染快133%
            3)内存减少54%
            4)使用Proxy代替defineProperty实现数据响应式
            5)重写虚拟DOM的实现和Tree-Shaking
        2. 新增特性
            1)Composition (组合) API
            2)setup            
                ref 和 reactive
                computed 和 watch
                新的生命周期函数
                provide与inject
            3)新组件            
                Fragment - 文档碎片
                Teleport - 瞬移组件的位置
                Suspense - 异步加载组件的loading界面
            4)其它API更新            
                全局API的修改
                将原来的全局API转移到应用对象
                模板语法变化
    2)创建项目    
        1.方式1:脚手架方式
            //安装或者升级
            npm install -g @vue/cli
            //保证 vue cli 版本在 4.5.0 以上
            vue --version
            //创建项目
            vue create my-project
        2.方式2:vite 创建
            npm init vite-app <project-name>
            cd <project-name>
            npm install
            npm run dev
    3)文件介绍
        1.main.ts文件
            // 引入createApp函数,创建对应的应用,产生应用的实例对象
            import { createApp } from 'vue'
            import App from './App.vue'
            // 创建App应用返回对应的实例对象,调用mount方法进行挂载
            createApp(App).mount('#app')
        2.App.vue文件
            <template>
              <!--Vue2中的html模版中必须要有一对根标签,Vue3组件的html模版中可以没有根标签-->
              <img alt="Vue logo" src="./assets/logo.png">
              <!--使用这个子级组件-->
              <HelloWorld msg="Welcome to Your Vue.js + TypeScript App"/>
            </template>
            <script lang="ts">
            // defineComponent函数,目的是定义一个组件,内部可以传入一个配置对象
            import { defineComponent } from 'vue';
            // 引入一个子级组件
            import HelloWorld from './components/HelloWorld.vue';            
            // 暴露出去一个定义好的组件
            export default defineComponent({
              // 当前组件的名字是App
              name: 'App',
              // 注册组件
              components: {
                // 注册一个子级组件
                HelloWorld
              }
            });
            </script>
            <style>
            </style>
    4)Composition (组合) API
        1. setup
            1)使用
                新的option, 所有的组合API函数都在此使用, 只在初始化时执行一次,函数如果返回对象, 对象中的属性或方法, 模板中可以直接使用
                  // setup(props,context){
                  //   const number =10
                  //   return {
                  //     number
                  //   }
                  // }
            2)setup参数
                1.props
                    是一个对象,里面有父级组件向子级组件传递的数据,并且是在子级组件中使用props接收到的所有的属性
                2.context参数属性
                    attrs: 包含没有在props配置中声明的属性的对象, 相当于 this.$attrs
                    slots: 包含所有传入的插槽内容的对象, 相当于 this.$slots
                    emit: 用来分发自定义事件的函数, 相当于 this.$emit                    
            3)细节
                1.setup是在beforeCreate生命周期回调之前就执行了,而且就执行一次,由此可以推断出:setup在执行的时候,当前的组件还没有创建出来,
                    也就意味着:组件实例对象this根本就不能用
                2.setup中的对象中的属性和data函数中的对象中的属性会合并为组件对象的属性,setup中的对象中的方法和methods对象中的方法会合并为组件对象的方法
                     在Vue3中尽量不要混合的使用data和setup及methods和setup,方法和属性如果有重名的话setup优先级更高
                  setup不能是一个async函数: 因为返回值不再是return的对象, 而是promise, 模板看不到return对象中的属性数据
        2.ref
            一般用来定义一个基本类型的响应式数据返回的是一个Ref对象,对象中有一个value属性,如果需要对数据进行操作,需要使用该Ref对象调用value属性的方式进行数据的操作
            html模版中是不需要使用.value属性的写法
            1)数据的响应式处理
                // 也可以用ref来处理对象/数组, 内部会自动将对象/数组转换为reactive的代理对象
                import { ref } from 'vue';
                const count = ref(0)
                // 方法
                function updateCount(){
                  // 报错的原因:count是一个Ref对象,对象是不能进行++的操作
                  // count++
                  count.value++
                }
                <h3>{{ count }}</h3>
            2)获取元素
                <input type="text" ref="inputRef" />
                const inputRef = ref<HTMLElement | null>(null)
                onMounted(() => {
                  inputRef.value && inputRef.value.focus() // 自动获取焦点
                })
        3.reactive
            定义多个响应式数据,内部基于 ES6 的 Proxy 实现,通过代理对象操作源对象内部数据都是响应式的
            const obj = {
              name: '小明',
              age: 20,
              wife: {
                name: '小甜甜',
                age: 18,
                cars: ['奔驰', '宝马', '奥迪'],
              },
            }
            // 通过改变user属性才有响应式,直接改变obj属性没有响应式
            // user为代理对象,obj是目标对象
            // reactive<any>(obj)或const obj: any = {}方式增加类型限制
            // 通过user点的方式去炒作属性才有响应式,如果user拆包后再去使用属性,则属性不具备响应式
            const user = reactive(obj)
        4.computed计算属性
            import {computed} from 'vue'
            // 计算属性的函数中如果只传入一个回调函数,表示的是get
            // fullName1是个ref类型,通过fullName1.value操作值
            // fullName1需要在setup中返回
            const fullName1 = computed(() => {
              return user.firstName + '_' + user.lastName
            })
            const fullName2 = computed({
              get() {
                return user.firstName + '_' + user.lastName
              },
              set(val: string) {
                const names = val.split('_')
                user.firstName = names[0]
                user.lastName = names[1]
              },
            })
        5.watch和watchEffect
            import {watch,watchEffect} from 'vue'
            watch(
              //参数1:监视的属性,参数2:回调,参数3:配置对象,immediate默认会执行一次watch,deep 深度监视
              user,
              (newVal) => {
                fullName3.value = firstName + '_' + lastName
              },
              { immediate: true, deep: true }
            )
            // watch可以监听多个数据,当我们使用watch监视非响应式的数据(user是响应式数据,user.firstName不是)的时候,代码需要改成回调
            watch([()=>user.firstName, ()=>user.lastName,fullName3], () => {
              // 这里的代码就没有执行,fullName3是响应式的数据,但是,user.firstName,user.lastName不是响应式的数据
              console.log('====')
            })
            //组件挂载和响应式数据方式变化都会执行回调
            watchEffect(() => {
              const names = fullName3.value.split('_')
              user.firstName = names[0]
              user.lastName = names[1]
            })
        6.toRefs
            可以把一个响应式对象转换成普通对象,该普通对象的每个属性都是一个 ref,相当于是让reactive包装后的对象的每个属性都具有响应式
            const state = reactive({
              name: '自来也',
              age: 47,
            })
             const { name, age } = toRefs(state)
             setInterval(() => {
              name.value += '==='
            }, 1000)
        7.其它Composition (组合) API
            1)shallowReactive和shallowRef
                shallowReactive : 只处理了对象内最外层属性的响应式(也就是浅响应式)
                shallowRef: 只处理了value的响应式, 不进行对象的reactive处理
                import {shallowReactive,shallowRef} from 'vue'
                // 改变m2.car.name没有响应式效果
                const m2 = shallowReactive({
                  name: '鸣人',
                  age: 20,
                  car: {
                    name: '奔驰',
                    color: 'red',
                  },
                })
                //改变m4.value.name没有响应式效果,改变m4.value有响应式效果
                const m4 = shallowRef({
                  name: '鸣人',
                  age: 20,
                  car: {
                    name: '奔驰',
                    color: 'red',
                  },
                })
            2)readonly和shallowReadonly
                import {reactive, readonly, shallowReadonly } from 'vue'
                深度只读,浅度只读
                const state = reactive({
                  name: '佐助',
                  age: 20,
                  car: {
                    name: '奔驰',
                    color: 'yellow',
                  },
                })
                //不能改state2.name和state2.car.name的值
                const state2 = readonly(state)
                //不能改state2.name的值,可以改state2.car.name的值
                const state2 = shallowReadonly(state)
            3)toRaw和markRaw
                toRaw:将一个响应式对象临时变成非响应式对象
                markRaw:将一个响应式对象变成非响应式对象,后面不能才变成响应式对象
                import { defineComponent, markRaw, reactive, toRaw } from 'vue'
                const state = reactive<UserInfo>({
                  name: '小明',
                  age: 20,
                })
                const testToRaw = () => {
                  // 把代理对象变成了普通对象了,数据变化,界面不变化
                  const user = toRaw(state)
                  user.name += '=='
                  console.log('哈哈,我好帅哦')
                }
                const testMarkRaw = () => {
                  const likes = ['吃', '喝']
                  // markRaw标记的对象数据,从此以后都不能再成为代理对象了,界面不变化
                  state.likes = markRaw(likes)
                  setInterval(() => {
                    if (state.likes) {
                      state.likes[0] += '='
                    }
                  }, 1000)
                }
            4)toRef
                为源响应式对象上的某个属性创建一个 ref对象, 二者内部操作的是同一个数据值, 更新时二者是同步的
                区别ref: 拷贝了一份新的数据值单独操作, 更新时相互不影响
                import { defineComponent, reactive, toRef, ref } from 'vue'
                const state = reactive({
                  age: 5,
                  money: 100,
                })
                // 把响应式数据state对象中的某个属性age变成了ref对象了,age改变会影响state.age
                const age = toRef(state, 'age')
                // 把响应式对象中的某个属性使用ref进行包装,变成了一个ref对象,age改变不会影响state.age
                const money = ref(state.money)
            5)customRef
                创建一个自定义的 ref,并对其依赖项跟踪和更新触发进行显式控制
                import { customRef, defineComponent, ref } from 'vue'
                // 自定义hook防抖的函数
                function useDebouncedRef<T>(value: T, delay = 200) {
                  let timeOutId: number
                  return customRef((track, trigger) => {
                    return {
                      // 取值走这个逻辑
                      get() {
                        // 告诉Vue追踪数据
                        track()
                        return value
                      },
                      // 设置值走这个逻辑
                      set(newValue: T) {
                        clearTimeout(timeOutId)
                        timeOutId = setTimeout(() => {
                          value = newValue
                          // 告诉Vue更新界面
                          trigger()
                        }, delay)
                      },
                    }
                  })
                }
            6)provide 与 inject
                组件跨层级通信
                import { defineComponent, provide,inject, ref } from 'vue'
                //父组件
                const color = ref('red')
                // 提供数据
                provide('color',color)
                // 子孙组件,注入的操作
                const color = inject('color')
            7)响应式数据的判断
                  // isRef: 检查一个值是否为一个 ref 对象
                  console.log(isRef(ref({}))) //true
                  // isReactive: 检查一个对象是否是由 reactive 创建的响应式代理
                  console.log(isReactive(reactive({}))) //true
                  // isReadonly: 检查一个对象是否是由 readonly 创建的只读代理
                  console.log(isReadonly(readonly({}))) //true
                  // isProxy: 检查一个对象是否是由 reactive 或者 readonly 方法创建的代理
                  console.log(isProxy(readonly({}))) //true
                  console.log(isProxy(reactive({}))) //true
            8)Fragment和Teleport组件
                在Vue3中: 组件可以没有根标签, 内部会将多个标签包含在一个Fragment虚拟元素中
                //Teleport 提供了一种干净的方法, 让组件的html在父组件界面外的特定标签(很可能是body)下插入显示
                <Teleport to="body">
                  <div>
                  </div>
                </Teleport>
            9)Suspense组件
                //加载异步组件的空白时间会加载Loading.....的内容
                <Suspense>
                    <template #default>
                      <!--异步组件-->
                      <AsyncAddress />
                    </template>
                    <template v-slot:fallback>
                      <!--loading的内容-->
                      <h2>Loading.....</h2>
                    </template>
                  </Suspense>
            10)路由加载
                import { defineAsyncComponent } from 'vue'
                // Vue2中的动态引入组件的写法:(在Vue3中这种写法不行)
                // const AsyncComponent = () => import('./AsyncComponent.vue')
                // Vue3中的动态引入组件的写法
                // const AsyncComponent = defineAsyncComponent(
                //   () => import('./AsyncComponent.vue')
                // )
    5)vue3响应式原理
        通过Proxy和Reflect实现响应式,可以通过改变数组索引实现响应式
        // 目标对象
        const user = {
          name: '佐助',
          age: 20,
          wife: {
            name: '小樱',
            age: 19
          }
        }
        // 把目标对象变成代理对象
        // 参数1:user---->target目标对象
        // 参数2:handler---->处理器对象,用来监视数据,及数据的操作
        const proxyUser = new Proxy(user, {
          // 获取目标对象的某个属性值
          get(target, prop) {
            console.log('get方法调用了')
            return Reflect.get(target, prop)
          },
          // 修改目标对象的属性值/为目标对象添加新的属性
          set(target, prop, val) {
            console.log('set方法调用了')
            return Reflect.set(target, prop, val)
          },
          // 删除目标对象上的某个属性
          deleteProperty(target, prop) {
            console.log('delete方法调用了')
            return Reflect.deleteProperty(target,prop)
          }
        })
    6)生命周期函数
        1.vue2
            vue2.x中的beforeDestroy和destroyed这两个生命周期回调已经在vue3中改名为beforeUnmount和unmounted,在setup方法外面使用
        2.vue3
            //在setup里面使用,beforeCreate和created被setup取代,相同的生命周期函数setup比较先执行
            import {onBeforeMount,onMounted,onBeforeUpdate,onUpdated,onBeforeUnmount,onUnmounted } from 'vue'
            onBeforeMount(()=>{
              console.log('3.0中的onBeforeMount')
            })


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值