vue3快速上手-vue3核心语法-做项目必备

发布时间:2024年01月23日

1.vue3简介

1.1. 【性能的提升】

  • 打包大小减少41%

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

  • 内存减少54%

1.2.【 源码的升级】

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

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

1.3. 【拥抱TypeScript】

  • Vue3可以更好的支持TypeScript

1.4. 【新的特性】

  1. Composition API(组合API):

    • setup

    • refreactive

    • computedwatch

      ......

  2. 新的内置组件:

    • Fragment

    • Teleport

    • Suspense

      ......

  3. 其他改变:

    • 新的生命周期钩子

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

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

      ......

2. vue3核心语法

2.1. 【OptionsAPI 与 CompositionAPI】

  • Vue2API设计是Options(配置)风格的。

  • Vue3API设计是Composition(组合)风格的。

Options API 的弊端

Options类型的 API,数据、方法、计算属性等,是分散在:datamethodscomputed中的,若想新增或者修改一个需求,就需要分别修改:datamethodscomputed,不便于维护和复用。

Composition API 的优势

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

2.2. 【拉开序幕的 setup】

setup 概述

setupVue3中一个新的配置项,值是一个函数,它是 Composition API “表演的舞台,组件中所用到的:数据、方法、计算属性、监视......等等,均配置在setup中。

特点如下:

  • setup函数返回的对象中的内容,可直接在模板中使用。

  • setup中访问thisundefined

  • setup函数会在beforeCreate之前调用,它是“领先”所有钩子执行的。

setup 的返回值

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

  • 若返回一个函数:则可以自定义渲染内容,代码如下:

setup(){
  return ()=> '你好啊!'
}

setup 与 Options API 的关系

  • Vue2 的配置(datamethos......)中可以访问到 setup中的属性、方法。

  • 但在setup不能访问到Vue2的配置(datamethos......)。

  • 如果与Vue2冲突,则setup优先。

setup 语法糖

setup函数有一个语法糖,这个语法糖,可以让我们把setup独立出去,代码如下:

<!-- 下面的写法是setup语法糖 -->
<script setup lang="ts">
  console.log(this) //undefined
  
  // 数据(注意:此时的name、age、tel都不是响应式数据)
  let name = '张三'
  let age = 18
  let tel = '13888888888'

  // 方法
  function changName(){
    name = '李四'//注意:此时这么修改name页面是不变化的
  }
  function changAge(){
    console.log(age)
    age += 1 //注意:此时这么修改age页面是不变化的
  }
  function showTel(){
    alert(tel)
  }
</script>

2.3. 【ref 创建:基本类型的响应式数据】

  • 作用:定义响应式变量。

  • 语法:let xxx = ref(初始值)

  • 返回值:一个RefImpl的实例对象,简称ref对象refref对象的value属性是响应式的

  • 注意点:

    • JS中操作数据需要:xxx.value,但模板中不需要.value,直接使用即可。

    • 对于let name = ref('张三')来说,name不是响应式的,name.value是响应式的。

<script setup>
import { ref,reactive } from 'vue'
let n = ref(10);  //相当于reactive({value:10});
//在JS中.value,在template省略.value

const o1 = ref({id:1})
const lists = ref([
  {id:1,title:'新闻1',content:'1111新闻 新闻 新闻 新闻 新闻'},
  {id:2,title:'新闻2',content:'2222新闻 新闻 新闻 新闻 新闻'},
  {id:3,title:'新闻3',content:'3333新闻 新闻 新闻 新闻 新闻'},
  {id:4,title:'新闻4',content:'4444新闻 新闻 新闻 新闻 新闻'},
  {id:5,title:'5555',content:'55555555555'},
  {id:6,title:'6666',content:'666666666666'}
]);
// function change(){}
const change = ()=>{
  // n.value++;
  // console.log(n)
  o1.value.id+=1;
  // o2.id+=1;
  // console.log(o2.id)
  lists.value.push({id:lists.value.length+1,title:'6666',content:'66666'})
}

//ref的另一种使用:DOM引用
let myInput = ref();
const action = ()=>{
  myInput.value.focus();
  myInput.value.style.color='#f60';
  console.log(myInput)
}
</script>

2.4. 【reactive 创建:对象类型的响应式数据】

  • 作用:定义一个响应式对象(基本类型不要用它,要用ref,否则报错)

  • 语法:let 响应式对象= reactive(源对象)

  • 返回值:一个Proxy的实例对象,简称:响应式对象。

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

<script setup>
import { ref,reactive } from 'vue'
let n = reactive(10); //添加常量出现警告,值不会有响应式特性
//reactive()函数接收一个普通对象,返回一个响应式的数据对象
// const o1 = reactive({id:1});
// const o2 = {id:2}; //非响应式数据
// const lists = reactive([
//   {id:1,title:'新闻1',content:'1111新闻 新闻 新闻 新闻 新闻'},
//   {id:2,title:'新闻2',content:'2222新闻 新闻 新闻 新闻 新闻'},
//   {id:3,title:'新闻3',content:'3333新闻 新闻 新闻 新闻 新闻'},
//   {id:4,title:'新闻4',content:'4444新闻 新闻 新闻 新闻 新闻'},
//   {id:5,title:'5555',content:'55555555555'},
//   {id:6,title:'6666',content:'666666666666'}
// ]);
// function change(){}
const change = ()=>{
  n++;
  console.log(n)
  // o1.id+=1;
  // o2.id+=1;
  // console.log(o2.id)
  // lists.push({id:lists.length+1,title:'6666',content:'66666'})
}

</script>

注意点:reactive定义的响应式数据,如果是从后端请求回来的数据,我们不能直接进行赋值,这样页面被没有进行渲染.

<script setup>
import { ref,reactive } from 'vue'
import Data from './data' //引入外部数据
 let n1 = 10;
 let n2 = ref(10);
 //let n3 = reactive(10);

 let o1 = ref([]);
 let o2 = reactive([]); 
 let o3 = reactive({arr:[]});

const change=()=>{
  // console.log(n1);
  // console.log(n2);
  // console.log(n3);
  // console.log(o1);
  // console.log(o2);
  //将data数据赋值给o1,o2
  //o1.value = Data;
  不用这种方式,避免出现全新的对象赋值等问题
  //o2 = Data; //这种方式不行,将原始对象替换了o2对象
  //解决方式一
  o2.push(...Data);
  //另一种解决方式
  o3.arr = Data;

}
</script>

2.5. 【ref 创建:对象类型的响应式数据】

  • 其实ref接收的数据可以是:基本类型对象类型

  • ref接收的是对象类型,内部其实也是调用了reactive函数。

2.6. 【ref 对比 reactive】

宏观角度看:

  1. ref用来定义:基本类型数据对象类型数据

  2. reactive用来定义:对象类型数据

  • 区别:

  1. ref创建的变量必须使用.value(可以使用volar插件自动添加.value)。

2.reactive重新分配一个新对象,会失去响应式(可以使用Object.assign去整体替换)。

  • 使用原则:

  1. 若需要一个基本类型的响应式数据,必须使用ref

  2. 若需要一个响应式对象,层级不深,refreactive都可以。

  3. 若需要一个响应式对象,且层级较深,推荐使用reactive

2.7. 【toRefs 与 toRef】

  • 作用:将一个响应式对象中的每一个属性,转换为ref对象。

  • 备注:toRefstoRef功能一致,但toRefs可以批量转换。

  • 语法如下:

<script lang="ts" setup name="Person">
  import {ref,reactive,toRefs,toRef} from 'vue'

  // 数据
  let person = reactive({name:'张三', age:18, gender:'男'})
	
  // 通过toRefs将person对象中的n个属性批量取出,且依然保持响应式的能力
  let {name,gender} =  toRefs(person)
	
  // 通过toRef将person对象中的gender属性取出,且依然保持响应式的能力
  let age = toRef(person,'age')

  // 方法
  function changeName(){
    name.value += '~'
  }
  function changeAge(){
    age.value += 1
  }
  function changeGender(){
    gender.value = '女'
  }
</script>

2.8. 【computed】

作用:根据已有数据计算出新数据(和Vue2中的computed作用一致)。

<template>
  <div class="person">
    姓:<input type="text" v-model="firstName"> <br>
    名:<input type="text" v-model="lastName"> <br>
    全名:<span>{{fullName}}</span> <br>
    <button @click="changeFullName">全名改为:li-si</button>
  </div>
</template>

<script setup lang="ts" name="App">
  import {ref,computed} from 'vue'

  let firstName = ref('zhang')
  let lastName = ref('san')

  // 计算属性——只读取,不修改
  /* let fullName = computed(()=>{
    return firstName.value + '-' + lastName.value
  }) */


  // 计算属性——既读取又修改
  let fullName = computed({
    // 读取
    get(){
      return firstName.value + '-' + lastName.value
    },
    // 修改
    set(val){
      console.log('有人修改了fullName',val)
      firstName.value = val.split('-')[0]
      lastName.value = val.split('-')[1]
    }
  })

  function changeFullName(){
    fullName.value = 'li-si'
  } 
</script>

2.9.【watch】

  • 作用:监视数据的变化(和Vue2中的watch作用一致)

  • 特点:Vue3中的watch只能监视以下四种数据

  1. ref定义的数据。

  2. reactive定义的数据。

  3. 函数返回一个值(getter函数)。

  4. 一个包含上述内容的数组。

我们在Vue3中使用watch的时候,通常会遇到以下几种情况:

* 情况一

监视ref定义的【基本类型】数据:直接写数据名即可,监视的是其value值的改变。

<template>
 ?<div class="person">
 ? ?<h1>情况一:监视【ref】定义的【基本类型】数据</h1>
 ? ?<h2>当前求和为:{{sum}}</h2>
 ? ?<button @click="changeSum">点我sum+1</button>
 ?</div>
</template>
?
<script lang="ts" setup name="Person">
 ?import {ref,watch} from 'vue'
 ?// 数据
 ?let sum = ref(0)
 ?// 方法
 ?function changeSum(){
 ? ?sum.value += 1
  }
 ?// 监视,情况一:监视【ref】定义的【基本类型】数据
 ?const stopWatch = watch(sum,(newValue,oldValue)=>{
 ? ?console.log('sum变化了',newValue,oldValue)
 ? ?if(newValue >= 10){
 ? ? ?stopWatch()
 ?  }
  })
</script>

* 情况二

监视ref定义的【对象类型】数据:直接写数据名,监视的是对象的【地址值】,若想监视对象内部的数据,要手动开启深度监视。

注意:

  • 若修改的是ref定义的对象中的属性,newValueoldValue 都是新值,因为它们是同一个对象。

  • 若修改整个ref定义的对象,newValue 是新值, oldValue 是旧值,因为不是同一个对象了。

<template>
 ?<div class="person">
 ? ?<h1>情况二:监视【ref】定义的【对象类型】数据</h1>
 ? ?<h2>姓名:{{ person.name }}</h2>
 ? ?<h2>年龄:{{ person.age }}</h2>
 ? ?<button @click="changeName">修改名字</button>
 ? ?<button @click="changeAge">修改年龄</button>
 ? ?<button @click="changePerson">修改整个人</button>
 ?</div>
</template>
?
<script lang="ts" setup name="Person">
 ?import {ref,watch} from 'vue'
 ?// 数据
 ?let person = ref({
 ? ?name:'张三',
 ? ?age:18
  })
 ?// 方法
 ?function changeName(){
 ? ?person.value.name += '~'
  }
 ?function changeAge(){
 ? ?person.value.age += 1
  }
 ?function changePerson(){
 ? ?person.value = {name:'李四',age:90}
  }
 ?/* 
 ?  监视,情况一:监视【ref】定义的【对象类型】数据,监视的是对象的地址值,若想监视对象内部属性的变化,需要手动开启深度监视
 ?  watch的第一个参数是:被监视的数据
 ?  watch的第二个参数是:监视的回调
 ?  watch的第三个参数是:配置对象(deep、immediate等等.....) 
  */
 ?watch(person,(newValue,oldValue)=>{
 ? ?console.log('person变化了',newValue,oldValue)
  },{deep:true})
 ?
</script>

* 情况三

监视reactive定义的【对象类型】数据,且默认开启了深度监视。

<template>
 ?<div class="person">
 ? ?<h1>情况三:监视【reactive】定义的【对象类型】数据</h1>
 ? ?<h2>姓名:{{ person.name }}</h2>
 ? ?<h2>年龄:{{ person.age }}</h2>
 ? ?<button @click="changeName">修改名字</button>
 ? ?<button @click="changeAge">修改年龄</button>
 ? ?<button @click="changePerson">修改整个人</button>
 ? ?<hr>
 ? ?<h2>测试:{{obj.a.b.c}}</h2>
 ? ?<button @click="test">修改obj.a.b.c</button>
 ?</div>
</template>
?
<script lang="ts" setup name="Person">
 ?import {reactive,watch} from 'vue'
 ?// 数据
 ?let person = reactive({
 ? ?name:'张三',
 ? ?age:18
  })
 ?let obj = reactive({
 ? ?a:{
 ? ? ?b:{
 ? ? ? ?c:666
 ? ?  }
 ?  }
  })
 ?// 方法
 ?function changeName(){
 ? ?person.name += '~'
  }
 ?function changeAge(){
 ? ?person.age += 1
  }
 ?function changePerson(){
 ? ?Object.assign(person,{name:'李四',age:80})
  }
 ?function test(){
 ? ?obj.a.b.c = 888
  }
?
 ?// 监视,情况三:监视【reactive】定义的【对象类型】数据,且默认是开启深度监视的
 ?watch(person,(newValue,oldValue)=>{
 ? ?console.log('person变化了',newValue,oldValue)
  })
 ?watch(obj,(newValue,oldValue)=>{
 ? ?console.log('Obj变化了',newValue,oldValue)
  })
</script>

* 情况四

监视refreactive定义的【对象类型】数据中的某个属性,注意点如下:

  1. 若该属性值不是【对象类型】,需要写成函数形式。

  2. 若该属性值是依然是【对象类型】,可直接编,也可写成函数,建议写成函数。

结论:监视的要是对象里的属性,那么最好写函数式,注意点:若是对象监视的是地址值,需要关注对象内部,需要手动开启深度监视。

<template>
 ?<div class="person">
 ? ?<h1>情况四:监视【ref】或【reactive】定义的【对象类型】数据中的某个属性</h1>
 ? ?<h2>姓名:{{ person.name }}</h2>
 ? ?<h2>年龄:{{ person.age }}</h2>
 ? ?<h2>汽车:{{ person.car.c1 }}、{{ person.car.c2 }}</h2>
 ? ?<button @click="changeName">修改名字</button>
 ? ?<button @click="changeAge">修改年龄</button>
 ? ?<button @click="changeC1">修改第一台车</button>
 ? ?<button @click="changeC2">修改第二台车</button>
 ? ?<button @click="changeCar">修改整个车</button>
 ?</div>
</template>
?
<script lang="ts" setup name="Person">
 ?import {reactive,watch} from 'vue'
?
 ?// 数据
 ?let person = reactive({
 ? ?name:'张三',
 ? ?age:18,
 ? ?car:{
 ? ? ?c1:'奔驰',
 ? ? ?c2:'宝马'
 ?  }
  })
 ?// 方法
 ?function changeName(){
 ? ?person.name += '~'
  }
 ?function changeAge(){
 ? ?person.age += 1
  }
 ?function changeC1(){
 ? ?person.car.c1 = '奥迪'
  }
 ?function changeC2(){
 ? ?person.car.c2 = '大众'
  }
 ?function changeCar(){
 ? ?person.car = {c1:'雅迪',c2:'爱玛'}
  }
?
 ?// 监视,情况四:监视响应式对象中的某个属性,且该属性是基本类型的,要写成函数式
 ?/* watch(()=> person.name,(newValue,oldValue)=>{
 ?  console.log('person.name变化了',newValue,oldValue)
  }) */
?
 ?// 监视,情况四:监视响应式对象中的某个属性,且该属性是对象类型的,可以直接写,也能写函数,更推荐写函数
 ?watch(()=>person.car,(newValue,oldValue)=>{
 ? ?console.log('person.car变化了',newValue,oldValue)
  },{deep:true})
</script>

* 情况五

监视上述的多个数据

<template>
 ?<div class="person">
 ? ?<h1>情况五:监视上述的多个数据</h1>
 ? ?<h2>姓名:{{ person.name }}</h2>
 ? ?<h2>年龄:{{ person.age }}</h2>
 ? ?<h2>汽车:{{ person.car.c1 }}、{{ person.car.c2 }}</h2>
 ? ?<button @click="changeName">修改名字</button>
 ? ?<button @click="changeAge">修改年龄</button>
 ? ?<button @click="changeC1">修改第一台车</button>
 ? ?<button @click="changeC2">修改第二台车</button>
 ? ?<button @click="changeCar">修改整个车</button>
 ?</div>
</template>
?
<script lang="ts" setup name="Person">
 ?import {reactive,watch} from 'vue'
?
 ?// 数据
 ?let person = reactive({
 ? ?name:'张三',
 ? ?age:18,
 ? ?car:{
 ? ? ?c1:'奔驰',
 ? ? ?c2:'宝马'
 ?  }
  })
 ?// 方法
 ?function changeName(){
 ? ?person.name += '~'
  }
 ?function changeAge(){
 ? ?person.age += 1
  }
 ?function changeC1(){
 ? ?person.car.c1 = '奥迪'
  }
 ?function changeC2(){
 ? ?person.car.c2 = '大众'
  }
 ?function changeCar(){
 ? ?person.car = {c1:'雅迪',c2:'爱玛'}
  }
?
 ?// 监视,情况五:监视上述的多个数据
 ?watch([()=>person.name,person.car],(newValue,oldValue)=>{
 ? ?console.log('person.car变化了',newValue,oldValue)
  },{deep:true})
?
</script>

2.10. 【watchEffect】

  • 官网:立即运行一个函数,同时响应式地追踪其依赖,并在依赖更改时重新执行该函数。

  • watch对比watchEffect

    1. 都能监听响应式数据的变化,不同的是监听数据变化的方式不同

    2. watch:要明确指出监视的数据

    3. watchEffect:不用明确指出监视的数据(函数中用到哪些属性,那就监视哪些属性)。

  • 示例代码:

<template>
  <div class="person">
    <h1>需求:水温达到50℃,或水位达到20cm,则联系服务器</h1>
    <h2 id="demo">水温:{{temp}}</h2>
    <h2>水位:{{height}}</h2>
    <button @click="changePrice">水温+1</button>
    <button @click="changeSum">水位+10</button>
  </div>
</template>

<script lang="ts" setup name="Person">
  import {ref,watch,watchEffect} from 'vue'
  // 数据
  let temp = ref(0)
  let height = ref(0)

  // 方法
  function changePrice(){
    temp.value += 10
  }
  function changeSum(){
    height.value += 1
  }

  // 用watch实现,需要明确的指出要监视:temp、height
  watch([temp,height],(value)=>{
    // 从value中获取最新的temp值、height值
    const [newTemp,newHeight] = value
    // 室温达到50℃,或水位达到20cm,立刻联系服务器
    if(newTemp >= 50 || newHeight >= 20){
      console.log('联系服务器')
    }
  })

  // 用watchEffect实现,不用
  const stopWtach = watchEffect(()=>{
    // 室温达到50℃,或水位达到20cm,立刻联系服务器
    if(temp.value >= 50 || height.value >= 20){
      console.log(document.getElementById('demo')?.innerText)
      console.log('联系服务器')
    }
    // 水温达到100,或水位达到50,取消监视
    if(temp.value === 100 || height.value === 50){
      console.log('清理了')
      stopWtach()
    }
  })
</script>

2.11. 【标签的 ref 属性】

作用:用于注册模板引用。

  • 用在普通DOM标签上,获取的是DOM节点。

  • 用在组件标签上,获取的是组件实例对象。

2.12. 【props】

<template>
<div class="person">
<ul>
  <li v-for="item in list" :key="item.id">
     {{item.name}}--{{item.age}}
   </li>
 </ul>
</div>
</template>

<script lang="ts" setup name="Person">
import {defineProps} from 'vue'
import {type PersonInter} from '@/types'

// 第一种写法:仅接收
// const props = defineProps(['list'])

// 第二种写法:接收+限制类型
// defineProps<{list:Persons}>()

// 第三种写法:接收+限制类型+指定默认值+限制必要性
let props = withDefaults(defineProps<{list?:Persons}>(),{
  list:()=>[{id:'asdasg01',name:'小猪佩奇',age:18}]
})
console.log(props)
</script>

2.13. 【生命周期】

  • 概念:Vue组件实例在创建时要经历一系列的初始化步骤,在此过程中Vue会在合适的时机,调用特定的函数,从而让开发者有机会在特定阶段运行自己的代码,这些特定的函数统称为:生命周期钩子

  • 规律:

    生命周期整体分为四个阶段,分别是:创建、挂载、更新、销毁,每个阶段都有两个钩子,一前一后。

  • Vue2的生命周期

    创建阶段:beforeCreatecreated

    挂载阶段:beforeMountmounted

    更新阶段:beforeUpdateupdated

    销毁阶段:beforeDestroydestroyed

  • Vue3的生命周期

    创建阶段:setup

    挂载阶段:onBeforeMountonMounted

    更新阶段:onBeforeUpdateonUpdated

    卸载阶段:onBeforeUnmountonUnmounted

  • 常用的钩子:onMounted(挂载完毕)、onUpdated(更新完毕)、onBeforeUnmount(卸载之前)

2.14. 【自定义hook】

  • 什么是hook?—— 本质是一个函数,把setup函数中使用的Composition API进行了封装,类似于vue2.x中的mixin

  • 自定义hook的优势:复用代码, 让setup中的逻辑更清楚易懂。

4. 路由

4.1. 【对路由的理解】

官网:介绍 | Vue Router

不断持续更新......

文章来源:https://blog.csdn.net/shi15926lei/article/details/135472884
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。