vue3学习小结

2022年7月14日 442点热度 0人点赞 0条评论

一、简介

     2020年9月18日,Vue.js发布3.0版本
     代号:One Piece(海贼王) https://v3.cn.vuejs.org/


二、快速开始

  • 通过 CDN:

      <script src="https://unpkg.com/vue@next"></script>
  • 通过脚手架 Vitenpm init vite hello-vue3 # 或 yarn create vite hello-vue3

图片

// 创建工程    npm init vite-app v3_demo// 进入工程目录    cd v3_demo// 安装依赖    npm install (or 'yarn')// 运行    npm run dev (or 'yarn dev')
  • 通过脚手架 vue-cli vue create hello-vue3

图片

// vue-cli 需要v4.5.0 以上     vue -V     @vue/cli 5.0.6    npm install -g @vue/cli ( cli版本安装or升级 )// 创建工程    vue create v3_demo// 选择 vue 3 preset    cd v3_demo    npm run serve (or 'yarn serve')

三、vite 与 webpack比较

  • webpack 资源先打包 服务器路由 - 模块 - 打包 - 准备服务器

    • 图片

  • vite 冷启动 热重载(HMR) 按需编译准备服务器 - 入口 - 路由 - 模块

    • 图片

四、VUE 挂载APP

//引入的不是vue构造函数 而是createApp是一个工厂函数import { createApp } from 'vue'import App from './App.vue'
// 创建应用实例对象-app (类似v2中的vm 但 app比vm 更轻)const app = createApp(App)
//挂载app.mount('#app')

//并不兼容 new vue v2 语法const vm = new Vue({ render: (h) => h(app)})vm.$mount('app')

app

图片


五、Template Fragment

  • v2 组件必须有一个根标签

  • v3 可以没有根标签了

 ⭐ 减少标签层级 减少内存占用

<template>    <div>111</div>    <div>222</div></template>

通过vue开发者工具可以看出来 是vue内部会将多个标签包含在Fragment的虚拟元素中不参与渲染图片


六、
Composition API (组合式 API 概念)

  • Option API 使用 (datacomputedmethodswatch) 组件开始变得更大时 导致组件难以阅读和理解

o图片图片

  • Composition API 利用Hook函数组织我们的代码,函数。让相关功能的代码更加有序的组织在一起

o图片


七、
常用的Composition API

1.setup

  • setup 组合式 API 的入口

oVue3.0中一个新的配置项,值为一个函数

o组件中所用到的:数据方法、计算属性、watch监听、生命周期,均要配置在setup

osetup 返回值

§一个对象

§一个渲染函数 (了解即可)

  • 执行时机

obeforeCreate之前执行一次,thisundefined

  • 注意点

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

oVue2.x配置(data、methos、computed...)中可以访问到setup中的属性、方法。

o但在setup中不能访问到Vue2.x配置(data、methos、computed...)。

o如果有重名, setup优先。

osetup不能是一个async函数,因为返回值不再是对象, 而是promise, 模板看不到return对象中的属性。(后期也可以返回一个Promise实例,但需要Suspense和异步组件的配合)

<template>  <div>{{ p.name }}</div>  <div>{{ p.age }}</div>  <div @click="getName">点击改变名称</div></template>
<script>//import { h } from "vue";export default { name: "App", setup() { let p = { name: "cy", age: "18", }; function getName() { alert(p.name) } return { p, getName }; // return ()=> h('div','cyy') 渲染函数 },};</script>

2.Props / Emits    

  •  Vue 3 现在提供一个 emits 选项,和现有的 props 选项类似

  • 这个选项可以用来定义一个组件可以向其父组件触发的事件。

     <template>  <div>    <p>{{ text }}</p>    <button v-on:click="$emit('accepted')">OK</button>  </div></template><script>  //2.0  export default {    props: ['text']  }</script>
  • 3.0 和 prop 类似,现在可以通过 emits 选项来定义组件可触发的事件

  • 该选项可以接收一个对象,该对象允许定义传入事件参数的验证器,和 props 定义里的验证器类似。

    <template>  <div>    <p>{{ text }}</p>    <button v-on:click="$emit('accepted')">OK</button>  </div></template><script>  //3.0  export default {    props: ['text'],    emits: ['accepted']  }</script>

3.Ref 函数

  • 定义一个响应式的数据

  • const xxx = ref(initValue)

o创建一个包含响应式数据的引用对象(reference对象,简称ref对象)

oJS中操作数据:xxx.value

o模板中读取数据: 不需要.value,直接:{{xxx}}

<template>  <h1>美女的信息</h1>  <h2>姓名:{{ name }}</h2>  <h2>年龄:{{ age }}</h2>  <h2>职业: {{ job.hobby }}</h2>  <h2>工资:{{ job.address }}</h2>  <button @click="changeInfo">十年后的信息</button></template>
<script>import { ref } from "vue";export default { name: "App", setup() { let name = ref("cy"); let age = ref(18); let job = ref({ hobby: "吃", address: "北京", }); function changeInfo() { name.value = "十年后的cy"; age.value += 10; job.value.hobby = "玩"; job.value.address = "上海"; } console.log(name, age, job); return { name, age, job, changeInfo, }; },};</script>

图片图片

  • 分析输出

o接收的数据可以是:基本类型、也可以是对象类型。

o基本类型的数据:ref会返回一个RefImpl的实例对象,响应式依靠的是类上的getter与setter完成的。

o对象类型的数据:value是一个proxy对象 ;内部 “ 求助 ” 了Vue3.0中的一个新函数—— reactive函数。

图片


4.reactive函数

  • 定义一个对象类型的响应式数据(基本类型不要用它,要用ref函数)

  • const 代理对象= reactive(源对象)接收一个对象(或数组),返回一个proxy对象

  • reactive定义的响应式数据是“深层次的”。

  • 内部基于 ES6 的 Proxy 实现,通过代理对象操作源对象内部数据进行操作。

<template>  <h2>姓名:{{ cy.name }}</h2>  <h2>年龄:{{ cy.age }}</h2>  <h2>爱好:{{ cy.hobby }}</h2>  <h3>测试数据:{{ cy.job.a.b.c }}</h3>  <button @click="changeInfo">修改信息</button></template>
<script>import { reactive } from "vue";export default { name: "App", setup() { // 数据 let cy = reactive({ name: "cy", age: 8, hobby: ["吃", "学习", "看书"], job: { a: { b: { c: 123, }, }, }, }); function changeInfo() { cy.name = "cyy"; cy.age = 18; cy.job.a.b.c = 456; // 直接通过数组下标修改,可以触发响应式 cy.hobby[0] = "吃吃吃"; } return { cy, changeInfo, }; },};</script>

图片图片

  • 分析输出

o接收的数据 一个对象包裹

o使用的时候 不需要.value;修改下标也可以触发响应式

oreactive 包裹的对象是一个proxy代理对象

5.Reactive 与 Ref 对比

  • 定义

oref 基本数据类型

oreactive 对象(数组)数据类型

oref也可以定义复杂数据类型,内部自动通过reactive转为代理对象

  • 原理

oref obj.defineproperty() ;通过getter与setter数据劫持

oreactive proxy数据劫持。通过Reflect操作内部数据

  • 使用

oref 读取操作需要.value

oreactive 直接读取 不需要.value

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

 Vue2.x的响应式

  • 实现原理

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

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

  • 存在问题

o新增属性、删除属性, 界面不会更新。

o直接通过下标修改数组, 界面不会自动更新

  • 解决方案

o使用官方提供的Vue.setVue.delete或者vm.$setvm.$delete API

let p = {    name: 'cy',    age: '18'}let p_ = {}Object.defineProperty(p_, 'name', {   configurable: true,  //可配置   get() {      return p.name   },   set(value) {      p.name = value   }})Object.defineProperty(p_, 'age', {   configurable: true,   get() {      return p.age   },   set(value) {      p.age = value   }})

proxy的响应式

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

    let p = {    name: 'cy',    age: '18'}const p_ = new Proxy(p, {get(target, prop) {   console.log('get');   return target[prop]  },  //修改、追加set(target, prop, value) {   console.log('set');   target[prop] = value},deleteProperty(target, prop) {   console.log('delete');   return delete target[prop]  },});

vue3.0的响应式

  • v3 底层 window.Reflect 反射 (set get deleteProperty)

ECMA ==== >Reflect

let p = {    name: 'cy',    age: '18'}const p_ = new Proxy(p, {    get(target, prop) {        console.log('get');        return Reflect.get(target, prop)    },    //修改、追加    set(target, prop, value) {        console.log('set');        return Reflect.set(target, prop)    },    deleteProperty(target, prop) {        console.log('delete');        return Reflect.deleteProperty(target, prop)    },});

7.Computend 计算属性

  • computed 函数

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

o图片

<template>  <input type="text" v-model="person.name" />  <input type="text" v-model="person.age" />  <h2>计算属性:{{ fullName }}</h2></template>
<script>import { reactive, computed } from "vue";export default { setup() { const person = reactive({ name: "cy", age: "18", }); //简写 let fullName = computed(() => { return person.name + "-" + person.age; }); //完整 // let fullName = computed({ // get() { // return person.firstName + "-" + person.lastName; // }, // set(value) { // const nameArr = value.split("-"); // person.firstName = nameArr[0]; // person.lastName = nameArr[1]; // }, // }); return { person, fullName }; },};</script>

8.Watch 监听

  • 参数

o ref 一个 {sum}

//监视ref定义的响应式数据watch(sum,(newValue,oldValue)=>{    console.log('sum变化了',newValue,oldValue)},{immediate:true})
//用ref定义了一个对象watch(person.value,(newValue,oldValue)=>{ console.log('person变化了',newValue,oldValue)})//ref 监听对象watch(person,(newValue,oldValue)=>{ console.log('person变化了',newValue,oldValue)},{deep: true})

o ref 多个 {[sum,sum1]}

watch([sum,msg],(newValue,oldValue)=>{    console.log('sum或msg变化了',newValue,oldValue)})

o reactive 全部 {person}

§若watch监视的是reactive定义的响应式数据,则无法正确获得oldValue!!

§若watch监视的是reactive定义的响应式数据,则强制开启了深度监视

watch(person,(newValue,oldValue)=>{    console.log('person变化了',newValue,oldValue)},{immediate:true,deep:false}) //此处的deep配置不再奏效

o reactive 单个 {()=>{person.name}}

watch(()=>person.job,(newValue,oldValue)=>{    console.log('person的job变化了',newValue,oldValue)},{immediate:true,deep:true})

o reactive 多个个 {[()=>{person.name},()=>{person.age}]}

watch([()=>person.job,()=>person.name],(newValue,oldValue)=>{    console.log('person的job变化了',newValue,oldValue)},{immediate:true,deep:true})

o 特殊 深层obj 开启deep监听

watch(()=>person.job,(newValue,oldValue)=>{    console.log('person的job变化了',newValue,oldValue)},{deep:true})

  •  目前存在问题

o监视reactive定义的响应式数据时:oldValue无法正确获取、强制开启了深度监视(deep失效)

o监视reactive定义的响应式数据中某个属性时:deep配置有效。


9.watchEffect函数

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

  • 类似computed属性

watchEffect(() => {  console.log("watchEffect");  console.log(p.test);});

10. watchEffect 与 Computend

  • 都是依赖性

  •  watchEffect注重过程(函数体),不用写返回值。

  • computed注重计算出来的值(返回值),必须需要返回值

11.生命周期

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

beforeDestroy改名为 beforeUnmount

destroyed改名为 unmounted

 图片

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

obeforeCreate===>setup()

ocreated=======>setup()

obeforeMount ===>onBeforeMount

omounted=======>onMounted

obeforeUpdate===>onBeforeUpdate

oupdated =======>onUpdated

obeforeUnmount ==>onBeforeUnmount

ounmounted =====>onUnmounted

  • ⭐ 组合式API的钩子比配置项早


12.Hook函数

  • hook 是个函数

  • 本质一个函数 把setup中的组合api拆分出去

  • 类似Vue2.0中的mixin

import { reactive, onMounted, onBeforeUnmount } from "vue";export default function() {  //实现鼠标“打点”相关的数据  let point = reactive({    x: 0,    y: 0,  });
//实现鼠标“打点”相关的方法 function savePoint(event) { point.x = event.pageX; point.y = event.pageY; console.log(event.pageX, event.pageY); }
//实现鼠标“打点”相关的生命周期钩子 onMounted(() => { window.addEventListener("click", savePoint); });
onBeforeUnmount(() => { window.removeEventListener("click", savePoint); });
return point;}
<template>  <h2>我是HelloWorld组件</h2>  <h2>当前点击时鼠标的坐标为:x:{{point.x}},y:{{point.y}}</h2></template>
<script> //引入Hook 函数 import usePoint from '../hooks/usePoint' export default { name:'HelloWorld', setup(){ const point = usePoint() return {point} } }</script>

13.toRef / toRefs

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

  • const name = toRef(person,'name')

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

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

优化一下我们一开始的使用

<template>  <input type="text" v-model="name" />  <input type="text" v-model="age" />  <p></p>  <br />  <span v-for="item in arr" :key="item">{{ item }}</span>  <p>{{ obj.a }}</p>  <p>{{ obj.b.b1 }}</p></template>
<script>import { reactive, toRefs, toRef } from "vue";export default { setup() { const person = reactive({ name: "cy", age: "18", arr: ["?", "?", "?", "?"], obj: { a: "obj.a", b: { b1: "obj.b.b1 ", }, }, }); //return { //person, // name:toRef(person,'name') //引用一个 维持通话 // ... //} //更优美的使用数据 return { person, ...toRefs(person) }; },};</script>

通过log可以看出来 toRefs 把 对象objectRefTmpl对象

基本类型ref对象、对象类型 proxy代理。

图片


14.全局API变动

图片


15.v-if 与 v-for 的优先级对比

  • 2.x 版本中在一个元素上同时使用 v-ifv-for 时,v-for 会优先作用。

  • 3.x 版本中 v-if 总是优先于 v-for 生效。

八、新的组件

1.Fragment

  • Vue2中: 组件必须有一个根标签

  • Vue3中: 组件可以没有根标签, 内部会将多个标签包含在一个Fragment虚拟元素中

  • 好处: 减少标签层级, 减小内存占用

2.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

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

  • 使用步骤:

o异步引入组件

import {defineAsyncComponent} from 'vue'const Child = defineAsyncComponent(()=>import('./components/Child.vue'))

  • 使用Suspense包裹组件,并配置好defaultfallback

odefault:就是组件要显示的内容

ofallback:就是组件没加载完全的“备胎”

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

九、被移除的 API

  • keyCode作为v-on修饰符的支持

  • $on、$off 和 $once 实例方法

  • 过滤器 (filter)

  • 内联模板 attribute

  • $children实例 property

  • propsData选项

  • $destroy 实例方法。用户不应再手动管理单个 Vue 组件的生命周期。

  • 全局函数 set 和 delete 以及实例方法 $set 和 $delete。基于代理的变化检测已经不再需要它们了。

参考

  • Vue3官方文档 https://v3.cn.vuejs.org/

  • 尚硅谷Vue3视频 https://www.bilibili.com/video/BV1Zy4y1K7SH

  • 掘金 https://juejin.cn/post/7005140118960865317/#heading-40

43710vue3学习小结

这个人很懒,什么都没留下

文章评论