Vue3 基础记录

Vue3

创建

基于vue-cli

bash 复制代码
## 查看@vue/cli版本,确保@vue/cli版本在4.5.0以上
vue --version

## 安装或者升级你的@vue/cli 
npm install -g @vue/cli

## 执行创建命令
vue create vue_test

##  随后选择3.x
##  Choose a version of Vue.js that you want to start the project with (Use arrow keys)
##  > 3.x
##    2.x

## 启动
cd vue_test
npm run serve

基于Vite

bash 复制代码
## 1.创建命令
npm create vue@latest

## 2.具体配置
## 配置项目名称
√ Project name: vue3_test
## 是否添加TypeScript支持
√ Add TypeScript?  Yes
## 是否添加JSX支持
√ Add JSX Support?  No
## 是否添加路由环境
√ Add Vue Router for Single Page Application development?  No
## 是否添加pinia环境
√ Add Pinia for state management?  No
## 是否添加单元测试
√ Add Vitest for Unit Testing?  No
## 是否添加端到端测试方案
√ Add an End-to-End Testing Solution? >> No
## 是否添加ESLint语法检查
√ Add ESLint for code quality?  Yes
## 是否添加Prettiert代码格式化
√ Add Prettier for code formatting?  No

文件结构

main.js

bash 复制代码
import { createApp } from 'vue'
import App from './App.vue'

createApp(App).mount('#app')

createApp(App) 返回的变量就是轻量的vm,并且很多方法不带$

vue3中template中,不用再写根div了

setup

bash 复制代码
<template>
  <div>
    <h2>hhh</h2>
    <button @click="sayHello">点击</button>
  </div>
</template>

<script>

export default {
  name: 'App',
  components: {
  },
  setup() {
    let name = 'jjking';

    function sayHello() {
      alert('Hello' + name);
    }

    return {  
      name,sayHello
    }
  }
}
</script>

<style></style>

setup函数返回的对象中的内容,可以在模版中直接使用

setup中this访问是undefined

setup函数会在beforeCreate之前调用

setup返回值,如果是一个渲染函数,则可以自定义渲染内容

这个东西,就是vue2中的main.js中的那个渲染函数

bash 复制代码
<template>
  <div>
    <h2>hhh</h2>
    <button @click="sayHello">点击</button>
  </div>
</template>

<script>
import { h } from 'vue';


export default {
  name: 'App',
  components: {
  },
  setup() {
    let name = 'jjking';

    function sayHello() {
      alert('Hello' + name);
    }

    // return {  
    //   name,sayHello
    // }

    return () => h('h1','jjking'); 
  }
}
</script>

<style></style>

不管你写什么,都会渲染成h1

  • setup的参数
    • props:值为对象,包含:组件外部传递过来,且组件内部声明接收了的属性。
    • context:上下文对象
      • attrs: 值为对象,包含:组件外部传递过来,但没有在props配置中声明的属性, 相当于 this.$attrs
      • slots: 收到的插槽内容, 相当于 this.$slots
      • emit: 分发自定义事件的函数, 相当于 this.$emit

ref

基本数据类型

使用ref包裹的返回的对象

是一个响应式的对象,如果要修改ref中的对象,需要修改value,而不是直接改

并且,看这个对象,是在原型对象中有get,set方法,有点类似于vue2的_data里边的数据

模版字符串{{}}里边不用.value的原因是,模版字符串会自动加上.value

bash 复制代码
<template>
  <div>
    <h2>{{name}}</h2>
    <button @click="change">点击change</button>
  </div>
</template>
<script>
import { ref } from 'vue';

export default {
  name: 'App',
  components: {
  },
  setup() {
    let name = ref('jjking');
    function change() {
      console.log(name);
      name.value = '改变后';
    }
    return {  
      name,change
    }
  }
}
</script>

对象数据类型

bash 复制代码
  setup() {
    let job = ref({
      type:'前端工程师',
      salary: 30
    })

    function changeSalary() {
      console.log(job);
      job.value.salary = 40;
    }

    return {  
      name,job,changeSalary
    }
  }

我们打印可以看到他实际上是Proxy对象,他的响应式是借助了Vue3中的 新函数,reactive函数

我们更改的话,就如上代码

reactive

一般用于对象和数组,基本类型用ref,不然报错

返回值是Proxy对象,且reactive定义的是深层次的响应式对象

注意,如果reavtive重新分配一个新对象,会失去响应式,必须用Object.assign来做整体的替换

bash 复制代码
<template>
  <div class="person">
    <h2>汽车信息:一辆{{car.brand}}车,价值{{car.price}}万</h2>
    <button @click="changeBrand">修改汽车的品牌</button>
    <button @click="changePrice">修改汽车的价格</button>
    <button @click="changeCar">修改汽车</button>
    <hr>
    <h2>当前求和为:{{sum}}</h2>
    <button @click="changeSum">点我sum+1</button>
  </div>
</template>

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

  // 数据
  let car = reactive({brand:'奔驰',price:100})
  let sum = ref(0)

  // 方法
  function changeBrand(){
    car.brand = '宝马'
  }
  function changePrice(){
    car.price += 10
  }
  function changeCar(){
    // car = {brand:'奥拓',price:1} //这么写页面不更新的
    // car = reactive({brand:'奥拓',price:1}) //这么写页面不更新的

    // 下面这个写法页面可以更新
    Object.assign(car,{brand:'奥拓',price:1})
  }
  function changeSum(){
    // sum = ref(9) //这么写页面不更新的
    sum.value += 1
  }
</script>

Vue3中的响应式原理

Vue2中,如果我们想修改对象或者数组中的数据,Vue是不会监测变化的,换句话说,也就是响应式没用,我们新增属性,删除属性,修改数组中的值

实现原理

通过Proxy代理对象

Proxy和Object.defineProperty很类似,不过他添加了删除属性,和追加属性的方法

追加属性的方法集成到了set方法里边

为什么要用Reflect呢,就是因为Reflect操作对象可以返回布尔值,如果像之前那样修改代码的话,报错是直接抛出的,我们必须用try catch来捕获

computed函数

bash 复制代码
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]
        }
    })
}

watch

bash 复制代码
//情况一:监视ref定义的响应式数据
watch(sum,(newValue,oldValue)=>{
	console.log('sum变化了',newValue,oldValue)
},{immediate:true})

//情况二:监视多个ref定义的响应式数据
watch([sum,msg],(newValue,oldValue)=>{
	console.log('sum或msg变化了',newValue,oldValue)
}) 

/* 情况三:监视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配置有效

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

watchEffect

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

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

  • watchEffect有点像computed:

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

生命 周期钩子

  • ue3.0中可以继续使用Vue2.x中的生命周期钩子,但有有两个被更名:
    • beforeDestroy改名为 beforeUnmount
    • destroyed改名为 unmounted
  • Vue3.0也提供了 Composition API 形式的生命周期钩子,与Vue2.x中钩子对应关系如下:
    • beforeCreate===>setup()
    • created=======>setup()
    • beforeMount ===>onBeforeMount
    • mounted=======>onMounted
    • beforeUpdate===>onBeforeUpdate
    • updated =======>onUpdated
    • beforeUnmount ==>onBeforeUnmount

自定义钩子

  • 什么是hook?------ 本质是一个函数,把setup函数中使用的Composition API进行了封装。

  • 类似于vue2.x中的mixin。

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

就是封装一个函数,为了复用

toRefs toRef

bash 复制代码
<template>
  <div class="person">
    <h2>姓名:{{person.name}}</h2>
    <h2>年龄:{{person.age}}</h2>
    <h2>性别:{{person.gender}}</h2>
    <button @click="changeName">修改名字</button>
    <button @click="changeAge">修改年龄</button>
    <button @click="changeGender">修改性别</button>
  </div>
</template>
 
<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>

toRef有点类似于,桥接,他指向的还是源数据,只不过他为了少写点代码

相关推荐
崔庆才丨静觅20 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby606121 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了21 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅21 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅21 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅1 天前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment1 天前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅1 天前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊1 天前
jwt介绍
前端
爱敲代码的小鱼1 天前
AJAX(异步交互的技术来实现从服务端中获取数据):
前端·javascript·ajax