Vue3 基础记录

发布于:2024-12-22 ⋅ 阅读:(16) ⋅ 点赞:(0)

Vue3

创建

基于vue-cli

## 查看@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

## 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

import { createApp } from 'vue'
import App from './App.vue'

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

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

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

setup

<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中的那个渲染函数

在这里插入图片描述

<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

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

对象数据类型

  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来做整体的替换

<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函数

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

//情况一:监视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更注重的是过程(回调函数的函数体),所以不用写返回值。
//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

<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有点类似于,桥接,他指向的还是源数据,只不过他为了少写点代码


网站公告

今日签到

点亮在社区的每一天
去签到