1.Vue3简介

  • 2020年9月18日,Vue.js发布3.0版本,代号:One Piece(海贼王)
  • 耗时2年多、2600+次提交、30+个RFC、600+次PR、99位贡献者
  • github上的tags地址:https://github.com/vuejs/vue-next/releases/tag/v3.0.0

面临的问题:随着功能的增长,复杂组件的代码变得难以维护,Vue3 就随之而来,TypeScript 使用的越来越多,Vue3就是 TS 写的所以能够更好的支持 TypeScript

在这里介绍就这么简单

vue2 的绝大多数的特性 在 Vue3 都能使用,毕竟 Vue 是渐进式的

响应式原理进行使用 Proxy 实现,v-model 可以传参了等等新特性

2. Vue3带来了什么

1.性能的提升

  • 打包大小减少41%

  • 初次渲染快55%, 更新渲染快133%

  • 内存减少54%

2.源码的升级

  • 使用Proxy代替defineProperty实现响应式

  • 重写虚拟DOM的实现和Tree-Shaking

3.拥抱TypeScript

  • Vue3可以更好的支持TypeScript

4.新的特性

  1. Composition API(组合API)

    • setup配置
    • ref与reactive
    • watch与watchEffect
    • provide与inject
  2. 新的内置组件

    • Fragment
    • Teleport
    • Suspense
  3. 其他改变

    • 新的生命周期钩子
    • data 选项应始终被声明为一个函数
    • 移除keyCode支持作为 v-on 的修饰符

一、创建Vue3.0工程

1.使用 vue-cli 创建

官方文档:https://cli.vuejs.org/zh/guide/creating-a-project.html#vue-create

## 查看@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## 使用可视化UI 创建工程
vue ui

2.使用 vite 创建

官方文档:https://v3.cn.vuejs.org/guide/installation.html#vite

vite官网:https://vitejs.cn

  • 什么是vite?—— 新一代前端构建工具。
  • 优势如下:
    • 开发环境中,无需打包操作,可快速的冷启动。
    • 轻量快速的热重载(HMR)。
    • 真正的按需编译,不再等待整个应用编译完成。
  • 传统构建 与 vite构建对比图

## 创建工程
npm init vite-app <project-name>
## 使用最新版本的 vite
npm init vite@latest
## 进入工程目录
cd <project-name>
## 安装依赖
npm install
## 运行
npm run dev

运行成功页面

  1. 创建一个应用实例

每个 Vue 应用都是通过用 createApp 函数创建一个新的应用实例开始的:

//方式一
const app = Vue.createApp({/* 选项 */
})// 挂载 dom
app.mount('#app')//方式二
createApp(App).mount('#app')

该应用实例是用来在应用中注册“全局”组件的。我们会在后面的指南中详细讨论,简单的例子:

const app = Vue.createApp({})
app.component('SearchInput', SearchInputComponent)
app.directive('focus', FocusDirective)
app.use(LocalePlugin)// 挂载 dom
const vm = app.mount('#app')

应用实例暴露的大多数方法都会返回该同一实例,允许链式:

Vue.createApp({}).component('SearchInput', SearchInputComponent).directive('focus', FocusDirective).use(LocalePlugin).mount('#app')

二、常用 Composition API

官方文档: https://v3.cn.vuejs.org/guide/composition-api-introduction.html

Vue3` 提出了 `Composition API

Vue2.X 我们使用的是 OptionAPI 里面有我们熟悉的 datacomputedmethodswatch

Vue3 中,我们依旧可以使用 OptionAPI当然不建议 和 Vue3 混用

Vue2 中,我们实现一个功能得分到不同的地方,把数据放在 data ,computed 方法放在 methods 里面,分开的太散乱了,几个功能还好,几十个上百个,那就有点…

所以 Vue3 提出了 Composition API ,它可以把 一个逻辑的代码都收集在一起 单独写个hook,然后再引入,这样就不到处分布,显得很乱了

1.拉开序幕的setup

setupComposition API的入口

  1. 理解:Vue3.0中一个新的配置项,值为一个函数。

  2. setup是所有Composition API(组合API)“ 表演的舞台 ”

  3. 组件中所用到的:数据、方法等等,均要配置在setup中。

  4. setup 执行顺序:

    它在beforeCreate之前执行一次beforeCreate这个钩子 的任务就是初始化,在它之前执行,那么 this 就没有被初始化 this = undefined 这样就不能通过 this 来调用方法 和 获取属性

  5. setup函数的两种返回值:

    1. 若返回一个对象,则对象中的属性、方法, 在模板中均可以直接使用。(重点关注!)

      这个对象的属性会与组件中 data 函数返回的对象进行合并,返回的方法和 methods 合并,合并之后直接可以在模板中使用,如果有重名的情况,会使用 setup 返回的属性方法methodsdata 能够拿到 setup 中的方法应该进行了合并,反之 setup 不能拿到它们的属性和方法,因为这个时候 this = undefined

    2. 若返回一个渲染函数:则可以自定义渲染内容。(了解)

  6. 注意点:

    1. 尽量不要与Vue2.x配置混用

      • Vue2.x配置(data、methos、computed…)中可以访问到setup中的属性、方法。
      • 但在setup中不能访问到Vue2.x配置(data、methos、computed…)。
      • 如果有重名, setup优先。
    2. setup不能是一个async函数,因为返回值不再是return的对象, 而是promise, 模板看不到return对象中的属性。(后期也可以返回一个Promise实例,但需要Suspense和异步组件的配合)
    <script>
    import { defineComponent} from 'vue'export default defineComponent({name: 'App',setup() {return {// 这里的属性 和 方法 会合并到 data 函数 和 methods 对象里}},
    })
    </script>
    

2. setup的两个注意点

  • setup执行的时机

    • 在beforeCreate之前执行一次,this是undefined。
  • setup的参数
    • props:值为对象,包含:组件外部传递过来,且组件内部声明接收了的属性。
    • context:上下文对象。包含3个属性 { attrs, slots, emit },这三个属性大家看名字就应该知道是什么吧 分别对应 this.$attrsthis.$slotsthis.$emit
      • attrs: 值为对象,包含:组件外部传递过来,但没有在props配置中声明的属性, 相当于 this.$attrs
      • slots: 收到的插槽内容, 相当于 this.$slots
      • emit: 分发自定义事件的函数, 相当于 this.$emit
setup(){console.log(this) //undefined
}

3.ref函数

  • 作用: 定义一个响应式的数据
  • 语法: const xxx = ref(initValue)
    • 创建一个包含响应式数据的引用对象(reference对象,简称ref对象, RefImpl)
    • JS中操作数据: xxx.value
    • 模板中读取数据: 不需要.value,直接:<div>{{xxx}}</div>
  • 备注:
    • 接收的数据可以是:基本类型、也可以是对象类型。
    • 基本类型的数据:响应式依然是靠Object.defineProperty()getset完成的。
    • 对象类型的数据:内部 “ 求助 ” 了Vue3.0中的一个新函数—— reactive函数。

示例:

//导入
import { ref } from 'vue'setup() {   // 方式一  let number1 = ref(10) let num = 0   // 方式二  let number2 = ref(num)  return {number1,number2} },

4.reactive函数

  • 作用: 定义一个对象类型的响应式数据(基本类型不要用它,要用ref函数)
  • 语法:const 代理对象= reactive(源对象)接收一个对象(或数组),返回一个代理对象(Proxy的实例对象,简称proxy对象)
  • reactive定义的响应式数据是“深层次的”。
  • 内部基于 ES6 的 Proxy 实现,通过代理对象操作源对象内部数据进行操作。

简单写个Vue3响应式例子来说下 Proxy

new Proxy(target, handler)
  • target :要使用 Proxy 包装的目标对象(可以是任何类型的对象,包括原生数组,函数,甚至另一个代理)
  • handler:一个通常以函数作为属性的对象,各属性中的函数分别定义了在执行各种操作时代理 p
// 模拟 Vue data
let data = {  msg: '',   age: '',
}
// 模拟 Vue 的一个实例
// Proxy 第一个
let vm = new Proxy(data, {   // get() 获取值  // target 表示需要代理的对象这里指的就是 data  // key 就是对象的 键  get(target, key) {  return target[key]  },  // 设置值  // newValue 是设置的值   set(target, key, newValue) {     // 也先判断下是否和之前的值一样 节省性能    if (target[key] === newValue) return    // 进行设置值    target[key] = newValue   document.querySelector('#app').textContent = target[key]    },
})

reactive 基础用法

导入,当然写的时候,vscode 会自动帮你引入

import { defineComponent, reactive } from 'vue'

简单使用

setup() {  let obj = reactive({    name: '小浪',    age: 21,  })  return {     obj,  }
}

来看看返回的 Proxy 对象吧

数据都在 target 中,

在模板使用直接 {{obj.name}} 即可

修改直接修改 obj[name] = ‘xxx’

操作代理对象,obj中的数据也会随之变化,同时如果想要在操作数据的时候,界面也要跟着重新更新渲染,那么也是操作代理对象

响应式的数据是深层次的(递归深度响应式)

对于多层嵌套的数据也是响应式的

setup() {  let obj = reactive({   name: '小浪',     age: 21,     phone: {       p_name: '小米',    p_apps: {        app_name: '小米运动',       },      },  })  function upadateName() {    obj.phone.p_apps.app_name = '掘金'   }  console.log(obj)  return {     obj,     upadateName, }
},

5.Vue3.0中的响应式原理

vue2.x的响应式

  • 实现原理:

    • 对象类型:通过Object.defineProperty()对属性的读取、修改进行拦截(数据劫持)。

    • 数组类型:通过重写更新数组的一系列方法来实现拦截。(对数组的变更方法进行了包裹)。

      Object.defineProperty(data, 'count', {get () {}, set () {}
      })
      
  • 存在问题:

    • 新增属性、删除属性, 界面不会更新。
    • 直接通过下标修改数组, 界面不会自动更新。

Vue3.0的响应式

  • 实现原理:

    • 通过Proxy(代理): 拦截对象中任意属性的变化, 包括:属性值的读写、属性的添加、属性的删除等。

    • 通过Reflect(反射): 对源对象的属性进行操作。

    • MDN文档中描述的Proxy与Reflect:

      • Proxy:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Proxy

      • Reflect:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Reflect

        new Proxy(data, {// 拦截读取属性值get (target, prop) {return Reflect.get(target, prop)},// 拦截设置属性值或添加新属性set (target, prop, value) {return Reflect.set(target, prop, value)},// 拦截删除属性deleteProperty (target, prop) {return Reflect.deleteProperty(target, prop)}
        })proxy.name = 'tom'
        

6.reactive对比ref

  • 从定义数据角度对比:

    • ref用来定义:基本类型数据
    • reactive用来定义:对象(或数组)类型数据
    • 备注:ref也可以用来定义对象(或数组)类型数据, 它内部会自动通过reactive转为代理对象
  • 从原理角度对比:
    • ref通过Object.defineProperty()getset来实现响应式(数据劫持)。
    • reactive通过使用Proxy来实现响应式(数据劫持), 并通过Reflect操作源对象内部的数据。
  • 从使用角度对比:
    • ref定义的数据:操作数据需要.value,读取数据时模板中直接读取不需要.value
    • reactive定义的数据:操作数据与读取数据:均不需要.value

7.计算属性与监视

1.computed函数

  • 与Vue2.x中computed配置功能一致

  • 写法

    //首先还是得导入 computed 方法
    import {computed} from 'vue'setup(){...//计算属性——简写let fullName = computed(()=>{return person.firstName + '-' + person.lastName})//计算属性——完整let fullName = computed({get(){return person.firstName + '-' + person.lastName},set(value){const nameArr = value.split('-')person.firstName = nameArr[0]person.lastName = nameArr[1]}})
    }
    

2.watch函数

  • 与Vue2.x中watch配置功能一致

  • 两个小“坑”:

    • 监视reactive定义的响应式数据时:oldValue无法正确获取、强制开启了深度监视(deep配置失效)。
    • 监视reactive定义的响应式数据中某个属性时:deep配置有效。
  • watch(data,handler,object)

  1. data:可以是返回值的 getter 函数,也可以是 ref
  2. handler:回调函数
  3. object:可选配置项 { immediate: true }
  • 引入
import { defineComponent, watch } from 'vue'
//情况一:监视ref定义的响应式数据
watch(sum,(newValue,oldValue)=>{console.log('sum变化了',newValue,oldValue)
},{immediate:true})//情况二:监视多个ref定义的响应式数据
watch([sum,msg],(newValue,oldValue)=>{console.log('sum或msg变化了',newValue,oldValue)
})
/*
sum或msg变化了 (2) [104, '100!!!!!!'] (2) [104, '100!!!!']
sum或msg变化了 (2) [104, '100!!!!!!!!'] (2) [104, '100!!!!!!']
sum或msg变化了 (2) [104, '100!!!!!!!!!!'] (2) [104, '100!!!!!!!!']
sum或msg变化了 (2) [105, '100!!!!!!!!!!'] (2) [104, '100!!!!!!!!!!']
sum或msg变化了 (2) [105, '100!!!!!!!!!!!!'] (2) [105, '100!!!!!!!!!!']
*//* 情况三:监视reactive定义的响应式数据若watch监视的是reactive定义的响应式数据,则无法正确获得oldValue!!若watch监视的是reactive定义的响应式数据,则强制开启了深度监视
*/
watch(person,(newValue,oldValue)=>{console.log('person变化了',newValue,oldValue)
},{immediate:true,deep:false}) //此处的deep配置不再奏效//情况四:监视reactive定义的响应式数据中的某个属性
watch(()=>person.job,(newValue,oldValue)=>{console.log('person的job变化了',newValue,oldValue)
},{immediate:true,deep:true}) //情况五:监视reactive定义的响应式数据中的某些属性
watch([()=>person.job,()=>person.name],(newValue,oldValue)=>{console.log('person的job变化了',newValue,oldValue)
},{immediate:true,deep:true})//特殊情况
watch(()=>person.job,(newValue,oldValue)=>{console.log('person的job变化了',newValue,oldValue)
},{deep:true}) //此处由于监视的是reactive素定义的对象中的某个属性,所以deep配置有效

3.watchEffect函数

  • watch的套路是:既要指明监视的属性,也要指明监视的回调。

  • watchEffect的套路是:不用指明监视哪个属性,监视的回调中用到哪个属性,那就监视哪个属性。

  • watchEffect有点像computed:

    • 但computed注重的计算出来的值(回调函数的返回值),所以必须要写返回值。
    • 而watchEffect更注重的是过程(回调函数的函数体),所以不用写返回值。
    //watchEffect所指定的回调中用到的数据只要发生变化,则直接重新执行回调。
    watchEffect(()=>{const x1 = sum.valueconst x2 = person.ageconsole.log('watchEffect配置的回调执行了')
    })
    

8.生命周期

vue2.x的生命周期
vue3.0的生命周期
  • Vue3.0中可以继续使用Vue2.x中的生命周期钩子,但有有两个被更名:

    • beforeDestroy改名为 beforeUnmount
    • destroyed改名为 unmounted
  • Vue3.0也提供了 Composition API 形式的生命周期钩子,与Vue2.x中钩子对应关系如下:

    Vue2.X 对应 Vue3组合API

    Vue2.X Vue3
    beforeCreate —> setup()
    created —> setup()
    beforeMount —> onBeforeMount
    mounted —> onMounted
    beforeUpdate —> onBeforeUpdate
    updated —> onUpdated
    beforeDestroy —> onBeforeUnmount
    destroyed —> onUnmounted
    activated —> onActivated
    deactivated —> onDeactivated
    errorCaptured —> onErrorCaptured
    onRenderTriggered
    onRenderTracked

    可以看出

    beforeCreatecreated 在Vu3还是能正常使用(再setup 外层还是可以用的,但不推荐),在Vue3我们可以用更好更快的 setup 代替

    on开头的 生命周期需要 通过 import 导入,在 setup 函数中使用

    Vue3 的生命周期 比 Vue2.X 的生命周期快

    举个例子: onBeforeMountbeforeMount 快 其他同理

    还多个两个钩子:

    • onRenderTriggered 跟踪虚拟 DOM 重新渲染时调用
    • onRenderTracked 当虚拟 DOM 重新渲染被触发时调用

9.自定义hook函数

  • 什么是hook?—— 本质是一个函数,把setup函数中使用的Composition API进行了封装。
  • 类似于vue2.x中的mixin。
  • 自定义hook的优势: 复用代码, 让setup中的逻辑更清楚易懂。

示例:

  • usePoint.js
///得到鼠标点的api
import { reactive, onMounted, onBeforeUnmount } from "vue";export default function usePoint(){//响应式数据let point = reactive({x: 0,y: 0});//方法const savePoint = event => {console.log(event.pageX, event.pageY);point.x = event.pageX;point.y = event.pageY;};//生命周期onMounted(() => {window.addEventListener('click', savePoint)});onBeforeUnmount(() => {//在卸载之前取消事件的监听window.removeEventListener('click', savePoint);});return point;
}
  • 使用
<template><h1>当前求和为:{{ sum }}</h1><button @click="sum++">点我加一</button><hr/><h2>当前点击时鼠标的坐标为x:{{ point.x }}, y:{{ point.y }}</h2>
</template><script>
import {ref} from 'vue';
import usePoint from "../hooks/usePoint";
export default {name: 'Demo',setup(){let sum = ref(0);//复用自定义hooksconst point = usePoint();//返回一个对象return {sum,point}},
}
</script><style>
</style>

10.toRef

  • 作用:创建一个 ref 对象,其value值指向另一个对象中的某个属性。

  • 语法:const name = toRef(person,'name')

  • 应用: 要将响应式对象中的某个属性单独提供给外部使用时。

  • 扩展:toRefstoRef功能一致,但可以批量创建多个 ref 对象,语法:toRefs(person)

<template><h4>{{ person }}</h4><h2>姓名:{{ name }}</h2><h2>年龄:{{ age }}</h2><h2>薪资:{{ salary }}K</h2><button @click="name = name + '~'">修改姓名</button><button @click="age++">增长年龄</button><button @click="salary++">增长薪资</button>
</template><script>
import { ref, reactive, toRef, toRefs} from 'vue';
export default {name: 'Demo',setup(){let person = reactive({name: '张三',age: 18,job:{j1:{salary: 20}}});//ref类型的值在模板里使用是不需要.value来取的const name1 = person.name //注意输出字符串,并不是响应式的数据console.log('@@@@@', name1);const name2 = toRef(person,name); //RefImpl 这里的name2与person.name是完全一模一样的(你改这里的name2与你改person.name是一码事),且数据还是响应式的console.log('####', name2);const x = toRefs(person);console.log(x);//返回一个对象(toRef是引用 name就是person.name且为响应式)//toRef处理一个,而toRefs处理一群//大白话:toRef(s)就是方便我们把响应式数据(ref,reactive)展开丢出去,方便在模版中应用return {person,// name: toRef(person, "name"),// age: toRef(person, "age"),// salary: toRef(person.job.j1, "salary")...toRefs(person),salary: toRef(person.job.j1, 'salary')  //toRef可以与toRefs连用,更加方便};//注意千万不能这样写//一旦这样写就与元数据分离了,改name不会引起person.name的变化(因为ref把name值包装成了一个refImpl对象)// return {//   person,//   name: ref(person.name),//   age: ref(person.age),//   salary: ref(person.job.j1.salary)// };}
}
</script>

三、其它 Composition API

1.shallowReactive 与 shallowRef

  • shallowReactive:只处理对象最外层属性的响应式(浅响应式)。
  • shallowRef:只处理基本数据类型的响应式, 不进行对象的响应式处理。
  • 什么时候使用?
    • 如果有一个对象数据,结构比较深, 但变化时只是外层属性变化 ===> shallowReactive。
    • 如果有一个对象数据,后续功能不会修改该对象中的属性,而是生新的对象来替换 ===> shallowRef。
<template><h2>当前的y是:{{ x.y }}</h2><button @click="x = {y : 888}">点我替换x</button><button @click="x.y++">点我y+1</button><hr/><h4>{{ person }}</h4><h2>姓名:{{ name }}</h2><h2>年龄:{{ age }}</h2><h2>薪资:{{ job.j1.salary }}K</h2><button @click="name = name + '~'">修改姓名</button><button @click="age++">增长年龄</button><button @click="job.j1.salary++">增长薪资</button>
</template><script>
import {ref,reactive, toRefs, shallowReactive, shallowRef} from 'vue';
export default {name: 'Demo',setup(){//shallowReactive只考虑对象类型的第一层数据响应式// let person = shallowReactive({//   name: '张三',//   age: 18,//   job:{//     j1:{//       salary: 20//     }//   }// });let person = reactive({name: '张三',age: 18,job:{j1:{salary: 20}}});// let x = ref(0);//传递基本类型来说,ref与shallowRef基本是没什么区别的// let x = shallowRef(0);//但注意对象类型shallowRef不去处理,而ref底层回去借助reactive生成proxy对象(getter/setter)//但注意不管是shallowR还是非shallow, 第一层都是响应式的(不如下面的x依然是响应式数据)let x = shallowRef({ y: 0 });console.log(x);// let x = ref({ y: 0 })return {person,...toRefs(person),x,};}
}
</script>

2.readonly 与 shallowReadonly

  • readonly: 让一个响应式数据变为只读的(深只读)。
  • shallowReadonly:让一个响应式数据变为只读的(浅只读)。
  • 应用场景: 不希望数据(尤其是这个数据是来自与其他组件时)被修改时。
<template><h2>当前求和为:{{ sum }}</h2><button @click="sum++">sum+1</button><hr/><h2>姓名:{{ name }}</h2><h2>年龄:{{ age }}</h2><h2>薪资:{{ job.j1.salary }}K</h2><button @click="name = name + '~'">修改姓名</button><button @click="age++">增长年龄</button><button @click="job.j1.salary++">增长薪资</button>
</template><script>
import {ref,reactive, toRefs, readonly, shallowReadonly} from 'vue';
export default {name: 'Demo',setup(){let sum = ref(0);let person = reactive({name: '张三',age: 18,job:{j1:{salary: 20}}});// person = readonly(person); //此时person里面的属性值都不允许修改//person = shallowReadonly(person); //第一层不能改(name,age), 但j1和salary仍然可以改动// sum = readonly(sum); //同理// sum = shallowReadonly(sum)return {sum,...toRefs(person),};}
}
</script>

3.toRaw 与 markRaw

  • toRaw:

    • 作用:将一个由reactive生成的响应式对象转为普通对象
    • 使用场景:用于读取响应式对象对应的普通对象,对这个普通对象的所有操作,不会引起页面更新。
  • markRaw:
    • 作用:标记一个对象,使其永远不会再成为响应式对象。
    • 应用场景:
      1. 有些值不应被设置为响应式的,例如复杂的第三方类库等。
      2. 当渲染具有不可变数据源的大列表时,跳过响应式转换可以提高性能。
<template><h2>当前求和为:{{ sum }}</h2><button @click="sum++">sum+1</button><hr/><h2>姓名:{{ name }}</h2><h2>年龄:{{ age }}</h2><h2>薪资:{{ job.j1.salary }}K</h2><h3 v-show="person.car">座驾信息:{{ person.car }}</h3><button @click="name = name + '~'">修改姓名</button><button @click="age++">增长年龄</button><button @click="job.j1.salary++">增长薪资</button><button @click="showRawPerson">输出最原始的person</button><button @click="addCar">给人添加一台车</button><button @click="person.car && (person.car.name +='!') ">换车名</button><button @click="changePrice">换价格</button>
</template><script>
import {markRaw, reactive, ref, toRaw, toRefs} from 'vue';export default {name: 'Demo',setup(){let sum = ref(0);let person = reactive({name: '张三',age: 18,job:{j1:{salary: 20}}});//ref reactive(响应式)const showRawPerson = () => {const  p = toRaw(person);// console.log(person); //proxy代理对象 Proxy {....}p.age++; //注意此时页面不会再发生变化了,普普通通的对象不是响应式console.log(p); //原始对象数据  {....}// const sum  = toRaw(sum);// console.log(sum); //undefined //这条路走不通,toRaw只处理reactive对象}const addCar = () => {person.car = markRaw({name: 'benz',price: 40}); //在响应式的对象身上添加任何属性都是响应式的,经过markRaw一包装就变成最原始的数据就不会再做响应}const changePrice = () => {person.car?.price && person.car.price++;console.log(person?.car?.price);}return {sum,person,...toRefs(person),showRawPerson,addCar,changePrice};}
}
</script>

4.customRef

  • 作用:创建一个自定义的 ref,并对其依赖项跟踪和更新触发进行显式控制。

  • 实现防抖效果:

    <template><input type="text" v-model="keyword"><h3>{{keyword}}</h3>
    </template><script>import {ref,customRef} from 'vue'export default {name:'Demo',setup(){// let keyword = ref('hello') //使用Vue准备好的内置ref//自定义一个myReffunction myRef(value,delay){let timer//通过customRef去实现自定义return customRef((track,trigger)=>{return{get(){track() //告诉Vue这个value值是需要被“追踪”的return value},set(newValue){clearTimeout(timer)timer = setTimeout(()=>{value = newValuetrigger() //告诉Vue去更新界面},delay)}}})}let keyword = myRef('hello',500) //使用程序员自定义的refreturn {keyword}}}
    </script>
    

5.provide 与 inject

  • 作用:实现祖与后代组件间通信

  • 套路:父组件有一个 provide 选项来提供数据,后代组件有一个 inject 选项来开始使用这些数据

  • 具体写法:

    1. 祖组件中:

      setup(){......let car = reactive({name:'奔驰',price:'40万'})provide('car',car)......
      }
      
    2. 后代组件中:

      setup(props,context){......const car = inject('car')return {car}......
      }
      

6.响应式数据的判断

  • isRef: 检查一个值是否为一个 ref 对象
  • isReactive: 检查一个对象是否是由 reactive 创建的响应式代理
  • isReadonly: 检查一个对象是否是由 readonly 创建的只读代理
  • isProxy: 检查一个对象是否是由 reactive 或者 readonly 方法创建的代理

四、Composition API 的优势

1.Options API 存在的问题

使用传统OptionsAPI中,新增或者修改一个需求,就需要分别在data,methods,computed里修改 。

2.Composition API 的优势

我们可以更加优雅的组织我们的代码,函数。让相关功能的代码更加有序的组织在一起。

五、新的组件

1.Fragment

  • 在Vue2中: 组件必须有一个根标签
  • 在Vue3中: 组件可以没有根标签, 内部会将多个标签包含在一个Fragment虚拟元素中
  • 好处: 减少标签层级, 减小内存占用

2.Teleport

  • 什么是Teleport?—— Teleport 是一种能够将我们的组件html结构移动到指定位置的技术。

    <teleport to="移动位置"><div v-if="isShow" class="mask"><div class="dialog"><h3>我是一个弹窗</h3><button @click="isShow = false">关闭弹窗</button></div></div>
    </teleport>
    

3.Suspense

  • 等待异步组件时渲染一些额外内容,让应用有更好的用户体验

  • 使用步骤:

    • 异步引入组件

      import {defineAsyncComponent} from 'vue'
      const Child = defineAsyncComponent(()=>import('./components/Child.vue'))
      
    • 使用Suspense包裹组件,并配置好defaultfallback

      <template><div class="app"><h3>我是App组件</h3><Suspense><template v-slot:default><Child/></template><template v-slot:fallback><h3>加载中.....</h3></template></Suspense></div>
      </template>
      

六、其他

1.全局API的转移

  • Vue 2.x 有许多全局 API 和配置。

    • 例如:注册全局组件、注册全局指令等。

      //注册全局组件
      Vue.component('MyButton', {data: () => ({count: 0}),template: '<button @click="count++">Clicked {{ count }} times.</button>'
      })//注册全局指令
      Vue.directive('focus', {inserted: el => el.focus()
      }
      
  • Vue3.0中对这些API做出了调整:

    • 将全局的API,即:Vue.xxx调整到应用实例(app)上

      2.x 全局 API(Vue 3.x 实例 API (app)
      Vue.config.xxxx app.config.xxxx
      Vue.config.productionTip 移除
      Vue.component app.component
      Vue.directive app.directive
      Vue.mixin app.mixin
      Vue.use app.use
      Vue.prototype app.config.globalProperties

2.其他改变

  • data选项应始终被声明为一个函数。

  • 过度类名的更改:

    • Vue2.x写法

      .v-enter,
      .v-leave-to {opacity: 0;
      }
      .v-leave,
      .v-enter-to {opacity: 1;
      }
      
    • Vue3.x写法

      .v-enter-from,
      .v-leave-to {opacity: 0;
      }.v-leave-from,
      .v-enter-to {opacity: 1;
      }
      
  • 移除keyCode作为 v-on 的修饰符,同时也不再支持config.keyCodes

  • 移除v-on.native修饰符

    • 父组件中绑定事件

      <my-componentv-on:close="handleComponentEvent"v-on:click="handleNativeClickEvent"
      />
      
    • 子组件中声明自定义事件

      <script>export default {emits: ['close']}
      </script>
      
  • 移除过滤器(filter)

    过滤器虽然这看起来很方便,但它需要一个自定义语法,打破大括号内表达式是 “只是 JavaScript” 的假设,这不仅有学习成本,而且有实现成本!建议用方法调用或计算属性去替换过滤器。

七、 文件组件<script setup> SFC写法

<script setup> 是在单文件组件 (SFC) 中使用组合式 API 的编译时语法糖。相比于普通的 <script> 语法,它具有更多优势:

  • 更少的样板内容,更简洁的代码。

  • 能够使用纯 TypeScript 声明 props 和抛出事件。

  • 更好的运行时性能 (其模板会被编译成与其同一作用域的渲染函数,没有任何的中间代理)。

  • 更好的 IDE 类型推断性能 (减少语言服务器从代码中抽离类型的工作)。

  • 每个 *.vue 文件最多可同时包含一个 <script setup> 块 (不包括常规的 <script>)

  • 该脚本会被预处理并作为组件的 setup() 函数使用,也就是说它会在每个组件实例中执行。<script setup> 的顶层绑定会自动暴露给模板。更多详情请查看 文档。

1.基本语法

当使用 <script setup> 的时候,任何在 <script setup> 声明的顶层的绑定 (包括变量,函数声明,以及 import 引入的内容) 都能在模板中直接使用:

<script setup>
import { capitalize } from './helpers'
import { ref } from 'vue'
//使用组件
import MyComponent from './MyComponent.vue'// 变量
const msg = 'Hello!'// 函数
function log() {console.log(msg)
}响应式
const count = ref(0)
</script><template><div @click="log">{{ msg }}</div><div>{{ capitalize('hello') }}</div><MyComponent />
</template>

更多用法参考 https://v3.cn.vuejs.org/api/sfc-script-setup.html

还不会 Vue3 ?一篇笔记带你快速入门相关推荐

  1. 四篇文章带你快速入门Jetpck(中)之ViewModel,DataBinding

    文章目录 四篇文章带你快速入门Jetpck(中)之ViewModel,DataBinding Jetpack 官方推荐架构 ViewModel 添加依赖 创建ViewModel 初始化ViewMode ...

  2. 带你快速入门AXI4总线--AXI4-Stream篇(1)----AXI4-Stream总线

    写在前面 随着对XILINX器件使用的深入,发现越来越多的IP都选配了AXI4的接口.这使得只要学会了AXI4总线的使用,基本上就能对XILINX IP的使用做到简单的上手.所以学会AXI4总线,对X ...

  3. 带你快速入门AXI4总线--AXI4-Full篇(3)----XILINX AXI4-Full接口IP源码仿真分析(Master接口)

    写在前面 接slave接口篇,本文继续打包一个AXI4-Full-Master接口的IP,学习下源码,再仿真看看波形. 带你快速入门AXI4总线--AXI4-Full篇(2)----XILINX AX ...

  4. 带你快速入门AXI4总线--AXI4-Full篇(1)----AXI4-Full总线

    写在前面 AXI4系列链接:带你快速入门AXI4总线--汇总篇(直达链接) 1.什么是AXI4-Full? AXI 表示 Advanced eXtensible Interface(高级可扩展接口), ...

  5. 【效率】超详细!手把手带你快速入门 GitHub!

    作者:Peter     编辑:JackTian 来源:公众号「杰哥的IT之旅」 快速入门GitHub GitHub在程序开发领域家喻户晓,现在几乎整个互联网的开发者都将版本管理工具GitHub作为版 ...

  6. 手把手带你快速入门超越GAN的Normalizing Flow

    手把手带你快速入门超越GAN的Normalizing Flow 作者:Aryansh Omray,微软数据科学工程师,Medium技术博主 机器学习领域的一个基本问题就是如何学习复杂数据的表征是机器学 ...

  7. Bootstrap学习笔记01【快速入门、栅格布局】

    Java后端 学习路线 笔记汇总表[黑马程序员] Bootstrap学习笔记01[快速入门.栅格布局][day01] Bootstrap学习笔记02[全局CSS样式.组件和插件.案例_黑马旅游网][d ...

  8. 一文带你快速入门【哈希表】

    最近开始学习哈希表,为此特写一遍文章介绍一下哈希表,带大家快速入门哈希表

  9. 【Nacos 学习笔记】01 - 快速入门

    文章目录 前言 一.下载和单机启动 nacos浏览器控制台界面 二.Java的SDK:nacos-client 1. 导包 2. config 相关 API 3. 服务发现相关 API 三.nacos ...

最新文章

  1. 深度学习如炼丹,你有哪些迷信做法?网友:Random seed=42结果好
  2. java兰顿蚂蚁解题思路_程序员面试金典 - 面试题 16.22. 兰顿蚂蚁(deque模拟)
  3. 椭圆曲线加密算法ECC
  4. 如何使用Fescar保证Dubbo微服务间的一致性
  5. iOS开发常用快捷键
  6. MATLAB 均值估计函数normfit
  7. Python实现的文件夹同步
  8. 2013-2019年百度搜索算法规则解读与应对
  9. iphone上app store切换国家和地区
  10. 三进网吧后,我“被跳槽”了!
  11. ARC120E - 1D Party
  12. STM32 GPS定位
  13. Homebrew 无法下载安装文件的解决方法
  14. 【leetcode】442. Find All Duplicates in an Array(Python C++)
  15. 【CVPR 2021】解决目标检测长尾分布:Adaptive Class Suppression Loss for Long-Tail Object Detection
  16. vue 实现微信登陆 你学会了吗
  17. 【2023最新】MySQL安装配置教程(5.7+8.0)
  18. Java添加水印(图片水印,文字水印)
  19. IEEE Fellow梅涛:计算机视觉的前沿进展与挑战
  20. 企业级指标数据体系建设思路探讨

热门文章

  1. sap模块介绍_SAP会计科目之 自动记账
  2. java 判断是不是图片_java判断是否是图片
  3. smartdeblur有手机版吗_SmartDeblur官方版下载_SmartDeblur2.3 官方版 - Win7旗舰版
  4. FastAdmin 如何部署到虚拟主机
  5. 破解红蜘蛛 (破解红蜘蛛多媒体网络教室) 解除老师控制
  6. 网站推广方法之资源合作推广
  7. 家用计算机维护,家用电脑日常维护技巧
  8. 【HTML】在图标上绘制圆圈数字提示符
  9. mysql MDL锁如何解决_Mysql 中的MDL
  10. html5 css3画八卦图,用纯CSS3绘制乾坤八卦图